Orillusion

    • 注册
    • 登录
    • 搜索
    • 版块
    • 最新
    • 标签
    1. 主页
    2. shuangliu
    • 资料
    • 关注 1
    • 粉丝 4
    • 主题 1
    • 帖子 38
    • 最佳 9
    • 有争议的 0
    • 群组 1

    shuangliu

    @shuangliu

    12
    声望
    29
    资料浏览
    38
    帖子
    4
    粉丝
    1
    关注
    注册时间 最后登录

    shuangliu 取消关注 关注
    administrators

    shuangliu 发布的最佳帖子

    • RE: WGSL | 模块变量和常量的源码案例

      w3c的doc国内可能不容易打开,可以参看Orillusion的官方翻译
      https://www.orillusion.com/zh/wgsl.html#var-and-let

      发布在 中文社区
      shuangliu
      shuangliu
    • RE: 顶点格式下的offset: 怎么理解?

      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在内部命中内存的速度,这个的提升也很重要。
      发布在 中文社区
      shuangliu
      shuangliu
    • RE: 通过device.createTexture()创建纹理时的一些参数问题
      1. 用来标明是拷贝的来源还是目标,copy_dst 就是可以做为 copy 的目标,比如用 copyExternalImageToTexture 把 image
        拷贝给 texture。相应的,copy_src 就是可以作为 copy 来源,也就是可以被拷贝,比如用 copyTexureToTexture,t1 copy to t2,那t1需要有 copy_src,t2要有 copy_dst

      2. 因为纹理贴图支持多维度的贴图,除了普通的 2d 贴图,webgpu 还支持 1d, cube, 3d, 2d-array, 3d-array 等类型,那么就对应的depthOrArrayLayer 标明深度参数或者 Array 的layer数量,比如cube对应的 depthOrArrayLayer 就必须是6,其他比如 2d-array 根据贴图数量设置

      3. rgba/bgra 只是 rgb 的排列方式不同而已,对应着小端对齐/大端对齐,并没有特殊的不同,我不确定 samplecount 为4,既开启了 MSAA 时,一定要用bgra8unorm吗?
        如果是,可能因为目前 webgpu 默认的 MSAA 需要硬件/系统驱动支持,所以必须要用 perfered format 才可以。
        目前大部分设备的色彩空间格式默认是 bgra 排列,起码我手上的 几个 windows, mac 和 ios 都是,所以开启默认的 MSAA 时,必须用 bgra8unorm。
        至于为什么默认是 bgra,因为 bgra 排列更符合cpu/gpu的内存排列方式,读取不需要额外的转换操作,可以直接使用底层驱动API去操作
        实践上,一般推荐调用context.getPreferredFormat() 得到系统默认的格式,可以避免一些不必要的问题,理论上性能也更好一些

      发布在 中文社区
      shuangliu
      shuangliu
    • Chrome writeBuffer Performance

      A simple data performance test between WebGL.bufferSubData and WebGPU.writeBuffer, try to simulate 1million transform matrix submit to GPU:


      For my platform:
      CPU: Intel i7 8700k
      Mem: 16gb
      GPU: Intel UHD 630
      OS: Mac os 12.01
      Chrome: 100.0.4862.3
      Firefox: 99.0a1


      for > 500k, take 1000k for heavy test

      Chrome 100 FireFox 99
      WebGL ~13 ms 26-30 ms
      writeBuffer 50~70 ms 26-30 ms
      mapAsync/unmap 40-50 ms 70-100 ms

      It is obviously that writeBuffer on Chrome is not ready for big dataset, basically 5-10x times slower than bufferSubData. Where mapAsync slightly faster than writeBuffer

      But for <150k, writeBuffer is faster

      Chrome 100 FireFox 99
      WebGL 2 - 4 ms 5 - 6 ms
      writeBuffer 1 - 2 ms ~2 ms
      mapAsync/unmap 5 -10 ms 60 - 100 ms

      For small dataset, the mapAsync is slower …


      When it comes to real application, WebGPU could get up to 20x slower then WebGL in Chrome, the device queue will be blocked while writing multi textrure/matrix/index/vertex ..

      In our contrast test:
      https://contrast.orillusion.com

      Event though Orillusion gets much better overall FPS than Three instance draw, Orillusion actually takes 10x longer time than Three.js in sending data to gpu. When it comes to 300k boxes, Orillusion takes over 50-70ms on writeBuffer where Three only takes 3-4ms on bufferSubData.

      This performance issue has been discussed for a long time, e.g. https://bugs.chromium.org/p/chromium/issues/detail?id=1266727&q=writeBuffer&can=2
      But it is still not addressed up to Chrome Canary v101

      For now, the best practice in Chrome, try mapAsync if you are working on very big dataset, but may not get much helpful in real application. Use writeBuffer for simple relatively small data is always a good choice. But overall, they are not fast as WebGL so far


      By the way, in our real practice, mapAsync may not a good choice for heavy rendering interactive Application.
      The async callback/promise can be delayed from 4ms up to 20ms, such as mouse/keyboard/ajax/networking events, or other mapAsync jobs.

      If you are working on a computing job, the delay is acceptable. But for real-time rendering, it can trigger a wired fps sometime, unstable frame change, hard to control from JS side. mapAsync vs writeBuffer is like relatively fast but unstable fps vs relatively slow but stable fps.


      Welcome anyone try the test, and post your result.

      发布在 General Discussion webgpu performance writebuffer
      shuangliu
      shuangliu
    • RE: Three.js vs Babylon.js vs Orillusion - Box 渲染测试

      @ukiasu 现在chrome里还不支持动态选择集成显卡或独立显卡,如果没有手动设置chrome使用3070ti,大概率还是用的i9自带的集成显卡在运行,可以检查一下到底用的哪个gpu

      另外,这个webgpu测试中最占据时间的步骤是cpu拷贝数据到gpu,目前的版本这部分的优化还不如webgl的效率,可以去测试一下 webgl和webgpu拷贝数据的效率 https://forum.orillusion.com/topic/39/chrome-writebuffer-performance
      如果 Dawn/Chrome 优化的好,理论上应该帧率能提升1倍以上

      另一点,目前webgpu还不支持硬件级别的光追管线,如果拿纯软件模拟,渲染效率会比较低,实际的意义不大,这部分可能要等webgpu下一个标准去支持

      发布在 Wiki
      shuangliu
      shuangliu
    • RE: WebGPU 更新 texture

      1.首先并不需要每个texture对应一个pipeline,可以在同一pipeline中使用不同的BindGroup,每个group对应不同的texture binding. e.g.

      let sampler = device.createSampler({
          magFilter: 'linear',
          minFilter: 'linear',
      });
      let texture1 = device.createTexture({ ... });
      let texture2 = device.createTexture({ ... });
      const group1 = device.createBindGroup({
          layout: pipeline.getBindGroupLayout(0),
          entries: [
              {
                  binding: 1,
                  resource: sampler,
              },
              {
                  binding: 2,
                  resource: texture1.createView(),
              }
          ]
      });
      const group2 = device.createBindGroup({
          layout: pipeline.getBindGroupLayout(0),
          entries: [
              {
                  binding: 1,
                  resource: sampler,
              },
              {
                  binding: 2,
                  resource: texture2.createView(),
              }
          ]
      });
      

      然后在 rendering loop 中通过 setBindGroup 切换 group1 和 group 2 即可。


      2.如果一组 textures 是同样的大小和格式,可以直接使用 texture_2d_array 去存储多个 image,这样即使一个group内,也可以在shader中通过切换array的index,来直接切换 texutre.

      对于动态的 video texuture, 我们可以直接使用 importExternalTexture 进行引入,随着video播放,texture 会自动更新

      const video = document.createElement('video');
      video.loop = true;
      video.autoplay = true;
      video.muted = true;
      video.src = '...';
      await video.play();
      
      const group = device.createBindGroup({
          layout: pipeline.getBindGroupLayout(0),
          entries: [
              {
                  binding: 1,
                  resource: sampler,
              },
              {
                  binding: 2,
                  resource: device.importExternalTexture({
                      source: video,
                  })
              }
          ]
      });
      

      3.对于更新静态的 texutre,可以根据目标 image/texture 的类型进行 copy 更新,目前 webgpu 提供多个copy command,我们一般最主要会用到的:copyExternalImageToTexture ,可以更新外部image到gpu texture:

      let texture = device.createTexture({ ... });
      const img1 = document.createElement('img');
      img1.src = '....';
      await img1.decode();
      const image1 = await createImageBitmap(img1);
      device.queue.copyExternalImageToTexture(
            { source: image1 },
            { texture: texture },
            [image1.width, image1.height]
      );
      ...
      ...js
      // 更新texture的image
      const img2 = document.createElement('img');
      img2.src = '....';
      await img2.decode();
      const image2 = await createImageBitmap(img2);
      device.queue.copyExternalImageToTexture(
            { source: image2 },
            { texture: texture },
            [image2.width, image2.height]
      );
      

      另外,也可以用 commandEncoder 执行 copyTextureToTexture 进行两个 gpu texutre 之间的copy 更新

      // e.g. 创建两个texture,texture1 用于显示,tempTexture用于接收外部图片,图片loading 后进行 copy 更新
      let texture1 = device.createTexture({ ... });
      ...
      let tempTexture = device.createTexture({ ... });
      let newImage = await loadImage() // 异步加载图片 
      device.queue.copyExternalImageToTexture(
          { source: newImage },
          { texture: tempTexture },
          [newImage.width, newImage.height]
      );
      const commandEncoder = device.createCommandEncoder();
      commandEncoder.copyTextureToTexture(
          { texture: tempTexture },
          { texture: texture1 }
      );
      device.queue.submit([commandEncoder.finish()]);
      

      其他的更新texture API 使用方法,可以参阅 https://www.orillusion.com/webgpu.html#image-copies


      4.对于 sampler,目前 webgpu 没有直接更新 sampler 的API,只能创建新的 sampler,并使用新的group进行渲染,e.g.

      let linearSampler = device.createSampler({
          magFilter: 'linear',
          minFilter: 'linear',
      });
      const group = device.createBindGroup({
          layout: pipeline.getBindGroupLayout(0),
          entries: [
              {
                  binding: 1,
                  resource: linearSampler,
              },
              {
                  binding: 2,
                  resource: texture
              }
          ]
      });
      let nearestSampler = device.createSampler({
          magFilter: 'nearest',
          minFilter: 'nearest',
      });
      const newGroup = device.createBindGroup({
          layout: pipeline.getBindGroupLayout(0),
          entries: [
              {
                  binding: 1,
                  resource: nearestSampler,
              },
              {
                  binding: 2,
                  resource: texture
              }
          ]
      });
      

      group中其他的resource并不需要重新创建,可以复用

      发布在 中文社区
      shuangliu
      shuangliu
    • RE: WGSL中生成随机数

      这个跟 WGSL 无关,任何一种shader 语言都没有自带 Math.random() 这种API,都需要开发者实现基本的伪随机算法,网上公开的算法和例子很多,比如

      https://zhuanlan.zhihu.com/p/390862782
      https://gamedev.stackexchange.com/questions/32681/random-number-hlsl

      基本上利用 fract/sin/cos 处理 position/uv/ 就可以实现基本的伪随机

      发布在 中文社区
      shuangliu
      shuangliu
    • RE: 顶点格式下的offset: 怎么理解?

      @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

      发布在 中文社区
      shuangliu
      shuangliu
    • RE: GPURenderBundle

      新加了 bundle 的 sample:
      https://orillusion.github.io/orillusion-webgpu-samples/#cubesRenderBundle

      发布在 中文社区
      shuangliu
      shuangliu

    shuangliu 发布的最新帖子

    • RE: Three.js vs Babylon.js vs Orillusion - Box 渲染测试

      @ukiasu 现在chrome里还不支持动态选择集成显卡或独立显卡,如果没有手动设置chrome使用3070ti,大概率还是用的i9自带的集成显卡在运行,可以检查一下到底用的哪个gpu

      另外,这个webgpu测试中最占据时间的步骤是cpu拷贝数据到gpu,目前的版本这部分的优化还不如webgl的效率,可以去测试一下 webgl和webgpu拷贝数据的效率 https://forum.orillusion.com/topic/39/chrome-writebuffer-performance
      如果 Dawn/Chrome 优化的好,理论上应该帧率能提升1倍以上

      另一点,目前webgpu还不支持硬件级别的光追管线,如果拿纯软件模拟,渲染效率会比较低,实际的意义不大,这部分可能要等webgpu下一个标准去支持

      发布在 Wiki
      shuangliu
      shuangliu
    • RE: google的Dawn挂梯子也Clone不下来

      首先,只设置 http.proxy 就行

      其次,请明确本地socks5的端口,不是所有的梯子都用1080/1086/443,每个软件都不一样,不要只是搜了网上的例子就粘过来用,比如,我用的 clash 一般是使用 7890 端口

      git config --global http.proxy 'socks5://127.0.0.1:7890'
      

      刚测试过,可以 clone Dawn 的 repo

      发布在 General Discussion
      shuangliu
      shuangliu
    • RE: google的Dawn挂梯子也Clone不下来

      @FuXii 目前一般的梯子,都是本地的socks5代理,是无法直接代理terminal,git,ssh 这些程序的,需要特殊的配置才可以,先自行搜索一下 git 的代理设置
      或者使用 Proxifier 类似的软件,直接转发系统底层tcp/udp 的连接到 socks5 代理

      发布在 General Discussion
      shuangliu
      shuangliu
    • RE: 使用 copyTextureToTexture可以将多个渲染结果copy到一个纹理上吗?

      @zhoubin10 很多经典的案例,比如 https://github.com/toji/web-texture-tool/blob/main/src/webgpu-mipmap-generator.js

      发布在 中文社区
      shuangliu
      shuangliu
    • RE: 使用 copyTextureToTexture可以将多个渲染结果copy到一个纹理上吗?

      @zhoubin10 不确定你的代码是否正确,但可以使用 for 循环进行 copyTextureToTexture 这种的操作,将多个贴图进行混合,确实可以用作生成 mipmap

      发布在 中文社区
      shuangliu
      shuangliu
    • RE: Texture作为attachment 附件的时候mipLevelCount只能为1,不能大于1吗?

      @zhoubin10 一般必须小于等于贴图的纹理维度,有固定的算法

      mipLevelCount = Math.floor(Math.log2(Math.max(source.width, source.height))) + 1
      
      发布在 中文社区
      shuangliu
      shuangliu
    • RE: Texture作为attachment 附件的时候mipLevelCount只能为1,不能大于1吗?

      @zhoubin10 webgpu中mipmap需要手动生成,可以参考 https://github.com/toji/webgpu-best-practices/blob/main/img-textures.md#generating-mipmaps

      发布在 中文社区
      shuangliu
      shuangliu
    • RE: orillusion入门系列三 | 几何体

      @支阿怪 目前引擎库还没有公开,所以无法直接安装,我们正在做内测,稍后会进行公开测试

      发布在 中文社区
      shuangliu
      shuangliu
    • RE: Orillusion入门心得系列(一. 学前准备)

      @lightgm 目前还没有2d相关封装,后续会扩充相关生态

      发布在 中文社区
      shuangliu
      shuangliu
    • RE: 运行WebGPU不显示图像

      @jocay 大概率是浏览器版本问题,可以尝试升级到最新版chrome

      发布在 中文社区
      shuangliu
      shuangliu