WebGPU 培训
WebGPU是什么? 它是一个在浏览器中实现低级图形渲染的API,可以让Web开发人员利用GPU提高渲染性能。WebGPU支持多种GPU,并允许Web应用程序通过JavaScript,WebAssembly或HLSL代码与GPU通信。
WebGPU可与WebGL和WebXR等其他Web图形API配合使用,但它是更先进和更灵活的API,提供了更多的控制权和更好的性能,从而更适合处理复杂和大型3D场景。
要使用WebGPU,需要使用最新的Web浏览器(如Chrome)和支持WebGPU的GPU。
const adapter = await navigator.gpu.requestAdapter(); const device = await adapter.requestDevice();
使用WebGPU,我们需要获取GPU的适配器(adapter)和设备(device),并将其存储在变量中,以便我们可以在GPU上执行操作。
实用WebGPU
1. 使用WebGPU渲染三角形
在使用WebGPU渲染三角形之前,需要进行一些准备工作。我们需要编写代码来创建窗口、初始化WebGPU并定义渲染器所需的常量和资源。在这里,我们使用了GLSL作为着色语言。
let vertexShader =
`
#version 450
layout(location = 0) in vec3 pos;
void main() {
gl_Position = vec4(pos, 1.0);
}
`;
let fragmentShader =
`
#version 450
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(1.0, 1.0, 1.0, 1.0);
}
`;
async function main() {
// Step 1: Create a window to render into.
const canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Step 2: Initialize WebGPU and create the "context".
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const context = canvas.getContext('gpupresent');
// Step 3: Define the shader modules (i.e. the shader code).
const shaderModule =
device.createShaderModule({
code: vertexShader
});
const fragModule = device.createShaderModule({
code: fragmentShader
});
// Step 4: Define the pipeline layout. This specifies the vertex input
// format, and any other inputs we will be using in our shaders.
const layout = device.createPipelineLayout({
bindGroupLayouts: []
});
// Step 5: Define the render pipeline. This specifies the shaders to use,
// as well as the pipeline layout from step 4.
const pipeline = device.createRenderPipeline({
layout,
vertex: {
module: shaderModule,
entryPoint: 'main',
buffers: [{
arrayStride: 12,
attributes: [{
shaderLocation: 0,
offset: 0,
format: 'float3'
}]
}]
},
fragment: {
module: fragModule,
entryPoint: 'main',
targets: [{
format: 'rgba8unorm'
}]
},
primitive: {
topology: 'triangle-list',
stripIndexFormat: undefined,
frontFace: 'ccw',
cullMode: 'none',
clampDepth: false
},
depthStencil: {
format: undefined,
depthWriteEnabled: false,
depthCompare: 'always',
stencilFront: {
compare: 'always',
failOp: 'keep',
passOp: 'keep',
depthFailOp: 'keep'
},
stencilBack: {
compare: 'always',
failOp: 'keep',
passOp: 'keep',
depthFailOp: 'keep'
},
stencilReadMask: 0xff,
stencilWriteMask: 0xff
}
});
// Step 6: Define the uniform buffer.
const uniformBuffer = device.createBuffer({
size: 16,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
const uniformBindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [{
binding: 0,
resource: {
buffer: uniformBuffer
}
}]
});
// Step 7: Define the render loop.
function update() {
const renderPassDescriptor = {
colorAttachments: [{
attachment: context.getCurrentTexture().createView(),
loadValue: [0, 0, 0, 1],
storeOp: 'store'
}]
};
const commandEncoder = device.createCommandEncoder();
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setPipeline(pipeline);
passEncoder.setBindGroup(0, uniformBindGroup);
passEncoder.draw(3, 1, 0, 0);
passEncoder.endPass();
device.queue.submit([commandEncoder.finish()]);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
}
main();
WebGPU React
使用WebGPU与React结合使用可以快速创建高性能的3D应用程序。下面的示例代码演示了如何在React中使用Jaspr和WebGPU来渲染一个简单的3D场景。
1. 在React中使用WebGPU渲染3D场景
import * as THREE from 'three';
import {
useResource,
useFrame,
Canvas,
} from 'react-three-fiber';
import Jaspr from 'jaspr';
function TriangleMesh(props) {
const geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(-1, 0, 0),
new THREE.Vector3(0, 1, 0),
new THREE.Vector3(1, 0, 0),
);
geometry.faces.push(new THREE.Face3(0, 1, 2));
const [meshRef] = useResource();
useFrame(({ clock }) => {
meshRef.rotation.x = clock.getElapsedTime() * 0.5;
meshRef.rotation.y = clock.getElapsedTime() * 0.8;
});
return (
v.toArray())}
itemSize={3}
/>
);
}
function Scene() {
return (
);
}
function App() {
return (
{
gl.getContext().makeCurrent();
}}
>
);
}
export default App;
2. WebGPU 渲染动画
下面是一个简单的示例代码,演示如何在WebGPU上渲染动画。
async function main() {
// Step 1: Create a window to render into.
const canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Step 2: Initialize WebGPU and create the "context".
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const context = canvas.getContext('gpupresent');
// Step 3: Define the shader modules (i.e. the shader code).
const shaderModule =
device.createShaderModule({
code: vertexShader
});
const fragModule = device.createShaderModule({
code: fragmentShader
});
// Step 4: Define the pipeline layout.
const layout = device.createPipelineLayout({
bindGroupLayouts: []
});
// Step 5: Define the render pipeline.
const pipeline = device.createRenderPipeline({
layout,
vertex: {
module: shaderModule,
entryPoint: 'main',
buffers: [{
arrayStride: 12,
attributes: [{
shaderLocation: 0,
offset: 0,
format: 'float3'
}]
}]
},
fragment: {
module: fragModule,
entryPoint: 'main',
targets: [{
format: 'rgba8unorm'
}]
},
primitive: {
topology: 'triangle-list',
stripIndexFormat: undefined,
frontFace: 'ccw',
cullMode: 'none',
clampDepth: false
},
depthStencil: {
format: undefined,
depthWriteEnabled: false,
depthCompare: 'always',
stencilFront: {
compare: 'always',
failOp: 'keep',
passOp: 'keep',
depthFailOp: 'keep'
},
stencilBack: {
compare: 'always',
failOp: 'keep',
passOp: 'keep',
depthFailOp: 'keep'
},
stencilReadMask: 0xff,
stencilWriteMask: 0xff
}
});
// Step 6: Define the uniform buffer.
const uniformBuffer = device.createBuffer({
size: 16,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
const uniformBindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [{
binding: 0,
resource: {
buffer: uniformBuffer
}
}]
});
// Step 7: Define the render loop.
let time = 0;
function update() {
const t = performance.now() / 1000.0;
const delta = t - time;
time = t;
const renderPassDescriptor = {
colorAttachments: [{
attachment: context.getCurrentTexture().createView(),
loadValue: [0, 0, 0, 1],
storeOp: 'store'
}]
};
const commandEncoder = device.createCommandEncoder();
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setPipeline(pipeline);
passEncoder.setBindGroup(0, uniformBindGroup);
passEncoder.draw(3, 1, 0, 0);
passEncoder.endPass();
device.queue.submit([commandEncoder.finish()]);
requestAnimationFrame(update);
}
update();
}
main();
原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/245345.html
微信扫一扫
支付宝扫一扫