什么是WebGPU
三维技术是前端不可分割的一部分,如何在网页中显示各种三维模型?搭建三维场景?运行三维游戏?想必各位前端开发首先想到的就是WebGL。WebGL基于openGL ES进行了两次迭代,现在大多数浏览器支持WebGL 2.0。然而,WebGL技术已经远远落后于现代显卡的发展速度,导致WebGL开发出的三维应用的性能远不及使用现代Api的本地应用。这给网页3D的应用带来了很大的瓶颈。
WebGPU就是用来弥补差距的浏览器全新Api。说是WebGPU,实际上是对WebGL Api的升级。它使用了现代显卡Api和全新工作流,减少了JS和显卡的通信次数,开发了新的shader语言,并兼容了了能够最大化各家显卡性能的Api。目前,一些主流的开源库已经使用上了这项技术,如Threejs、Babylonjs和tensorflowjs等。它们宣称WebGPU带来了数倍乃至上百倍的性能提升。
webgpu是一种简单的系统,它所做的也只不过是在GPU上运行三种函数:顶点着色器、片元着色器和计算着色器。
- 上图上有一个管道,包含两个GPU可以运行的着色器,点着色器和片元着色器,当然,你也可以有一个计算着色器
- 着色器通过bindGroup指向资源(buffer, texture,sample)
- 管道间接通过内部状态引用缓存区的属性
- 属性从缓冲区提取数据,并将数据输入顶点着色器
- 顶点着色器可能数据反馈给片元着色器
- 片元着色器通过渲染过程描述写入纹理
要在GPU上执行着色器,需要创建所有这些资源并设置此状态。资源的创造是相对直接的。一件有趣的事情是,大多数Web GPU资源在创建后无法更改。你可以更改它们的内容,但不能更改它们的大小、用法、格式等。如果你想更改其中的任何内容,你可以创建一个新资源并销毁旧资源。
一些状态是通过创建然后执行命令缓冲区来设置的。命令缓冲区顾名思义。它们是命令的缓冲区。您可以创建编码器。编码器将命令编码到命令缓冲器中。然后完成编码器,它会为您提供它创建的命令缓冲区。然后,您可以提交该命令缓冲区,让Web GPU执行命令。
如下代码,绘制一个三角形:
async function main() {
const adapter = await navigator.gpu?.requestAdapter();
const device = await adapter?.requestDevice();
if (!device) {
fail('need a browser that supports WebGPU');
return;
}
// Get a WebGPU context from the canvas and configure it
const canvas = document.querySelector('canvas');
const context = canvas.getContext('webgpu');
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
context.configure({
device,
format: presentationFormat,
});
const module = device.createShaderModule({
label: 'our hardcoded red triangle shaders',
code: `
@vertex fn vs(
@builtin(vertex_index) vertexIndex : u32
) -> @builtin(position) vec4f {
var pos = array<vec2f, 3>(
vec2f( 0.0, 0.5), // top center
vec2f(-0.5, -0.5), // bottom left
vec2f( 0.5, -0.5) // bottom right
);
return vec4f(pos[vertexIndex], 0.0, 1.0);
}
@fragment fn fs() -> @location(0) vec4f {
return vec4f(1, 0, 0, 1);
}
`,
});
const pipeline = device.createRenderPipeline({
label: 'our hardcoded red triangle pipeline',
layout: 'auto',
vertex: {
module,
entryPoint: 'vs',
},
fragment: {
module,
entryPoint: 'fs',
targets: [{ format: presentationFormat }],
},
});
const renderPassDescriptor = {
label: 'our basic canvas renderPass',
colorAttachments: [
{
// view: <- to be filled out when we render
clearValue: [0.3, 0.3, 0.3, 1],
loadOp: 'clear',
storeOp: 'store',
},
],
};
function render() {
// Get the current texture from the canvas context and
// set it as the texture to render to.
renderPassDescriptor.colorAttachments[0].view =
context.getCurrentTexture().createView();
// make a command encoder to start encoding commands
const encoder = device.createCommandEncoder({ label: 'our encoder' });
// make a render pass encoder to encode render specific commands
const pass = encoder.beginRenderPass(renderPassDescriptor);
pass.setPipeline(pipeline);
pass.draw(3); // call our vertex shader 3 times.
pass.end();
const commandBuffer = encoder.finish();
device.queue.submit([commandBuffer]);
}
render();
}
function fail(msg) {
// eslint-disable-next-line no-alert
alert(msg);
}
main();
WebGPU要怎么学呢?
笔者在WebGPU正式推出后,就开始了对WebGPU的学习。到现在也有一两个月了。中间走了不少弯路,也得到了很多感悟,最终也算是有所收获。我下面就根据我的经验梳理一下WebGPU的学习过程,让大家少走一些弯路,也能够对WebGPU这项技术有一个较深的理解。
首先要明白一点,如果你要学习就需要深入的学习,从基础到应用,如果你只是想参考例子写一个玩具,我觉得读到这里应该就可以了,去找几个Web3D开源库,参考例子Copy Copy玩玩就行了。下面我介绍的学习过程是需要你下一番功夫,耗费点脑力的。
其实学习过程很简单,也就几步:
- 由于WebGPU是3D技术,它的基础是图形学,图像学的基础是数学,主要是线性代数。首先需要去复习一个基础的线性代数知识。其次,需要对图形学的基础知识有基础的了解。这里推荐闫令琪的Games 101课程,还有李伟老师写的博客李伟的博客 (yxyy.name)(在掘金也可以搜到李伟老师的写的博客)
- 在有了基础的线性代数和图形学知识后,便可以学习WebGPU相关的Api了,这里推荐WebGPU Fundamentals,在这本教程里对WebGPU进行了由浅入深的教学讲解,读完这个教程,基本上就能够说对WebGPU入门了,可以去应对各种应用了。
- 学习了WebGPU相关Api后,便可以去学习基于WebGPU的各种流行的开源Web3D库了,如babylonjs,threejs等
github也开了awesome-webgpu,可以找到各种想要的知识:
以上就是全部内容了。希望我的分享能够给您带来收获。可以关注我,或者关注我的公众号:风筝文刊,我将常伴你左右!