3

在线

604

用户

185

主题

486

帖子
  • WebGL 与 WebGPU比对[6] - 纹理

    中文社区
    1
    1 赞同
    1 帖子
    285 浏览
    尚无回复
  • WebGPU 更新 texture

    中文社区
    2
    0 赞同
    2 帖子
    295 浏览

    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并不需要重新创建,可以复用

  • 0 赞同
    2 帖子
    187 浏览

    @浮光_ 考虑你为什么需要做flip,可能是OpenGL或者WebGL的坐标系与WebGPU的不同,WebGL的原点是左下角,而DX12和Vulkan,也就是WebGPU的坐标原点都是左上角,如果你把webgl的代码放到webgpu的话,就需要转换坐标,可以在shader把UV的值改一下,比如uv.y = 1 - uv.y

    另外,gl.pixelStore只是改变了你上传texture的顺序,但是整个屏幕空间的坐标是不对应的,后面如果还需要处理比如render target,那么问题还会存在