Orillusion

    • 注册
    • 登录
    • 搜索
    • 版块
    • 最新
    • 标签

    顶点格式下的offset: 怎么理解?

    中文社区
    webgpu
    2
    6
    140
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • 支阿怪
      支阿怪 最后由 shuangliu 编辑

      f31699df-3253-472c-8fea-4af443831042-image.png

      ea8a95e8-62c6-4326-b8b8-652380451881-image.png
      规范只说明是format最小倍数?这个成员定义有何意义,为实现什么呢?

      没有捷径,自发光芒

      1 条回复 最后回复 回复 引用 0
      • shuangliu
        shuangliu 最后由 shuangliu 编辑

        offset 用来标识 attributes 的偏移量,你的另一个帖子中
        https://forum.orillusion.com/topic/28/关于setvertexbuffer-插槽的理解
        用 setVertexBuffer(index, vertexBufer) 根据不同的 index 可以在vertex shader 中设置不同的 location 插槽,这是一种做法,调用多次 setVertexBuffer 设置不同插槽

        除了设置不同的index,我们还可以通过一次 setVertexBuffer 直接把所有顶点相关信息一次性提交,效率更高,比如一般常规来说,我们的geometry信息会包含 position、normal或color、uv三种信息,那么可以直接设置一个大的buffer:

        const cubeVertexArray = new Float32Array([
          // float4 position, float4 color, float2 uv,
          1, -1, 1, 1,   1, 0, 1, 1,  1, 1,
          -1, -1, 1, 1,  0, 0, 1, 1,  0, 1,
          -1, -1, -1, 1, 0, 0, 0, 1,  0, 0,
          ...... // 省略篇幅
          1, 1, -1, 1,   1, 1, 0, 1,  1, 0,
          1, -1, -1, 1,  1, 0, 0, 1,  1, 1,
          -1, 1, -1, 1,  0, 1, 0, 1,  0, 0,
        ]);
        

        那么在pipeline创建时可以通过 offset 指定buffer的偏移量用来标识不同的插槽属性:

        const renderPipeline = this.device.createRenderPipeline({
            vertex: {
                module:  vertexShader,
                entryPoint: 'main',
                buffers: [{
                    arrayStride: 10 * 4, // 标明每 10 个值一组数据
                    attributes: [
                        {
                            // position
                            shaderLocation: 0, // 插槽index
                            offset: 0, // 偏移量 0
                            format: 'float32x4',  // 标明4个 float32 position
                        },
                        {
                            // color
                            shaderLocation: 1, // 插槽index
                            offset: 4 * 4, // 偏移量 4
                            format: 'float32x4', // 标明 4 个 float32 color
                        },
                        {
                            // uv
                            shaderLocation: 2, // 插槽index
                            offset: 8 * 4, // 偏移量 8
                            format: 'float32x2',  // 标明 2 个 float32 uv
                        }
                    ],
                }]
            },
            ....  // 省略
        })
        

        那么只需设置一次vertexbuffer

        const verticesBuffer = device.createBuffer({
            size: cubeVertexArray.byteLength,
            usage: GPUBufferUsage.VERTEX,
            mappedAtCreation: true,
        });
        new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray);
          verticesBuffer.unmap();
        
        ... // 省略
        
        passEncoder.setVertexBuffer(0, verticesBuffer);
        

        在shader中,就可以通过offset调用不同的location:

        [[stage(vertex)]]
        fn main([[location(0)]] position : vec4<f32>,
                [[location(1)]] color : vec4<f32>,
                [[location(2)]] uv : vec2<f32>,
        ) -> VertexOutput {
                ... // 省略
        }
        

        这种做法效率更高一些,做高性能的 webgpu 程序要尽可能减少不必要的command次数 和 gpu 数据交换次数,所以:

        1. 减少setVertexBuffer 的次数,把所有相关信息一次提交,要比多次设置index快很多
        2. 在数据层面,创建一个gpubuffer,要比创建多个零散的gpubuffer效率高很多,减少cpu与gpu的交换数据次数,也减少了GPU在内部命中内存的速度,这个的提升也很重要。
        支阿怪 2 条回复 最后回复 回复 引用 2
        • 支阿怪
          支阿怪 @shuangliu 最后由 编辑

          @shuangliu 非常感谢解答👍

          没有捷径,自发光芒

          1 条回复 最后回复 回复 引用 0
          • 支阿怪
            支阿怪 @shuangliu 最后由 编辑

            @shuangliu 还有个问题请教,就是怎么理解计算buffer的偏移量呢?0、4、8这是怎么得出的呢?

            没有捷径,自发光芒

            shuangliu 1 条回复 最后回复 回复 引用 0
            • shuangliu
              shuangliu @支阿怪 最后由 shuangliu 编辑

              @wenhao0807 这个是根据你自己的vertex设置安排的

              const cubeVertexArray = new Float32Array([
                // float4 position, float4 color, float2 uv,
                1, -1, 1, 1,   1, 0, 1, 1,  1, 1,
                -1, -1, 1, 1,  0, 0, 1, 1,  0, 1,
                -1, -1, -1, 1, 0, 0, 0, 1,  0, 0,
                ...... // 省略篇幅
                1, 1, -1, 1,   1, 1, 0, 1,  1, 0,
                1, -1, -1, 1,  1, 0, 0, 1,  1, 1,
                -1, 1, -1, 1,  0, 1, 0, 1,  0, 0,
              ]);
              

              这个例子中,一行10个数字,你可以安排排列方式,1-4 是position, 5-8 是 color或者一般设置normal,9-10是uv值,相应的就是 pipeline 中的 offset。
              一般来说,对于普通object/mesh,我们一般用8个值做顶点buffer,3个 position, 3个normal, 2个uv:

              buffers: [
                  {
                      arrayStride: 8 * 4,
                      attributes: [
                          {
                              // position
                              shaderLocation: 0,
                              offset: 0,
                              format: 'float32x3',
                          },
                          {
                              // normal
                              shaderLocation: 1,
                              offset: 3 * 4,
                              format: 'float32x3',
                          },
                          {
                              // uv
                              shaderLocation: 2,
                              offset: 6 * 4,
                              format: 'float32x2',
                          }
                      ],
                  }
              ]
              

              其他信息,比如transform,color,light,material等参数会用 uniform/storage buffer进行传递。当然你可以自行安排,比如对于lines/points,就不需要normal或者uv,那vertexbuffer中就会设置color

              支阿怪 1 条回复 最后回复 回复 引用 1
              • 支阿怪
                支阿怪 @shuangliu 最后由 编辑

                @shuangliu 明白了,感谢您的回复👍

                没有捷径,自发光芒

                1 条回复 最后回复 回复 引用 0
                • First post
                  Last post

                Recent Post

                • 目前可以预览demo了

                  • 阅读更多
                • A

                  这demo太卡了,我机器性能不算差,运行个demo cpu就将近100%

                  • 阅读更多
                • A

                  没有贴出app.vue的代码

                  • 阅读更多
                • @aichangqing 可能是之前版本的cdn缓存没更新,可以清理本地缓存刷新再试一次

                  • 阅读更多
                • 36e6af78-b023-4031-9b56-bd8713b44393-image.png

                  已经是版本 113.0.5656.0(正式版本)canary (64 位)并且开启chrome://flags/#enable-unsafe-webgpu 为enable,为啥还不能预览demo

                  • 阅读更多

                Copyright © 2022 Orillusion | Contact US