안녕하십니까, 크롬 -> 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 함수 호출) :
setSubData 차지 91.54 %
지속적인지도 버퍼 (setBufferDataByPersistentMapBuffer 함수 호출)를 사용합니다 :
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 단편 거부 동일한 의미)