代码分析说明:
部分说明请参考 Hello Triangle 以下只解释该功能的实现部分代码
import { makeSample, SampleInit } from '../../components/SampleLayout';
import triangleVertWGSL from '../../shaders/triangle.vert.wgsl';
import redFragWGSL from '../../shaders/red.frag.wgsl';
const init: SampleInit = async ({ canvas, pageState }) => {
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
if (!pageState.active) return;
const context = canvas.getContext('webgpu') as GPUCanvasContext;
const devicePixelRatio = window.devicePixelRatio;
canvas.width = canvas.clientWidth * devicePixelRatio;
canvas.height = canvas.clientHeight * devicePixelRatio;
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
context.configure({
device,
format: presentationFormat,
alphaMode: 'premultiplied',
});
// 采样次数
const sampleCount = 4;
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {
module: device.createShaderModule({
code: triangleVertWGSL,
}),
entryPoint: 'main',
},
fragment: {
module: device.createShaderModule({
code: redFragWGSL,
}),
entryPoint: 'main',
targets: [
{
format: presentationFormat,
},
],
},
primitive: {
topology: 'triangle-list',
},
// 渲染管线中添加采样次数
multisample: {
count: 4,
},
});
// 采样所使用的纹理
const texture = device.createTexture({
size: [canvas.width, canvas.height],
sampleCount,
format: presentationFormat,
// 设置纹理的用例为渲染附件
usage: GPUTextureUsage.RENDER_ATTACHMENT,
});
// 该纹理为渲染的view
const view = texture.createView();
function frame() {
// Sample is no longer the active page.
if (!pageState.active) return;
const commandEncoder = device.createCommandEncoder();
const renderPassDescriptor: GPURenderPassDescriptor = {
colorAttachments: [
{
// 渲染的view
view,
// 如果view是多采样的,该纹理子资源将接收此颜色附件的解析输出
resolveTarget: context.getCurrentTexture().createView(),
clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
loadOp: 'clear',
storeOp: 'discard',
},
],
};
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setPipeline(pipeline);
passEncoder.draw(3);
passEncoder.end();
device.queue.submit([commandEncoder.finish()]);
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
};
顶点着色器
@vertex
fn main(
@builtin(vertex_index) VertexIndex : u32
) -> @builtin(position) vec4<f32> {
var pos = array<vec2<f32>, 3>(
vec2(0.0, 0.5),
vec2(-0.5, -0.5),
vec2(0.5, -0.5)
);
return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
}
片元着色器
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4(1.0, 0.0, 0.0, 1.0);
}
总结步骤:
-
navigator.gpu.requestAdapter
申请适配器 -
adapter.requestDevice
申请设备 -
canvas.getContext('webgpu')
获取GPU上下文 -
context.configure
配置上下文,将设备传给上下文 -
device.createRenderPipeline
创建渲染管线,并设置多重渲染的次数 multisample
6.device.createTexture
创建多重渲染的纹理,将纹理的view 传入编码器
-
device.createCommandEncoder
创建编码器 -
commandEncoder.beginRenderPass
开始编码由 descriptor 描述的渲染过程,将view设置为多重渲染纹理的view, resolveTarget设置为canvas的 view
9 passEncoder.setPipeline
设置渲染管线
-
passEncoder.draw
设置绘制顶点数 -
passEncoder.end
编码结束 -
commandEncoder.finish
完成编码 -
device.queue.submit
提交编码器
网友评论