3

我有两组用作线带的顶点:

  1. 顶点1
  2. 顶点2

重要的是要知道这些顶点具有以前未知的值,因为它们是动态的。

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

选项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. 讨论如何通过提供“DestinationVertexPosition”或以某种方式修改想法来正确实现选项 1,以更好地实现相同的结果。
  3. 关于如何实施选项 2的讨论。
4

2 回答 2

10

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

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);
于 2011-12-30T15:38:20.420 回答
3

您在此处的两个选项需要权衡:一次提供两次几何图形并在其间进行插值,或者仅提供一组几何图形,但对每一帧都这样做。您必须权衡几何大小与上传带宽。

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

如果顶点是恒定的,您可以将它们一次上传到GL_STATIC_DRAW设置了标志的一个或两个顶点缓冲区对象 (VBO) 中。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 都更快。

于 2011-12-30T15:44:09.000 回答