0

好的......想象我有一个相对简单的实体,它有六个不同的法线,但实际上有接近 48 个面(每个方向 8 个面),并且面之间有很多共享顶点。在 OpenGL 中渲染它的最有效方法是什么?

我知道我可以将顶点放在一个数组中,然后使用索引数组来渲染它们,但是我必须不断打破我的渲染步骤来改变法线(即设置法线 1...渲染 8 个面...设置法线2...渲染8个面等)因此,我必须维护一个索引数组数组...每个法线一个!不好!

我可以做到的另一种方法是使用单独的法线和顶点数组(甚至将它们交错)但这意味着我需要法线与顶点的比例为一比一,这意味着法线将被复制 8 倍以上比他们需要的!在具有球形甚至曲面的物体上,每个法线很可能都是不同的,但对于这一点,这似乎真的是在浪费内存。

在一个完美的世界中,我希望我的顶点和法线数组具有不同的长度,然后当我去绘制我的三角形或四边形时,为该顶点指定每个数组的索引。

现在 OBJ 文件格式允许您准确指定...一个顶点数组和一个不同长度的法线数组,然后当您指定要渲染的面时,您指定一个顶点和一个法线索引(以及一个 UV 坐标,如果您也在使用纹理)这似乎是完美的解决方案!48 个顶点但只有 8 个法线,然后是定义形状面的索引对。但我不确定如何在 OpenGL ES 中渲染它(再次注意“ES”。)目前我必须“非规范化”(对不起那里的 SQL 双关语)法线回到 1 对 1顶点数组,然后渲染。只是浪费我的记忆。

有人帮忙吗?我希望我在这里遗漏了一些非常简单的东西。

标记

4

1 回答 1

1

你没有错过任何东西。这就是规范的工作方式,因为这是大多数硬件的工作方式(也就是你的完美不是硬件完美)。

我不会讨论实现支持索引数组的硬件的复杂性,但我会指出你可能会失去的一个优化:GL 可能使用单个索引作为顶点后变换缓存的索引,不必在下一次迭代中重新转换顶点。您使用一组索引使优化变得更加复杂。

关于内存节省:在您的情况下,您大致谈论的是一个立方体,每个面使用 4 个四边形,8 个三角形。所以我们谈论的是 9*6=54 个独特的顶点。如果你只有位置和法线,那就是 54 * 4 * 3 * 2 = 1296 B 的顶点数据 + 2 * 48 * 3 = 288 B 的索引数据(假设属性基类型为 4 字节,索引为 GLushort)。总计1584B。这也是假设位置和法线的非最佳数据格式。替代方案大约是 26*4*3(pos)+8*4*3(norm)+2*48*3*2=312+96+576=984B。所以你在这个人为的案例上节省了大约 0.5kB。将其传递给属性的更节省内存的类型,您将得到:648+288=936 vs 156+48+576=780... 差异开始可以忽略不计。

我为什么要提这个?因为如果您想要优化内存消耗,您应该查看您的属性数据类型。

最后,正如您自己注意到的那样,在实际的 3d 世界中(即不是在盒子世界中),这种机制的节省会很低:很少有属性可以共享。

于 2010-01-09T08:45:38.683 回答