如何为大网格实现VBO并获得流畅的动画?

时间:2012-04-18 20:05:53

标签: c++ opengl vbo maya

我在Maya中创建一个长达一分钟的动画,我打算在OpenGL中渲染它。我这样做是作为大学的一个项目。

场景只包含一个人脸扭曲的表情。网格有大约2200个四边形面。

我找到了一个将Wavefront对象文件转换为顶点和普通数组的perl脚本。我打算以24fps在Maya中制作动画,然后将每个帧中的网格导出到Wavefront对象文件,然后通过perl脚本运行所有这些,这将为我提供顶点和普通数组。

因此,为了测试可行性,我将Maya中的两个动画帧转换为目标文件并通过脚本运行(在调整之后),这给了我数千glVertexglNormal个调用。我将所有这些复制到我的C ++程序并编译它。它运行顺利。

考虑到当我将60秒* 24帧的glVertexglNormal语句复制到程序中时程序的大小,我想尝试使用VBO。所以,我读到了它,但我不太了解实现。

所以我的第一个问题是:在这种情况下,实施VBO的最佳方法是什么?

我正在考虑顶点和法线的2D数组,每帧一个; GL_STATIC_DRAW_ARB的{​​usage}参数和glBufferDataARB()

说,如果我的动画是5帧长,我的脸部网格由2200个顶点和法线组成,那么我将创建:

GLfloat face_vertices[5][2200] = {.....};
GLfloat face_normals[5][2200] = {.....};

我的第二个问题:上述代码能否与VBO一起工作或表现良好?

另外,我不确定这些信息是否重要,但我的电脑是在英特尔82945G显卡上运行的,而且我很确定我学院的电脑也在英特尔上运行。我以为我会提到这一点。

更新

表现也是一个问题。

2 个答案:

答案 0 :(得分:1)

  

我正在考虑顶点和法线的2D数组,每帧一个;和

我认为这是不正确的解决方案。有了这么多数据,就可以流式传输它。例如,在内存中保留1秒的动画,按需加载其余动画。我相信这个场景有GL_STREAM_****个标志。

更好的解决方案是从maya及其动画中导出骨骼。 (在这种情况下,你需要一个永远不会改变的网格)

拥有来逐帧导出每个顶点动画的唯一情况是你输出的东西计算成本非常高。我能想到的唯一现实场景是3D流体网格(拓扑改变非常框架等) - 其他一切都可以在CPU或GPU上计算。但是,您的帖子并未表明这是您的方案。因此,根据墨菲定律,我将不得不假设您使用效率低下的解决方案来解决可以以不同方式解决的问题。

  

:上述代码是否可以与VBO一起工作或表现良好?

无法回答,因为你没有说明你将如何绘制数据。通过滥用着色器,Alpha混合或渲染相同的东西,即使使用简单的几何体也可以使任何机器瘫痪。

答案 1 :(得分:1)

如果你可以平滑地运行两帧动画,你可以顺利运行60 * 24帧“值得glVertex和glNormal语句”,如果你可以从你的Maya动画中自动生成GL调用。这种方法的唯一问题是你的源代码和二进制可执行文件将是非常庞大的。这是使你的方法“糟糕”的问题。

所以,首先,不是每个顶点数据都有一个glVertex调用,你可以将数据放在一个数组(或std :: vector,就此而言),并使用一个简单的循环遍历它:

std::vector<int> idx;
std::vector<vertex> frame_data;
...
glBegin(GL_QUADS);
for(int i = 0; i < idx.size(); ++i) {
  glVertex3f(frame_data[idx].x, frame_data[idx].y, frame_data[idx].z);
  glNormal3f(frame_data[idx].nx, frame_data[idx].ny, frame_data[idx].nz);
}
glEnd();

Idx表示面,idx中的每4个元素形成一个四边形。 Frame_data是该帧的特定顶点数据,每帧必须有一个这样的数组,并且这些数据由idx索引。这样,您必须解决的唯一问题是如何将此数据读入您的应用程序。如果你可以从你的网格文件生成glVertex调用,你可以生成一个文件,你可以使用C ++ fstream轻松地在你的应用程序中加载,然后构建数据数组,然后迭代它们并进行绘图调用。

在这种情况下你不会看到使用glBegin()/ glEnd()和VBO之间的性能差异,因为2200四边形的数量太少而没有任何差别,但对你来说这将是一个有趣的练习。组织我告诉你的数组中的数据(idx和vertex_data)是使用VBO的第一步。您必须在一个结构中打包相对于一个顶点的所有数据:

struct vertex {
  float x, y, z; // Position
  float nx, ny, nz; // Normal
};
...
vertex frame_data[v_count];
uint16_t idx[2200 * 4]; // 4 vertices makes one face

请注意,v_count 不是 2200.这是你的四边形数,所以这个数字是相对于idx大小而不是frame_data,即同一个顶点可以用在多个四边形面上。

你需要两个缓冲区,一个是静态来保存idx(一个GL_ELEMENT_ARRAY_BUFFER和GL_STATIC_DRAW),因为这在执行期间不会改变,另一个“流”缓冲区用于保存顶点数据(GL_ARRAY_BUFFER和GL_STREAM_DRAW)。最后一个使用“GL_STREAM_DRAW”,因为您需要为动画每帧重写其内容。请参阅glBufferData