【发布时间】:2015-12-25 23:32:58
【问题描述】:
我想使用 OpenGL 创建一个显示蝴蝶/飞翔的鸟的简单动画,但我不知道如何解决这个问题。
既然动画很小,那么创建一个包含两个图像的纹理来表示动画会是一个很好的解决方案吗?如果是这样,我应该如何在他们之间交换图片?
【问题讨论】:
我想使用 OpenGL 创建一个显示蝴蝶/飞翔的鸟的简单动画,但我不知道如何解决这个问题。
既然动画很小,那么创建一个包含两个图像的纹理来表示动画会是一个很好的解决方案吗?如果是这样,我应该如何在他们之间交换图片?
【问题讨论】:
首先调用glTexImage2D加载纹理图片,另一次加载图片到已经存在的纹理,使用glTexSubImage2D,明显比glTexImage2D调用快,非常适合这种类型的动画。
来自规范的信息:
void glTexSubImage2D(
GLenum target,
GLint level,
GLint xoffset,
GLint yoffset,
GLsizei width,
GLsizei height,
GLenum format,
GLenum type,
const GLvoid * data
);
glTexSubImage2D重新定义现有的连续子区域 二维纹理图像。数据替换引用的纹素 现有纹理数组中带有x索引xoffset的部分 和xoffset + width - 1(含)和 y 索引yoffset和yoffset + height - 1,包括在内。该区域可能不包括任何 纹理数组范围之外的纹素,因为它最初是 指定。
如果要获得完整的纹理图像交换,您只需将xoffset 和yoffset 指定为零。
你可以像这样指定纹理名称数组
char* textureNames[10] = { "...", "...", ..., "..." };
然后是纹理数据
GLbyte* textureData[10]; // 10 texture instances
使用LoadTGA rutine 加载纹理数据并自动分配内存
for (int i = 0; i < 10; i++) {
textureData[i] = LoadTGA(
textureNames[i],
/*... TEXTURE PARAMS MUST BE THE SAME FOR ALL IMAGES */
);
}
加载第一张图片
glTexImage2D(
GL_TEXTURE_2D, GL_RGB, 0, width, height, 0,
format, GL_UNSIGNED_BYTE, textureData[0]
);
在某些渲染函数中
static int imageIndex = 0;
glTexSubImage2D(
GL_TEXTURE_2D, 0, 0, 0, width, height,
format, GL_UNSIGNED_BYTE, textureData[imageIndex]
);
imageIndex++;
if (imageIndex == 10) // max index reached
imageIndex = 0;
考虑到您使用少量的帧(纹理),我建议您在渲染中添加一些延迟,因为图片的变化非常快。
或者,如果您想实现实时渲染速度,您可以使用某种异步计时器在纹理索引之间切换。
或者因为您只想在 2 个单独的纹理之间进行更改,我之前已经回答了 randomly apply textures to the surfaces。因此,只需创建 2 个简单的 2d 纹理即可完成。
for (int i = 0; i < 2; i++) {
g_pnTextures[i] = loadTGA(textureNames[i], g_pnTextures[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
}
g_pnTextures 必须是 GLuint 类型的数组。纹理生成调用类似于glGenTextures(2, g_pnTextures)。
然后依次改变它的索引。并将它们绑定到某个表面。
glBindTexture(GL_TEXTURE_2D, g_pnTextures[imageIndex++]);
if (imageIndex == 10) // max index reached
imageIndex = 0;
glBegin(GL_QUADS);
// specify texture coords
glTexCoord2f(0.0f, 0.0f);
glVertex2f(-1.0f, -1.0f);
// specify texture coords
glTexCoord2f(0.0f, 1.0f);
glVertex2f(1.0f, -1.0f);
// specify texture coords
glTexCoord2f(1.0f, 1.0f);
glVertex2f(1.0f, 1.0f);
// specify texture coords
glTexCoord2f(1.0f, 0.0f);
glVertex2f(-1.0f, 1.0f);
glEnd();
正如你所见,这个 loadTGA 函数返回的是内存缓冲区而不是 OpenGL 纹理标识符(这会导致值转换出现问题)。
注意:最后一个技术可以应用于少量纹理。如果要实现电影效果可视化或GIF动画,第一种技术是最好的方法。
【讨论】:
code char* textureNames[2] = { "Textures\\bird1.tga", "Textures\\bird2.tga"};胶合鸟1纹理;胶水鸟2纹理; GLbyte* 纹理数据[2]; // 2 个纹理实例 glGenTextures(1, &bird1Texture); glGenTextures(1, &bird2Texture); //这里是错误 textureData[0] = loadTGA(textureNames[0], bird1Texture); textureData[0] = loadTGA(textureNames[1], bird2Texture); glTexImage2D(GL_TEXTURE_2D, GL_RGB, 0, 10, 10, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData[0]);对不起,我不能缩进代码..
glBindTexture 和 glTexImage 所以你实际上无法访问纹理数据缓冲区。