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 个字节。
过程是
- 从缓冲区中的
offset
字节开始
- 从缓冲区读取 12 个字节并将它们应用于属性值
- 将
stride
添加到 offset
- 转到 2
无论您要求它处理多少个顶点。
注意:假设您实际将数据一个接一个地放入缓冲区。你不必那样做。您可以将所有 row0 并排放置,然后是所有 row1,然后是所有 row2。或者您甚至可以将所有 row0 放在与 row1 和 row2 不同的缓冲区中。我不认为我见过任何人这样做,只是指出顶部描述的方式并没有固定下来。这只是最常见的方式。
我正在阅读
在设置顶点属性数组时,我注意到一件事:
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 个字节。
过程是
- 从缓冲区中的
offset
字节开始 - 从缓冲区读取 12 个字节并将它们应用于属性值
- 将
stride
添加到offset
- 转到 2
无论您要求它处理多少个顶点。
注意:假设您实际将数据一个接一个地放入缓冲区。你不必那样做。您可以将所有 row0 并排放置,然后是所有 row1,然后是所有 row2。或者您甚至可以将所有 row0 放在与 row1 和 row2 不同的缓冲区中。我不认为我见过任何人这样做,只是指出顶部描述的方式并没有固定下来。这只是最常见的方式。