WebGPU 下一代浏览器图形 API
FreeGuideOnline
最新
2026-07-11
2. JavaScript 代码 (main.js)
async function main() {
const canvas = document.getElementById('canvas');
if (!navigator.gpu) {
throw new Error('WebGPU not supported');
}
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const context = canvas.getContext('webgpu');
const format = navigator.gpu.getPreferredCanvasFormat();
context.configure({
device,
format,
alphaMode: 'opaque',
});
// 三角形顶点数据(NDC坐标)
const vertices = new Float32Array([
0.0, 0.5, 0.0, // 上
-0.5, -0.5, 0.0, // 左下
0.5, -0.5, 0.0, // 右下
]);
const vertexBuffer = device.createBuffer({
size: vertices.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertices);
// WGSL 着色器代码
const shaderCode = `
@vertex
fn vs_main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return vec4<f32>(pos, 1.0);
}
@fragment
fn fs_main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0); // 红色
}
`;
const shaderModule = device.createShaderModule({ code: shaderCode });
// 管线布局(空,因为我们没有绑定资源)
const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [] });
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: pipelineLayout,
vertex: {
module: shaderModule,
entryPoint: 'vs_main',
buffers: [{
arrayStride: 3 * 4, // 3个float
attributes: [{
shaderLocation: 0,
offset: 0,
format: 'float32x3',
}],
}],
},
fragment: {
module: shaderModule,
entryPoint: 'fs_main',
targets: [{ format }],
},
primitive: {
topology: 'triangle-list',
},
});
// 渲染循环
function frame() {
const commandEncoder = device.createCommandEncoder();
const textureView = context.getCurrentTexture().createView();
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: textureView,
clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
loadOp: 'clear',
storeOp: 'store',
}],
});
renderPass.setPipeline(pipeline);
renderPass.setVertexBuffer(0, vertexBuffer);
renderPass.draw(3); // 3个顶点
renderPass.end();
device.queue.submit([commandEncoder.finish()]);
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
}
main().catch(console.error);