在使用Visual Studio时,使用Opengl 1创建纹理动画的最佳方法是什么?

5

我想用OpenGL创建一个简单的动画,展示一只蝴蝶/鸟儿飞翔的场景,但我不知道该如何解决这个问题。

如果动画比较小,那么使用两张图片来表示动画会是一个不错的解决方案。如果是这样,我应该如何在它们之间交换图片呢?

1个回答

5
首先通过调用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可以重新定义一个现有二维纹理图像的连续子区域。由数据引用的纹素将替换现有纹理数组的部分,包括xoffsetxoffset + width - 1(含)之间的x索引和yoffsetyoffset + height - 1(含)之间的y索引。此区域不得包括原始指定的纹理数组范围之外的任何纹素。

如果要获取完整的纹理图像交换,只需将xoffsetyoffset设置为零即可。

您可以指定纹理名称数组,例如:

char* textureNames[10] = { "...", "...", ..., "..." }; 

然后是纹理数据

GLbyte* textureData[10]; // 10 texture instances

使用具有自动内存分配功能的LoadTGA例程加载纹理数据。
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;

考虑到您使用了少量帧(纹理),我建议您在渲染时添加一些延迟,因为图片将会变化得非常快。
或者,如果您想要实现实时渲染速度,您可以使用某种异步计时器来在纹理索引之间切换。
或者,如果您只想在两个单独的纹理之间切换,我之前已经回答过如何随机应用纹理于表面。因此,只需创建两个简单的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动画,则第一种技术是最好的方法。

我无法使用loadTGA在textureData中加载纹理,因为它告诉我无法从int转换为GLbyte*。 - Maria
@Maria:由于您创建了两个不同的纹理,可以应用另一种更改纹理的策略。 - Mykola
这是我的代码: code char* textureNames[2] = { "Textures\bird1.tga", "Textures\bird2.tga"}; GLuint bird1Texture; GLuint bird2Texture; GLbyte* textureData[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]); 抱歉,我无法缩进代码.. - Maria
1
@Maria: 这个问题是由于你的loadTGA函数像黑匣子一样造成的。从你的帖子中我可以看到它加载了TGA图像并调用了“glBindTexture”和“glTexImage”,因此你实际上无法访问纹理数据缓冲区。 - Mykola
非常感谢!我使用了第二种方法,它完美地运行了! - Maria
@Maria:祝贺你!祝你好运! - Mykola

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接