WebGPU 학습 (육) : 학습 "rotatingCube"예를

안녕하십니까, 크롬 -> webgpu-samplers->이 문서의 rotatingCube 예 배울 수 있습니다.

마지막 게시물 :
WebGPU 학습 (다섯) : 현대적인 그래픽 API 지원 기술 포인트 WebGPU 조사

rotatingCube.ts 알아보기

우리는 배웠습니다 "삼각형 그리기", 그것과 비교 예를 들어,이 예는 다음과 같은 요소를 추가합니다 :

  • 전송 행렬에 대한 모델 (UBO로 약칭 함)을 균일 버퍼 개체 증가 뷰 매트릭스 생성 행렬을 투영 행렬 (매트릭스 MVP이라 함), 각각의 프레임에서 업데이트된다
  • 설정 정점
  • 열기 컬링
  • 열기 깊이 테스트

아래, 우리는 열 rotatingCube.ts의 새에 차례로 모습에, 파일 :

균일 버퍼 개체 늘리기

소개

WebGL을 1에서는 각 게임 오브젝트 (예를 들어 diffuseMap 미만성 색상 모델 행렬 등) uniform1i 통해 쉐이더, uniform4fv 다른 기능에 대응 균일 변수를 전달한다.
다음과 같은 값의 대부분은 예를 들어, 전달 될 필요가 없습니다 :
? gameObject1 및 gameObject3이 같은 shader1를 사용할 경우, 같은 확산 색상을 가지고, 당신은 단지 확산 색상 중 하나를 통과해야하지만, 일반적으로 우리가 넣어 WebGL을 1 이 확산 색상은 비용의 중복의 결과로 전달됩니다.

WebGPU 균일 버퍼 객체를 사용하면 균일 한 변수를 전달한다. 글로벌 균일 버퍼 우리는 단지 각 패스 범위에 사용되는 설정 데이터 (오프셋 크기가 설정)을 렌더링하는 값을 설정해야 할 버퍼 그래서 동일한 데이터 재사용있다. 값이 균일 변경된 경우 균일 버퍼 만이 대응하는 데이터를 수정해야한다.

WebGPU, 우리는 UBO 모든 게임 오브젝트에게 모델 행렬을 넣을 수있는 모든 카메라의 뷰 및 투영 행렬은 난반사 컬러, 거울 등의 데이터 (의 UBO (등과 퐁 재료 PBR 재료와 같은) 각각의 재료를 설정할 UBO에 색상 등), 각각의 광 (예를 들면, 데이터 (방향 광, 점 광원 등) 예를 들어, 유효 오버 헤드 송신 균일 변수를 줄일 수 UBO로 광 컬러, 조명 위치 등).

또한, 우리는주의를 기울 UBO 메모리 레이아웃에 필요
가 각 열 네 개의 요소가 동의 기본 레이아웃은 std140 우리가 대략적으로 이해할 수 있습니다.
이제 설명 해보자
다음 UBO 균일 해당 블록의 레이아웃 std140 같이 정의된다 :

layout (std140) uniform ExampleBlock
{
    float value;
    vec3  vector;
    mat4  matrix;
    float values[3];
    bool  boolean;
    int   integer;
};

그것은 실제 레이아웃의 메모리에 :

layout (std140) uniform ExampleBlock
{
                     // base alignment  // aligned offset
    float value;     // 4               // 0 
    vec3 vector;     // 16              // 16  (must be multiple of 16 so 4->16)
    mat4 matrix;     // 16              // 32  (column 0)
                     // 16              // 48  (column 1)
                     // 16              // 64  (column 2)
                     // 16              // 80  (column 3)
    float values[3]; // 16              // 96  (values[0])
                     // 16              // 112 (values[1])
                     // 16              // 128 (values[2])
    bool boolean;    // 4               // 144
    int integer;     // 4               // 148
};

즉, 제 1 엘리먼트 UBO 2-4 0 (정렬하는) 제 요소 값이고,이며,
X, Y, Z의 벡터 값 th 요소 5-7와 여덟 번째 요소는 0 ;
9-24 행렬 요소 값 (열 순위)
배열의 값 25-27 요소 값은 제 부재 (28)는 0,
29 소자, 제 플로트에 부울 값 30 0 ~ 32 요소;
34-36 0 첫 번째 요소로 정수 값 부동의 첫 요소 (33).

이 샘플 코드의 분석에 대응

  • 정점 셰이더 균일 블록 정의

다음과 같이 코드입니다 :

  const vertexShaderGLSL = `#version 450
  layout(set = 0, binding = 0) uniform Uniforms {
    mat4 modelViewProjectionMatrix;
  } uniforms;
  ...
  void main() {
    gl_Position = uniforms.modelViewProjectionMatrix * position;
    fragColor = color;
  }
  `;

std140의 기본 레이아웃은 세트를 지정하고, 바인딩 매트릭스 MVP 포함

  • uniformsBindGroupLayout 만들기

다음과 같이 코드입니다 :

  const uniformsBindGroupLayout = device.createBindGroupLayout({
    bindings: [{
      binding: 0,
      visibility: 1,
      type: "uniform-buffer"
    }]
  });

시야 (1 같음) GPUShaderStage.VERTEX 입력 "균일 버퍼"로 지정된

  • 균일 한 버퍼를 만들기

다음과 같이 코드입니다 :

  const uniformBufferSize = 4 * 16; // BYTES_PER_ELEMENT(4) * matrix length(4 * 4 = 16)

  const uniformBuffer = device.createBuffer({
    size: uniformBufferSize,
    usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
  });
  • 균일 한 바인딩 그룹 만들기

다음과 같이 코드입니다 :

  const uniformBindGroup = device.createBindGroup({
    layout: uniformsBindGroupLayout,
    bindings: [{
      binding: 0,
      resource: {
        buffer: uniformBuffer,
      },
    }],
  });
  • 균일 한 버퍼의 데이터 프레임 각각 업데이트 MVP 행렬

다음과 같이 코드입니다 :

  //因为是固定相机,所以只需要计算一次projection矩阵
  const aspect = Math.abs(canvas.width / canvas.height);
  let projectionMatrix = mat4.create();
  mat4.perspective(projectionMatrix, (2 * Math.PI) / 5, aspect, 1, 100.0);
  
  ...
 
  
  //计算mvp矩阵
  function getTransformationMatrix() {
    let viewMatrix = mat4.create();
    mat4.translate(viewMatrix, viewMatrix, vec3.fromValues(0, 0, -5));
    let now = Date.now() / 1000;
    mat4.rotate(viewMatrix, viewMatrix, 1, vec3.fromValues(Math.sin(now), Math.cos(now), 0));

    let modelViewProjectionMatrix = mat4.create();
    mat4.multiply(modelViewProjectionMatrix, projectionMatrix, viewMatrix);

    return modelViewProjectionMatrix;
  }
  
  ...
  return function frame() {
    uniformBuffer.setSubData(0, getTransformationMatrix());
    ...
  }
  • 패스 설정 바인드 그룹을 렌더링

다음과 같이 코드입니다 :

    ...
    passEncoder.setBindGroup(0, uniformBindGroup);

"업데이트 유니폼 버퍼"의 상세 분석

이 예는 업데이트 setSubData 균일 버퍼를 사용

  return function frame() {
    uniformBuffer.setSubData(0, getTransformationMatrix());
    ...
  }

우리 WebGPU 학습 (다섯) : 현대적인 그래픽 API 지원 기술 포인트 WebGPU 조사 -> 접근 제로 드라이버 overhead-> 지속적인 지도 버퍼 , 레퍼런스이다 "라고 GPU로 전송 데이터를 CPU"를 달성하는 방법은 두 가지가 있습니다 WebGPU되어, GPUBuffer 업데이트 된 값 :
1. 전화 GPUBuffer-> setSubData 방법
2. 지속적인지도 버퍼 기술

우리는이 예제에서는 두 번째 방법을 사용하는 방법을 살펴 :

function setBufferDataByPersistentMapBuffer(device, commandEncoder, uniformBufferSize, uniformBuffer, mvpMatricesData) {
    const [srcBuffer, arrayBuffer] = device.createBufferMapped({
        size: uniformBufferSize,
        usage: GPUBufferUsage.COPY_SRC
    });

    new Float32Array(arrayBuffer).set(mvpMatricesData);
    srcBuffer.unmap();

    commandEncoder.copyBufferToBuffer(srcBuffer, 0, uniformBuffer, 0, uniformBufferSize);
    const commandBuffer = commandEncoder.finish();

    const queue = device.defaultQueue;
    queue.submit([commandBuffer]);

    srcBuffer.destroy();
}

return function frame() {
    //uniformBuffer.setSubData(0, getTransformationMatrix());
     ...

    const commandEncoder = device.createCommandEncoder({});

    setBufferDataByPersistentMapBuffer(device, commandEncoder, uniformBufferSize, uniformBuffer, getTransformationMatrix());
     ...
}

성능을 검증하기 위해, 나는 한 벤치 마크 테스트를 UBO를 생성, 그것은 160,000 mat4, 실시 JS 프로파일을 포함 :

사용 setSubData (setBufferDataBySetSubData 함수 호출) :
2019년 12월 22일 스크린 샷 아침 10.09.43.png-38.6kB

setSubData 차지 91.54 %

지속적인지도 버퍼 (setBufferDataByPersistentMapBuffer 함수 호출)를 사용합니다 :
2019년 12월 22일 스크린 샷 아침 10.09.50.png-52.9kB

createBufferMapped 和 setBufferDataByPersistentMapBuffer 占 72.72 + 18.06 = 90.78 %

우리는 거의 2 성능을 볼 수 있습니다. 이 방법을 선호한다 그래서 그러나 원칙에서 지속적으로지도 버퍼를 고려하면, 빠른 (CPU와 GPU 점유율, 복사 할 필요가 없습니다 버퍼)을 달성했다.

또한, WebGPU 커뮤니티는 여전히 (사람이 GPUUploadBuffer 패스를 높이기 위해 제안하는 경우) 우리는 또한 그 점에서 모니터 진행을 계속 할 필요가 있으므로, 업데이트 버퍼 데이터를 최적화하는 방법을 논의하고있다.

참고 자료

고급-GLSL -> 통일 버퍼 오브젝트

설정 정점

  • 정점의 위치 ()에서 색 데이터 속성에 대한 버텍스 쉐이더 전송

다음과 같이 코드입니다 :

  const vertexShaderGLSL = `#version 450
  ...
  layout(location = 0) in vec4 position;
  layout(location = 1) in vec4 color;
  layout(location = 0) out vec4 fragColor;
  void main() {
    gl_Position = uniforms.modelViewProjectionMatrix * position;
    fragColor = color;
  }
  
  const fragmentShaderGLSL = `#version 450
  layout(location = 0) in vec4 fragColor;
  layout(location = 0) out vec4 outColor;
  void main() {
    outColor = fragColor;
  }
  `;

여기 fragColor 색상을 설정하고, 설정 한 outColor 프래그먼트 쉐이더 fragColor를 수신한다 (아웃 WebGL에 대응 한 변수를 변경)함으로써 색 정점 색에 대응하는 프래그먼트

  • , 정점 버퍼 세트 큐브 정점 데이터를 생성

다음과 같이 코드입니다 :

cube.ts:

//每个顶点包含position,color,uv数据
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,

    1, 1, 1, 1,    1, 1, 1, 1,  1, 1,
    1, -1, 1, 1,   1, 0, 1, 1,  0, 1,
    1, -1, -1, 1,  1, 0, 0, 1,  0, 0,
    1, 1, -1, 1,   1, 1, 0, 1,  1, 0,
    1, 1, 1, 1,    1, 1, 1, 1,  1, 1,
    1, -1, -1, 1,  1, 0, 0, 1,  0, 0,

    -1, 1, 1, 1,   0, 1, 1, 1,  1, 1,
    1, 1, 1, 1,    1, 1, 1, 1,  0, 1,
    1, 1, -1, 1,   1, 1, 0, 1,  0, 0,
    -1, 1, -1, 1,  0, 1, 0, 1,  1, 0,
    -1, 1, 1, 1,   0, 1, 1, 1,  1, 1,
    1, 1, -1, 1,   1, 1, 0, 1,  0, 0,

    -1, -1, 1, 1,  0, 0, 1, 1,  1, 1,
    -1, 1, 1, 1,   0, 1, 1, 1,  0, 1,
    -1, 1, -1, 1,  0, 1, 0, 1,  0, 0,
    -1, -1, -1, 1, 0, 0, 0, 1,  1, 0,
    -1, -1, 1, 1,  0, 0, 1, 1,  1, 1,
    -1, 1, -1, 1,  0, 1, 0, 1,  0, 0,

    1, 1, 1, 1,    1, 1, 1, 1,  1, 1,
    -1, 1, 1, 1,   0, 1, 1, 1,  0, 1,
    -1, -1, 1, 1,  0, 0, 1, 1,  0, 0,
    -1, -1, 1, 1,  0, 0, 1, 1,  0, 0,
    1, -1, 1, 1,   1, 0, 1, 1,  1, 0,
    1, 1, 1, 1,    1, 1, 1, 1,  1, 1,

    1, -1, -1, 1,  1, 0, 0, 1,  1, 1,
    -1, -1, -1, 1, 0, 0, 0, 1,  0, 1,
    -1, 1, -1, 1,  0, 1, 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,
]);
rotatingCube.ts:

  const verticesBuffer = device.createBuffer({
    size: cubeVertexArray.byteLength,
    usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
  });
  verticesBuffer.setSubData(0, cubeVertexArray);

정점 데이터의 한 세트가,이 설정 setSubData 여기에 사용될 수 있기 때문에, 성능에 거의 영향을 미치지

  • 당신이 렌더링 파이프 라인을 작성, 지정된 속성 정점 셰이더

다음과 같이 코드입니다 :

cube.ts:

export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.
export const cubePositionOffset = 0;
export const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.
rotatingCube.ts:

  const pipeline = device.createRenderPipeline({
    ...
    vertexState: {
      vertexBuffers: [{
        arrayStride: cubeVertexSize,
        attributes: [{
          // position
          shaderLocation: 0,
          offset: cubePositionOffset,
          format: "float4"
        }, {
          // color
          shaderLocation: 1,
          offset: cubeColorOffset,
          format: "float4"
        }]
      }],
    },
    ...
  });
  • 꼭지점의 수는 패스 - 렌더링> (36)를 지정 그리는

다음과 같이 코드입니다 :

  return function frame() {
    ...
    const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
    ...
    passEncoder.draw(36, 1, 0, 0);
    passEncoder.endPass();
    ...
  }

열기 컬링

관련 코드는 다음과 같습니다

  const pipeline = device.createRenderPipeline({
    ...
    rasterizationState: {
      cullMode: 'back',
    },
    ...
  });

로 정의 관련 :

enum GPUFrontFace {
    "ccw",
    "cw"
};
enum GPUCullMode {
    "none",
    "front",
    "back"
};
...

dictionary GPURasterizationStateDescriptor {
    GPUFrontFace frontFace = "ccw";
    GPUCullMode cullMode = "none";
    ...
};

어떤 CCW 시계 반대 방향으로는, CW는 시계 방향으로 나타냅니다.

본 실시 예는 외부 cullMode 위로 제공되지 frontFace (frontFace 기본 CCW)는 것이다 WebGPU 반 삼각형의 모든 배면 (내부 커넥터의 정점 방향으로, 즉 시계 방향으로 삼각형)에 제공되기 때문에 잡초

참고 자료

[얻기가 WebGL] VI 다각형 정점 및
조사 : 래스터 주

열기 깊이 테스트

이제 관련 코드의 분석 및 템플릿 테스트와 관련된 코드를 무시 :

  • 당신이 렌더링 파이프 라인을 생성, 설정 depthStencilState

다음과 같이 코드입니다 :

  const pipeline = device.createRenderPipeline({
    ...
    depthStencilState: {
      //开启深度测试
      depthWriteEnabled: true,
      //设置比较函数为less,后面会继续说明 
      depthCompare: "less",
      //设置depth为24bit
      format: "depth24plus-stencil8",
    },
    ...
  });
  • (형식은 또한 24 비트 1의 그것의 크기 -> 깊이 주) 깊이 텍스처를 생성, 그것의 뷰 및 스텐실 attachment-> 첨부 통과 -> 깊이를 렌더링하도록 설정되어

다음과 같이 코드입니다 :

  const depthTexture = device.createTexture({
    size: {
      width: canvas.width,
      height: canvas.height,
      depth: 1
    },
    format: "depth24plus-stencil8",
    usage: GPUTextureUsage.OUTPUT_ATTACHMENT
  });

  const renderPassDescriptor: GPURenderPassDescriptor = {
    ...
    depthStencilAttachment: {
      attachment: depthTexture.createView(),

      depthLoadValue: 1.0,
      depthStoreOp: "store",
      ...
    }
  };

그 중, depthStencilAttachment는 다음과 같이 정의된다 :

dictionary GPURenderPassDepthStencilAttachmentDescriptor {
    required GPUTextureView attachment;

    required (GPULoadOp or float) depthLoadValue;
    required GPUStoreOp depthStoreOp;
    ...
};

depthLoadValue와와 depthStoreOp WebGPU 학습 (II) : 학습 "삼각형을 그리기"예 -> 분석 렌더링 패스 -> colorAttachment loadOp StoreOp이 예를 들어, 우리가 분석처럼 직접 관련 코드 :


  const pipeline = device.createRenderPipeline({
    ...
    depthStencilState: {
      ...
      depthCompare: "less",
      ...
    },
    ...
  });
  
  ...

  const renderPassDescriptor: GPURenderPassDescriptor = {
    ...
    depthStencilAttachment: {
      ...
      depthLoadValue: 1.0,
      depthStoreOp: "store",
      ...
    }
  };

깊이 테스트는 depthLoadValue 값 GPU의 Z 값을 단편화 할 경우 (범위 [0.0-1.0])는 본 명세서 (여기서는 1.0)의 비교를 제공 하였다. 비교 함수가 사용하는 함수를 정의 depthCompare 상기 (여기서, 이하, Z의보다 큰 모든 값 또는 1.0 단편 거부 동일한 의미)

참고 자료

깊이 테스트

최종 렌더링 결과

스크린 샷 12.01.20.png-54.8kB 2019년 12월 22일 PM

참고 자료

WebGPU规范
webgpu 샘플러 Github에서 리포
WebGPU-5

추천

출처www.cnblogs.com/chaogex/p/12079739.html