OpenGL ES 2(iOS)变形/两组顶点之间的动画

时间:2011-12-30 14:12:44

标签: ios opengl-es opengl-es-2.0 vertex-shader

我有两组顶点用作线条:

  1. Vertexes1
  2. Vertexes2
  3. 重要的是要知道这些顶点以前是未知的值,因为它们是动态的。

    我想在这两者之间进行动画过渡(变形)。我想出了两种不同的方法:

    选项1:

    在顶点着色器中设置一个时间均匀,来自 0 - 1 ,我可以这样做:

    // Inside main() in the vertex shader
    float originX = Position.x;
    float destinationX = DestinationVertexPosition.x;
    float interpolatedX = originX + (destinationX - originX) * Time;
    
    gl_Position.x = interpolatedX;
    

    正如您可能看到的,这有一个问题:如何在那里获得“DestinationVertexPosition”

    选项2:

    在顶点着色器之外进行插值计算,我遍历每个顶点并为插值创建第三个顶点集,并使用它进行渲染:

    // Pre render
    // Use this vertex set to render
    InterpolatedVertexes
    
    for (unsigned int i = 0; i < vertexCount; i++) {
       float originX = Vertexes1[i].x;
       float destinationX = Vertexes2[i].x;
       float interpolatedX = originX + (destinationX - originX) * Time;
    
       InterpolatedVertexes[i].x = interpolatedX;
    }
    

    我已经高度简化了这两个代码片段,只是为了明确这个想法。

    现在,从两个选项中,我觉得第一个在性能方面肯定更好,因为在着色器级别发生了一些事情,而且每次“时间”已更新。

    所以,既然已经涵盖了问题的介绍,我将非常感谢以下三件事:

    1. 讨论在OpenGL ES 2(iOS)中实现预期结果的更好方法。
    2. 关于如何正确实施选项1 的讨论,可以通过提供“DestinationVertexPosition”或以某种方式修改想法,以更好地实现相同的结果。< / LI>
    3. 关于如何实施选项2 的讨论。

2 个答案:

答案 0 :(得分:10)

在ES 2中,您可以根据需要指定这些属性 - 因此,为origindestination指定属性并在顶点着色器中对它们进行线性插值没有问题。但是你真的不应该逐个组件地执行它,因为你的代码建议你想要GPU作为矢量处理器,而mix GLSL函数将执行你想要的线性混合。所以例如(明显效率低下和假设)

int sourceAttribute = glGetAttribLocation(shader, "sourceVertex");
glVertexAttribPointer(sourceAttribute, 3, GL_FLOAT, GL_FALSE, 0, sourceLocations);

int destAttribute = glGetAttribLocation(shader, "destVertex");
glVertexAttribPointer(destAttribute, 3, GL_FLOAT, GL_FALSE, 0, destLocations);

gl_Position = vec4(mix(sourceVertex, destVertex, Time), 1.0);

答案 1 :(得分:3)

这里你的两个选项有一个权衡:一次提供两倍几何并在其间插值,或只提供一组几何,但每帧都这样做。您必须权衡几何尺寸与上传带宽。

鉴于我对iOS设备的经验,我强烈推荐选项1.在这些设备上每帧上传新的几何图形可能非常昂贵。

如果顶点是常量,您可以将它们上传到一个或两个顶点缓冲区对象(VBO)中并设置GL_STATIC_DRAW标记。 PowerVR SGX系列具有处理静态VBO的硬件优化,因此在初始上载后可以非常快速地使用它们。

至于如何上传两组顶点以便在单个着色器中使用,几何体只是着色器的另一个输入属性。您可以将一组,两组或更多组顶点馈送到单个顶点着色器中。您只需使用

等代码定义属性
attribute vec3 startingPosition;
attribute vec3 endingPosition;

并使用

之类的代码在它们之间进行插值
vec3 finalPosition = startingPosition * (1.0 - fractionalProgress) + endingPosition * fractionalProgress;

编辑:Tommy指出我忘记的mix()操作,这是进行上述顶点插值的更好方法。

为了通知你的着色器程序在哪里获得第二组顶点,你将使用几乎相同的glVertexAttribPointer()调用第二组几何作为第一组几何,只指向那个VBO和属性。

请注意,您可以将此计算作为向量执行,而不是单独分解所有三个组件。对于当前PowerVR SGX芯片的highp默认精度,这并没有太大的帮助,但是在未来可能会比一次执行这个组件更快。

您可能还想查看用于顶点蒙皮的其他技术,因为可能还有其他方法可以设置不需要上传两组完整顶点的顶点动画。

我听说过一个案例,其中选项2(在每个帧上上传新的几何图形)可能更可取在特定情况下,使用Accelerate框架对几何体进行矢量处理最终会比在上面进行蒙皮更快-GPU。我记得Unity人员曾经讨论过这个问题,但是我不记得它是用于非常小的还是非常大的几何体。在我与自己合作的所有案例中,选项1都更快。