我正在为一个小游戏写一个2D引擎。
我的想法是,我可以在一次绘制调用中渲染整个场景。我以为我可以在四边形上渲染每个2D图像,这意味着我可以使用实例化。
我想象我的顶点着色器看起来像这样
...
in vec2 pos;
in mat3 model;
in sampler2d tex;
in vec2 uv;
...
我以为我可以在gpu上加载纹理并像使用VBO一样获取它的句柄,但它似乎并不那么简单。
似乎我必须致电
glActiveTexture(GL_TEXTURE0..N);
为我要加载的每个纹理。现在这看起来并不像我想象的那么容易。现代游戏引擎如何渲染多个纹理?
我读到GL_TEXTURE
的纹理限制依赖于GPU,但它至少是45.如果我想渲染一个包含超过45个纹理的图像,例如90?
似乎我必须渲染前45个纹理并从gpu中删除所有纹理,并将其他45个纹理从hdd加载到gpu。做每一帧似乎都不合理。特别是当我想要为2D图像设置动画时。
我可以很容易地认为2d字符的简单动画可能包含10个不同的图像。这意味着我可以轻松地超越纹理限制。
我的一个小想法是将多个图像合并到一个巨型图像中,然后通过紫外坐标偏移它们。
我想知道我是否误解了纹理在OpenGL中是如何工作的。
如何在OpenGL中渲染多个纹理?
答案 0 :(得分:13)
问题有点宽泛,所以这只是在同一个绘图调用中使用多个纹理的一些选项的快速概述。
对于此方法,使用典型序列将每个纹理绑定到不同的纹理单元:
glActiveTexture(GL_TEXTUREi);
glBindTexture(GL_TEXTURE_2D, tex[I]);
在着色器中,您可以拥有一堆单独的sampler2D
制服或一系列sampler2D
制服。
这样做的主要缺点是你受到可用纹理单元数量的限制。
您可以使用数组纹理。这是通过使用GL_TEXTURE_2D_ARRAY
纹理目标完成的。在许多方面,2D纹理阵列类似于3D纹理。它基本上是一堆堆叠在一起的2D纹理,并存储在一个纹理对象中。
缺点是所有纹理都需要具有相同的尺寸。如果他们不这样做,你必须使用最大尺寸的纹理数组大小,并浪费内存用于较小的纹理。如果尺寸不相同,您还必须对纹理坐标应用缩放。
这是你已经提出的想法。将所有纹理存储在单个大纹理中,并使用纹理坐标来控制使用哪个纹理。
虽然这是一种流行的方法,但是存在一些技术挑战。您必须小心纹理之间的接缝,以便在使用线性采样时它们不会相互渗透。虽然这种方法与纹理数组不同,允许不同的纹理大小而不浪费内存,但在地图集中分配区域对于可变大小来说有点棘手。
目前仅提供此扩展程序:ARB_bindless_texture。
答案 1 :(得分:6)
您需要了解纹理单位和纹理对象的区别。
纹理单元就像OpenGL光栅化器的“纹理盒”。光栅化器具有有限数量的“cartrige”槽(称为纹理单元)。要将纹理加载到纹理单元中,首先选择具有glActiveTexture
的单位,然后使用glBindTexture
加载纹理“cardridge”(纹理对象)。
您可以拥有的纹理对象的数量仅受系统内存(和存储功能)的限制,但只有有限数量的纹理可以同时“插入”纹理单元。
采样器类似于“点击”纹理单元着色器中的不同采样器可以“点击”到相同的纹理单元中。通过将采样器均匀设置为纹理单位,您可以选择要采样的单位。
然后你也可以在同一时间将相同的纹理“插入”多个纹理单元。
我读到GL_TEXTURE的纹理极限取决于GPU,但它至少为45.如果我想渲染一个包含超过45个纹理的图像,例如90?
通常,您不会尝试使用单个绘图调用渲染整个图像。几乎不可能捕捉到在什么情况下使用哪种纹理的所有变化。通常,您会为“材质”的特定外观编写着色器。假设你有一个着色器模拟某些金属上的油漆。你有3种纹理:金属,油漆和调制纹理,可以控制金属和油漆可见的位置。然后着色器将有3个采样器制服,每个纹理一个。要渲染具有该外观的表面
glUseProgram
)glActiveTexture(GL_TEXTURE_0+i
)并绑定纹理('glBindTexture`)glUniform1i(…, i)
)。