<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      WebGPU學習(八):學習“texturedCube”示例

      大家好,本文學習Chrome->webgpu-samplers->texturedCube示例。

      上一篇博文:
      WebGPU學習(七):學習“twoCubes”和“instancedCube”示例

      下一篇博文:
      WebGPU學習(九):學習“fractalCube”示例

      學習texturedCube.ts

      最終渲染結果:
      截屏2019-12-23上午8.11.40.png-117.2kB

      該示例繪制了有一個紋理的立方體。

      與“rotatingCube”示例相比,該示例增加了下面的步驟:

      • 傳輸頂點的uv數據
      • 增加了sampler和sampled-texture類型的uniform數據

      下面,我們打開texturedCube.ts文件,依次分析增加的步驟:

      傳遞頂點的uv數據

      • shader加入uv attribute

      代碼如下:

        const vertexShaderGLSL = `#version 450
        ...
        layout(location = 0) in vec4 position;
        layout(location = 1) in vec2 uv;
      
        layout(location = 0) out vec2 fragUV;
        layout(location = 1) out vec4 fragPosition;
      
        void main() {
          fragPosition = 0.5 * (position + vec4(1.0));
          ...
          fragUV = uv;
        }
        `;
        
        const fragmentShaderGLSL = `#version 450
        layout(set = 0, binding = 1) uniform sampler mySampler;
        layout(set = 0, binding = 2) uniform texture2D myTexture;
      
        layout(location = 0) in vec2 fragUV;
        layout(location = 1) in vec4 fragPosition;
        layout(location = 0) out vec4 outColor;
      
        void main() {
          outColor =  texture(sampler2D(myTexture, mySampler), fragUV) * fragPosition;
        }
        `;
      

      vertex shader傳入了uv attribute數據,并將其傳遞給fragUV,從而傳到fragment shader,作為紋理采樣坐標

      另外,這里可以順便說明下:fragPosition用來實現與position相關的顏色漸變效果

      • uv數據包含在verticesBuffer的cubeVertexArray中

      cubeVertexArray的代碼如下:

      cube.ts:
      export const cubeUVOffset = 4 * 8;
      export 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, 0, 0, 1,  1, 0,
          1, -1, 1, 1,   1, 0, 1, 1,  1, 1,
          -1, -1, -1, 1, 0, 0, 0, 1,  0, 0,
      
          ...
      ]);
      

      創建和設置verticesBuffer的相關代碼如下:

      texturedCube.ts:
        const verticesBuffer = device.createBuffer({
          size: cubeVertexArray.byteLength,
          usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
        });
        verticesBuffer.setSubData(0, cubeVertexArray);
        
        ...
        
        return function frame() {
          ...
          passEncoder.setVertexBuffer(0, verticesBuffer);
          ...
        } 
      
      • 創建render pipeline時指定uv attribute的相關數據

      代碼如下:

        const pipeline = device.createRenderPipeline({
          ...
          vertexState: {
            vertexBuffers: [{
              ...
              attributes: [
              ...
              {
                // uv
                shaderLocation: 1,
                offset: cubeUVOffset,
                format: "float2"
              }]
            }],
          },
          ...
        });    
      

      增加了sampler和sampled-texture類型的uniform數據

      WebGPU相對于WebGL1,提出了sampler,可以對它設置filter、wrap等參數,從而實現了texture和sampler自由組合,同一個texture能夠以不同filter、wrap來采樣

      • fragment shader傳入這兩個uniform數據,用于紋理采樣

      代碼如下:

        const fragmentShaderGLSL = `#version 450
        layout(set = 0, binding = 1) uniform sampler mySampler;
        layout(set = 0, binding = 2) uniform texture2D myTexture;
      
        layout(location = 0) in vec2 fragUV;
        layout(location = 1) in vec4 fragPosition;
        layout(location = 0) out vec4 outColor;
      
        void main() {
          outColor =  texture(sampler2D(myTexture, mySampler), fragUV) * fragPosition;
        }
        `;
      
      • 創建bind group layout

      代碼如下:

        const bindGroupLayout = device.createBindGroupLayout({
          bindings: [
          ...
          {
            // Sampler
            binding: 1,
            visibility: GPUShaderStage.FRAGMENT,
            type: "sampler"
          }, {
            // Texture view
            binding: 2,
            visibility: GPUShaderStage.FRAGMENT,
            type: "sampled-texture"
          }]
        });
      
      • 拷貝圖片到texture,返回texture

      代碼如下,后面會進一步研究:

        const cubeTexture = await createTextureFromImage(device, 'assets/img/Di-3d.png', GPUTextureUsage.SAMPLED);
      
      • 創建sampler,指定filter

      代碼如下:

        const sampler = device.createSampler({
          magFilter: "linear",
          minFilter: "linear",
        });
        
      

      我們看一下相關定義:

      GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});
      
      ...
      
      dictionary GPUSamplerDescriptor : GPUObjectDescriptorBase {
          GPUAddressMode addressModeU = "clamp-to-edge";
          GPUAddressMode addressModeV = "clamp-to-edge";
          GPUAddressMode addressModeW = "clamp-to-edge";
          GPUFilterMode magFilter = "nearest";
          GPUFilterMode minFilter = "nearest";
          GPUFilterMode mipmapFilter = "nearest";
          float lodMinClamp = 0;
          float lodMaxClamp = 0xffffffff;
          GPUCompareFunction compare = "never";
      };
      

      GPUSamplerDescriptor的addressMode指定了texture在u、v、w方向的wrap mode(u、v方向的wrap相當于WebGL1的wrapS、wrapT,w方向是給3d texture用的)

      mipmapFilter與mipmap有關,lodXXX與texture lod有關,compare與軟陰影的Percentage Closer Filtering技術有關,我們不討論它們

      • 創建uniform bind group時傳入sampler、texture的view
        const uniformBindGroup = device.createBindGroup({
          layout: bindGroupLayout,
          bindings: [
          ...
          {
            binding: 1,
            resource: sampler,
          }, {
            binding: 2,
            resource: cubeTexture.createView(),
          }],
        });
      

      參考資料

      Sampler Object

      詳細分析“拷貝圖片到texture”步驟

      相關代碼如下:

        const cubeTexture = await createTextureFromImage(device, 'assets/img/Di-3d.png', GPUTextureUsage.SAMPLED);
      

      該步驟可以分解為兩步:
      1.加載圖片
      2.拷貝解碼后類型為HTMLImageElement的圖片到GPU的texture中

      下面依次分析:

      1、加載圖片

      打開helper.ts文件,查看createTextureFromImage對應代碼:

        const img = document.createElement('img');
        img.src = src;
        await img.decode();
      

      這里使用decode api來加載圖片。另外一種實現方式是使用img.onload:

        const img = document.createElement('img');
        img.src = src;
        img.onload = (img) => {
          ...
        };
      

      我們來分析下這兩種加載方式:
      根據Pre-Loading and Pre-Decoding Images with Javascript for Better Performance的說法,圖片的加載過程有兩個步驟:
      1.從服務器加載圖片
      2.解碼圖片

      對于這兩種加載圖片的方式,圖片的加載過程的第1步都是在其它線程上并行執行,不會阻塞主線程;
      如果用onload,則瀏覽器會在主線程上同步執行第2步,從而阻塞主線程;
      如果用decode api,則瀏覽器會在其它線程上并行執行第2步,不會阻塞主線程。

      因為chrome和firefox瀏覽器都支持decode api,所以加載圖片應該優先使用該API。
      兼容性情況如下圖所示:
      截屏2019-12-24下午2.31.34.png-85.3kB

      參考資料

      Pre-Loading and Pre-Decoding Images with Javascript for Better Performance
      Chrome 圖片解碼與 Image.decode API

      2、拷貝圖片

      WebGL1只能使用texImage2D將圖片上傳到GPU texture中,而WebGPU能讓我們更加靈活地控制上傳過程。

      WebGPU有兩種方法上傳:

      • 創建圖片對應的imageBitmap,將其拷貝到GPU texture中

      該方法要用到copyImageBitmapToTexture函數。雖然WebGPU規范已經定義了該函數,但目前Chrome Canary不支持它,所以暫時不能用該方法上傳。

      參考資料
      Proposal for copyImageBitmapToTexture
      ImageBitmapToTexture design

      • 將圖片繪制到canvas中,通過getImageData獲得數據,將其設置到buffer中,把buffer數據拷貝到GPU texture中

      本示例使用這種方法實現上傳。
      我們來看下createTextureFromImage對應代碼:

        const imageCanvas = document.createElement('canvas');
        imageCanvas.width = img.width;
        imageCanvas.height = img.height;
      
        const imageCanvasContext = imageCanvas.getContext('2d');
        
        //在繪制圖片時將圖片在Y方向反轉了
        imageCanvasContext.translate(0, img.height);
        imageCanvasContext.scale(1, -1);
        
        imageCanvasContext.drawImage(img, 0, 0, img.width, img.height);
        const imageData = imageCanvasContext.getImageData(0, 0, img.width, img.height);
      

      這里首先創建canvas,然后繪制圖片,最后獲得圖片數據。

      接著看后續代碼:

        let data = null;
      
        const rowPitch = Math.ceil(img.width * 4 / 256) * 256;
        if (rowPitch == img.width * 4) {
          data = imageData.data;
        } else {
          data = new Uint8Array(rowPitch * img.height);
          for (let y = 0; y < img.height; ++y) {
            for (let x = 0; x < img.width; ++x) {
              let i = x * 4 + y * rowPitch;
              data[i] = imageData.data[i];
              data[i + 1] = imageData.data[i + 1];
              data[i + 2] = imageData.data[i + 2];
              data[i + 3] = imageData.data[i + 3];
            }
          }
        }
      
        const texture = device.createTexture({
          size: {
            width: img.width,
            height: img.height,
            depth: 1,
          },
          format: "rgba8unorm",
          usage: GPUTextureUsage.COPY_DST | usage,
        });
      
        const textureDataBuffer = device.createBuffer({
          size: data.byteLength,
          usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,
        });
      
        textureDataBuffer.setSubData(0, data);
      

      rowPitch需要為256的倍數(也就是說,圖片的寬度需要為64px的倍數),這是因為Dx12對此做了限制(參考Copies investigation):

      RowPitch must be aligned to D3D12_TEXTURE_DATA_PITCH_ALIGNMENT.
      Offset must be aligned to D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT, which is 512.

      另外,關于紋理尺寸,可以參考WebGPU-6

      第一個問題是關于紋理尺寸的,回答是WebGPU沒有對尺寸有特別明確的要求。sample code中最多不能比4kor8k大就行。這個也不是太難理解,OpenGL對紋理和FBO的尺寸總是有上限的。

      另外,根據我的測試,buffer(代碼中的textureDataBuffer)中的圖片數據需要為未壓縮的圖片數據(它的類型為Uint8Array,length=img.width * img.height * 4(因為每個像素有r、g、b、a這4個值)),否則會報錯(在我的測試中,“通過canvas->toDataURL得到圖片的base64,將其轉為Uint8Array,得到壓縮后的圖片數據,將其設置到buffer中”會報錯)

      繼續看后續代碼:

        const commandEncoder = device.createCommandEncoder({});
        commandEncoder.copyBufferToTexture({
          buffer: textureDataBuffer,
          rowPitch: rowPitch,
          imageHeight: 0,
        }, {
          texture: texture,
        }, {
          width: img.width,
          height: img.height,
          depth: 1,
        });
      
        device.defaultQueue.submit([commandEncoder.finish()]);
      
        return texture;
      

      這里提交了copyBufferToTexture這個command到GPU,并返回texture
      (注:這個command此時并沒有執行,會由GPU決定什么時候執行)

      WebGPU支持buffer與buffer、buffer與texture、texture與texture之間互相拷貝。

      參考資料
      3 channel formats
      Copies investigation (+ proposals)

      參考資料

      WebGPU規范
      webgpu-samplers Github Repo
      WebGPU-6

      posted @ 2019-12-24 14:57  楊元超  閱讀(816)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产精品SM捆绑调教视频| 久久亚洲精品中文字幕| 在线观看特色大片免费网站| 亚洲欧洲日产国无高清码图片| 久久精品熟女亚洲av艳妇| 国产无遮挡又黄又爽不要vip软件| 亚洲第一狼人天堂网伊人| 国产精品爽爽v在线观看无码| 高中女无套中出17p| 国产精品老熟女露脸视频| 又爽又黄又无遮挡的激情视频 | 亚洲中文字幕精品一区二区三区| 人人人爽人人爽人人av| 欧美激情一区二区三区成人| 久久亚洲色www成人| 中文无码高潮到痉挛在线视频| 亚洲一区二区精品极品| 一本久道久久综合狠狠躁av| 国产香蕉九九久久精品免费| 中文字幕国产精品第一页| 极品蜜臀黄色在线观看| 思思99热精品在线| 另类 专区 欧美 制服| 日韩丝袜欧美人妻制服| 中文字幕一区二区久久综合| 国产啪视频免费观看视频| 97久久精品人人澡人人爽| 午夜福利国产精品视频| 无翼乌口工全彩无遮挡h全彩| 中文字幕无码视频手机免费看| 伊人久久大香线蕉aⅴ色| h动态图男女啪啪27报gif| 亚洲精品香蕉一区二区| 老熟妇高潮一区二区三区| 亚洲午夜av一区二区| 97人妻中文字幕总站| 性男女做视频观看网站| 国产成人高清亚洲综合| 色综合欧美亚洲国产| 狠狠干| 99国产精品欧美一区二区三区|