【问题标题】:Stride vs offset for mat4 attribmat4 属性的步幅与偏移量
【发布时间】:2021-01-28 00:50:47
【问题描述】:

我正在阅读this answer on SO,其中有人正在提取 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 的等价物时,为什么步幅需要是整个矩阵的大小?

【问题讨论】:

    标签: attributes webgl2


    【解决方案1】:

    步幅是跳过多少字节才能到达该属性的下一个值。对于 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 行数据。从第一个矩阵的第0行到第二个矩阵的第0行是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 不同的缓冲区中。我认为我从未见过有人这样做,只是指出顶部描述的方式并非一成不变。这只是最常见的方式。

    【讨论】:

    • 这个问题最初是在阅读关于实例对象的 webglfundamentals2 文章时提出的。那篇文章的作者亲自回答了这个问题,我感到非常惊喜!谢谢:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-26
    相关资源
    最近更新 更多