具有多个纹理的VBO

时间:2011-09-06 10:36:17

标签: opengl 2d vbo

你能用不同的纹理渲染四边形的VBO吗?现在,我读到了按纹理或纹理atlasses排序,但仍然没有回答我的问题。我正在进行一场2D比赛。现在我的动画精灵将为它们的帧和一个普通的地图创建一个纹理图集,并且所有这些都将共享相同的VBO(如果可能的话)。所以每个精灵都会有一个atlass(一些动画可能有很多帧和姿势,可能会填充4096 * 4096纹理)。那有可能吗?是还是不是。如果没有效率为每个精灵都有一个索引的VBO,其所有动画帧都具有所有纹理坐标,并且每帧只发送4个索引(对于单个动画帧)并更改每个VBO的纹理? 编辑:其中一些可能正在移动(显然),有些可能不会。


在考虑之后我意识到内存使用也是一个问题。那些纹理atlasses会占用大量的内存。一个4096 * 4096 RGBA纹理需要64 MB,这是很多(而且没有法线贴图会使用量增加一倍)。而且我认为我不能将这么多动画塞进一个类中。像暗黑破坏神这样的旧游戏,或者Infinity Engine上的游戏只需要几兆的VRAM,它们看起来非常好。

2 个答案:

答案 0 :(得分:6)

为了澄清,VBO可以包含纹理坐标,但不知道将应用哪些纹理。

让VBO独立于纹理,并根据动画/帧索引计算片段/像素着色器中的纹理坐标。假设你的VBO中有四边形,那么你设置纹理坐标,这样它们就可以映射整个纹理。然后在着色器中,您将缩放并平移纹理坐标以在纹理图集上映射单个帧。然后,您可以将动画索引,图集中的帧数等等赋予着色器的统一值。

修改(进一步澄清):

四边形的纹理坐标

(0,1)          (1,1)
  x-------------x
  |             |
  |             |
  |             |
  |             |
  |             |
  x-------------x
(0,0)          (1,0)

这对应于将整个纹理映射到此单个四边形。

假设你的纹理很方便地分成16x16“帧”,在纹理图集中以行列顺序堆叠。因此,单个帧的大小在u和v的纹理坐标中分别为1/16。这是你移动的窗口。现在在着色器中,传递动画的“帧”数字,四边形中每个顶点的纹理坐标是它的纹理坐标缩放16,然后由帧(基于0的整数)转换:

float scale = 0.0625   // 1/16.
texCoord *= scale; 
texCoord += float2(scale*frame%16, scale*(frame/16))

现在我在这里写下这个,所以可能会有一些小错误。此外,此代码假定texCoord是四边形上片段的纹理坐标。请注意,计算1/16一次比重复除以16便宜得多,每个像素可以添加。如果您还没有关注我,则行float2(比例*帧%16,比例*(帧/ 16))可能会令人困惑。一个更简单的案例:

(with a total of 64 frames in an 8x8 grid)
       frame   0  1  2  3  4  5  6  7  8  9  10  11  12
x = frame%8    0  1  2  3  4  5  6  7  0  1   2   3   4 
y = frame/8    0  0  0  0  0  0  0  0  1  1   1   1   1      
(note integer division)

答案 1 :(得分:1)

当然,这是可能的(假设纹理坐标保持不变)。只需使用glBindTexture()附加要使用的纹理,然后使用glActiveTexture()选择要修改的纹理单元。

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE2D, texture_texid);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE2D, normalmap_texid);
DrawStuff();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE2D, texture2_texid);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE2D, normalmap2_texid);
DrawStuff();

如果你只使用一个纹理,显然可以跳过glActiveTexture()