mat4 属性的步幅与偏移量

Stride vs offset for mat4 attrib

我正在阅读 有人在拉 mat4 属性。

在设置顶点属性数组时,我注意到一件事:

gl.vertexAttribPointer(row3Location, floatsPerRow, gl.FLOAT, 
                   false, bytesPerMatrix, row3Offset);

我知道提供的 mat4 占用 4 个属性槽,但为什么我们传递 bytesPerMatrix 作为步幅而不是 bytesPerRow 之类的东西?每个属性插槽不应该从其偏移量中拉出 16 个字节而不是 64 个字节吗?

这就是我想象的 16 字节的步幅和 16 的倍数的偏移量。

0000111122223333444455556666777788889999AAAABBBBCCCCDDDDEEEEFFFF
^---------------
                ^---------------
                                ^---------------
                                                ^---------------

这就是我想象的 64 字节步幅和 16 的倍数偏移量的方式。

0000111122223333444455556666777788889999AAAABBBBCCCCDDDDEEEEFFFF
^---------------------------------------------------------------
                ^---------------------------------------------------------------
                                ^---------------------------------------------------------------
                                                ^---------------------------------------------------------------
^ considerable overlap when pulling attributes for matrix

所以,很明显我的步幅和偏移心智模型是错误的。这实际上是如何工作的?当此属性一次仅拉动相当于 vec4 时,为什么步幅需要是整个矩阵的大小?

步幅是要跳过多少字节才能到达该属性的下一个值。对于 mat3 有 3 个属性,一个对应于矩阵的每一行。每个属性的数据,假设你把你的矩阵放在一个缓冲区中,彼此线性相邻,是:

|        Matrix0        |        Matrix1        |        Matrix2        | ...
| row0  | row1  | row2  | row0  | row1  | row2  | row0  | row1  | row2  | ...
| x,y,z | x,y,z | x,y,z | x,y,z | x,y,z | x,y,z | x,y,z | x,y,z | x,y,z | ...

所以第一个属性需要第 0 行的数据,对于每个矩阵。从第一个矩阵的 row0 到第二个矩阵的 row0 是 bytesPerMatrix

|        Matrix0        |        Matrix1        |        Matrix2        | ...
| row0  | row1  | row2  | row0  | row1  | row2  | row0  | row1  | row2  | ...
| x,y,z | x,y,z | x,y,z | x,y,z | x,y,z | x,y,z | x,y,z | x,y,z | x,y,z | ...
| --- bytesPerMatrix -->|
                        | --- bytesPerMatrix -->|
                                                | --- bytesPerMatrix -->|

stride 是要跳过多少字节才能到达下一个值,而不是要读取多少字节。要读取的字节数由属性的大小和类型参数定义,如

const size = 3;
const type = gl.FLOAT;
const normalize = false;
const stride = bytesPerMatrix;
const offset = row * bytesPerRow
gl.vertexAttribPointer(location, size, type, normalize, stride, offset);

以上是因为 size = 3 和 type = FLOAT 它将读取 12 个字节。

过程是

  1. 从缓冲区中的 offset 字节开始
  2. 从缓冲区读取 12 个字节并将它们应用于属性值
  3. stride 添加到 offset
  4. 转到 2

无论您要求它处理多少个顶点。

注意:假设您实际将数据一个接一个地放入缓冲区。你不必那样做。您可以将所有 row0 并排放置,然后是所有 row1,然后是所有 row2。或者您甚至可以将所有 row0 放在与 row1 和 row2 不同的缓冲区中。我不认为我见过任何人这样做,只是指出顶部描述的方式并没有固定下来。这只是最常见的方式。