本文是个WebGPU基础入门教程,阐述如何从0开始基于WebGPU+WGSL着色器语言渲染一个三角形。由于WebGPU仍然没有发布1.0,API和着色器语言WGSL变换非常快,本文是目前(2021-7-10)最新的API实现,最新API比笔者半年前接触的话语法上简化了不少。在正式开始尝鲜前,先看下WebGPU与WebGL2的对比:
webgpu
webgl2
从视觉效果上看,webgpu流光溢彩,动画流畅,webgl2显卡由于不咋的,带不动,卡顿严重,色彩暗淡,应该是不支持光线追踪导致的,结论是webgpu吊打webgl。
体验地址:https://toji.github.io/webgpu-clustered-shading/
需要安装chrome金丝雀版本并开启webgpu才能看,设置见下文。
一 WebGPU学习资料
官方地址:https://github.com/gpuweb/gpuweb
WebGPU API文档:https://gpuweb.github.io/gpuweb/#intro
WGSL着色器API文档:https://gpuweb.github.io/gpuweb/wgsl/
官方示例:https://github.com/austinEng/webgpu-samples
除官方资料外,还有比较丰富的社区资料。
知乎大神wonder-yyc专栏:https://zhuanlan.zhihu.com/p/95956384
还有一个github中文学习教程,这个练习内容简单,但是介绍为什么要学习WebGPU为什么要替换WebGL比较详细:
https://github.com/hjlld/LearningWebGPU
韩国的一个内容不错的学习仓库,示例内容比较丰富:
https://github.com/redcamel/webgpu/
除官方示例紧跟WebGPU API外,其他资料只能学习参考了,由于API变更和着色器从GLSL-->WGSL的转换,社区资料都运行不了了。
二 Hello WebGPU
程序员学习任何语言,一开始都有个打印Hello World的代码,通常就一行代码,但无论学习WebGL还是WebGPU,hello world比你想象的要复杂多了,绘制三角形就是图形引擎的helloworld,来看看如何使用最新的API进行渲染学习吧。
2.1 环境准备
先下载谷歌浏览金丝雀版本,下载地址:
https://www.google.cn/intl/zh-CN/chrome/canary/
下载完毕,next安装,easy。
设置WebGPU支持:
打开chrome canary浏览器,在url地址中输入:
chrome://flags/#enable-unsafe-webgpu

将webgpu启用。
2.2 示例说明
获取webgpu的交互上下文context
与开发canvas和webgl一样,首先要从浏览器获取交互上下文context:
//获取显卡适配器const adapter = await navigator.gpu.requestAdapter({powerPreference: 'high-performance'});//获取设备const device = await adapter.requestDevice();//获取gpu交互上下文const context = canvas.getContext("gpupresent");// 交换链,用于显卡往显示器输出图像const swapChainFormat = "bgra8unorm";context.configure({device,format: swapChainFormat,});
初始化顶点buffer
webgl中常规操作,传入顶点数组给顶点着色器,webgpu里稍微麻烦点,参考示例代码:
//测试三角形const vertexArray = new Float32Array([0.0, 0.5,-0.5, -0.5,0.5, -0.5]);const verticesBuffer = device.createBuffer({size: vertexArray.byteLength,usage: GPUBufferUsage.VERTEX,//显示声明该buffer是给顶点着色器使用mappedAtCreation: true,});new Float32Array(verticesBuffer.getMappedRange()).set(vertexArray);verticesBuffer.unmap();
定义渲染管线
webgl中首先使用glsl着色器语言定义好顶点着色器,片元着色器,然后根据两个着色器创建一个渲染的program。同理,webgpu中是使用wgsl创建着色器,并创建渲染管线。
//定义顶点和片元着色器const wgslShaders = {vertex: `[[stage(vertex)]]fn main([[location(0)]] a_position : vec2<f32>) -> [[builtin(position)]] vec4<f32> {return vec4<f32>(a_position, 0.0, 1.0);}`,fragment: `[[stage(fragment)]]fn main() -> [[location(0)]] vec4<f32> {return vec4<f32>(1.0, 0.0, 0.0, 1.0);}`};//定义渲染管线const pipeline = device.createRenderPipeline({vertex: {module: device.createShaderModule({code: wgslShaders.vertex,}),entryPoint: "main",buffers: [{/*步进值,也就是每个顶点需要占用几个储存空间,单位是 byte。我们是用 Float32Array 来储存顶点位置的,每个 32 位浮点数需要 4 个 byte;xyz三维顶点需要 3 个 32 位浮点数来分别表示,即 4 * 3 byte。xy二维顶点需要2个32 位浮点数来分别表示,即 4 * 2 个 byte。*/arrayStride: 4 * 2,attributes: [{// position//对应顶点着色器中 (location = 0)shaderLocation: 0,//0代表从头开始,不设置位移,有时候可以将多个顶点写一个buffer,根据offset位移选择用于不同地方offset: 0,//2个32位浮点数,如果3个32位浮点数,就可以写float32x3format: "float32x2",}],},]},fragment: {module: device.createShaderModule({code: wgslShaders.fragment,}),entryPoint: "main",targets: [{format: swapChainFormat,},],},// 绘制模式/*enum GPUPrimitiveTopology {"point-list","line-list","line-strip","triangle-list","triangle-strip"};*/primitive: {topology: 'triangle-list',}});
创建渲染函数
webgl中创建完program和各种buffer,buffer或vao绑定program后,需要写一个render函数,让webgl渲染,再把这个函数挂到动画函数里,webgpu也一样,需要声明一个渲染函数:
function frame() {const commandEncoder = device.createCommandEncoder();// 获取当前纹理图像const textureView = context.getCurrentTexture().createView();// 渲染通道描述const renderPassDescriptor: GPURenderPassDescriptor = {// 存储图像信息colorAttachments: [{// 指定存储图像的位置view: textureView,// 背景颜色loadValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },storeOp: 'store',// storeOp 存储选型 store 或 clear,必需显示声明// resolveTarget 多重采样},],};//开启一个渲染通道const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);//默认会开启一个视口viewport,宽高就是canvas的width height而不是clientwidth,clientheight//设置 渲染管线passEncoder.setPipeline(pipeline);// 设置顶点buffer,0就是渲染管线中shaderLocation:0定义的buffer位置// 意思在声明的位置绑定这个设置好的bufferpassEncoder.setVertexBuffer(0, verticesBuffer);passEncoder.draw(3, 1, 0, 0);passEncoder.endPass();device.queue.submit([commandEncoder.finish()]);}
好了,入门代码就这么多了,完整代码参考:
https://github.com/FreeGIS/webgpu_learning/
代码下载下来,三板斧:
//安装依赖npm install// 编译npm run build// 启动npm run serve
之后用chrome canary浏览器打开,效果如下:

入门东西就这么多,如果要深入学习,首先需要图形学基础,其次根据官网和大神示例多理解消化吸收,功夫不负有心人的。。。




