当前位置:首页 > 科技  > 软件

WebGPU 入门:绘制一个三角形

来源: 责编: 时间:2023-11-01 09:19:00 216观看
导读大家好,我是前端西瓜哥。今天我们来入门 WebGPU,来写一个图形版本的 Hello World,即绘制一个三角形。WebGPU 是什么?WebGPU 是一个正在开发中的潜在 Web 标准和 JavaScript API,目标是提供 “现代化的 3D 图形和计算能力”

nk828资讯网——每日最新资讯28at.com

大家好,我是前端西瓜哥。nk828资讯网——每日最新资讯28at.com

今天我们来入门 WebGPU,来写一个图形版本的 Hello World,即绘制一个三角形。nk828资讯网——每日最新资讯28at.com

WebGPU 是什么?

WebGPU 是一个正在开发中的潜在 Web 标准和 JavaScript API,目标是提供 “现代化的 3D 图形和计算能力”。nk828资讯网——每日最新资讯28at.com

简单来说,WebGPU 提供一个更现代的 Web 上的图形渲染标准。nk828资讯网——每日最新资讯28at.com

WebGPU 的出现就是为了取代 WebGL 的,因为后者的 API 实在有些过时,无法利用好现代 GPU 的一些高级特性,本身的 API 设计也较难使用。nk828资讯网——每日最新资讯28at.com

相比 WebGL,WebGPU 有更好的性能表现,API 更底层更灵活,并支持更高级的现代特性,比如计算着色器。nk828资讯网——每日最新资讯28at.com

毫无疑问,WebGPU 是前端图形渲染的未来,值得去学习一下。nk828资讯网——每日最新资讯28at.com

像是以性能著称的前端图形库 PixiJS,也开始进行支持 WebGPU 的工作,并在最近发布了预览版本,声称性能将是 WebGL 的 2.5 倍。nk828资讯网——每日最新资讯28at.com

nk828资讯网——每日最新资讯28at.com

不过目前 WebGPU 还不够成熟,仍有许多工作要做,且只有少数浏览器的最新版本直接支持或通过设置开启。nk828资讯网——每日最新资讯28at.com

即使之后所有浏览器都支持了,旧版本浏览器还是不支持的,离大范围使用还有相当长的一段路要走。nk828资讯网——每日最新资讯28at.com

nk828资讯网——每日最新资讯28at.com

只能说未来可期。nk828资讯网——每日最新资讯28at.com

但生产中,我们可以做一个回退机制:如果浏览器支持 WebGPU,我们用 WebGPU 去渲染,如果不支持就回滚到 WebGL。nk828资讯网——每日最新资讯28at.com

只要在底层渲染方案上封装一层渲染器 renderer,就像 PixiJS 现在做的事情一样,个人还是比较期待它在性能上的提升的。nk828资讯网——每日最新资讯28at.com

绘制三角形

OK,我们开始用 WebGPU 绘制一个三角形。nk828资讯网——每日最新资讯28at.com

确保你的浏览器支持 WebGPU,建议用 Chrome,并更新到最新版本。nk828资讯网——每日最新资讯28at.com

这里我们创建一个宽高各为 300 的 canvas 元素,用于绘制图形。nk828资讯网——每日最新资讯28at.com

<canvas width="300" height="300"></canvas>

初始化 WebGPU 相关的一些对象。nk828资讯网——每日最新资讯28at.com

adapter 和 device

创建一个适配器对象 adapter,适配器是一个 GPU 物理硬件设备的抽象。nk828资讯网——每日最新资讯28at.com

const adapter = await navigator.gpu.requestAdapter();

requestAdapter() 方法会查看系统上所有可用的 GPU 设备,并选择其中合适的适配器。该方法可以传一些参数,去按条件匹配。比如 { powerPreference: 'low-power' } 表示优先使用低能耗的 GPU。nk828资讯网——每日最新资讯28at.com

此外,这个方法返回的是一个 Promise,即它是 异步的,需要用 await 的方式去等待异步的结果。nk828资讯网——每日最新资讯28at.com

然后基于 adapter,调用 requestDevice 方法拿到设备对象 device。nk828资讯网——每日最新资讯28at.com

device 可以理解为 adapter 的一个会话。做个比喻的话 adapter 是一个公司,device 是一个具体干活的人。nk828资讯网——每日最新资讯28at.com

const device = await adapter.requestDevice();

requestDevice() 方法也可以传入配置项,去开启一些高级特性,或是指定一些硬件限制,比如最大纹理尺寸。nk828资讯网——每日最新资讯28at.com

配置 canvas

类似 canvas 2d 和 webgl,我们需要通过 canvas 元素拿到上下文。nk828资讯网——每日最新资讯28at.com

const canvas = document.querySelector('canvas');const ctx = canvas.getContext('webgpu');

接着是调用 ctx.configure() 方法配置刚刚声明的 device 对象和像素格式。nk828资讯网——每日最新资讯28at.com

const canvasFormat = navigator.gpu.getPreferredCanvasFormat();// 给上下文配置 device 对象和ctx.configure({  device,  format: canvasFormat,});

navigator.gpu.getPreferredCanvasFormat() 会返回当前环境合适的像素格式的字符串标识,通常是 'bgra8unorm',表示用 8 位无符号整数来表示蓝色、绿色、红色和透明度四个分量。nk828资讯网——每日最新资讯28at.com

设置背景色

创建命令编码器 GPUCommandEncoder 实例,它用于编码需要提交给 GPU 的命令。nk828资讯网——每日最新资讯28at.com

const encoder = device.createCommandEncoder();

开启一个新的渲染通道(Render Pass),这里清空颜色缓冲区时填充了一个浅蓝色背景。nk828资讯网——每日最新资讯28at.com

和 WebGL 一样,使用 RGBA 的格式,每个分量为 0 到 1 的范围,比如 { r: 1, g: 0, b: 0, a: 1 } 表示红色,或者你可以用数组的形式 [1, 0, 0, 1]。nk828资讯网——每日最新资讯28at.com

const pass = encoder.beginRenderPass({  // 颜色附件,一个用于存储渲染输出颜色数据的纹理  colorAttachments: [    {      // 要渲染到的目标      view: ctx.getCurrentTexture().createView(),      // 渲染前清空颜色缓冲区      loadOp: 'clear',      // 清除颜色为浅蓝色,不设置会默认使用黑色      clearValue: { r: 0.6, g: 0.8, b: 0.9, a: 1 },      // 渲染结果会被保留在纹理中,后序好绘制到 canvas 上      storeOp: 'store',    },  ],});

我们先不绘制三角形,看看背景的渲染效果,为此我们提前执行下面代码:nk828资讯网——每日最新资讯28at.com

// 这里是绘制三角形的代码,之后会实现pass.end(); // 完成指令队列的记录const commandBuffer = encoder.finish(); // 结束编码device.queue.submit([commandBuffer]); // 提交给 GPU 命令队列

nk828资讯网——每日最新资讯28at.com

远峰蓝。nk828资讯网——每日最新资讯28at.com

创建缓冲区

先说说 WebGPU 的坐标系,它和 WebGL 一样,原点在画布中心,x 轴向右,y 轴向上,取值范围都是 -1 到 1。nk828资讯网——每日最新资讯28at.com

nk828资讯网——每日最新资讯28at.com

声明顶点数据。这些顶点为组成三角形的三个坐标。nk828资讯网——每日最新资讯28at.com

const vertices = new Float32Array([  -0.5, -0.5,  0.5, -0.5,  0.5, 0.5,]);

然后创建顶点缓冲区:nk828资讯网——每日最新资讯28at.com

const vertexBuffer = device.createBuffer({  // 标识,字符串随意写,报错时会通过它定位  label: 'Triangle Vertices',  // 缓冲区大小,这里是 24 字节。6 个 4 字节(即 32 位)的浮点数  size: vertices.byteLength,  // 标识缓冲区用途(1)用于顶点着色器(2)可以从 CPU 复制数据到缓冲区  usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,});

label 方便我们定位错误位置:nk828资讯网——每日最新资讯28at.com

nk828资讯网——每日最新资讯28at.com

接着是将顶点数据复制到缓冲区:nk828资讯网——每日最新资讯28at.com

device.queue.writeBuffer(vertexBuffer, /* bufferOffset */ 0, vertices);

参数 bufferOffset 表示缓冲区偏移多少字节数的位置写入数据。nk828资讯网——每日最新资讯28at.com

读取方式

设置缓冲区的读取方式。nk828资讯网——每日最新资讯28at.com

const vertexBufferLayout = {  // 每组读 8 个字节。一个坐标为两个浮点数(2 * 4字节)  arrayStride: 2 * 4,   attributes: [    {      // 指定数据格式,这样 WebGPU 才知道该如何解析,格式为 2 个 32位浮点数      format: 'float32x2',      offset: 0, // 从每组的第一个数字开始      shaderLocation: 0, // 顶点着色器中的位置    },  ],};

attributes 是一个数组,这里我们只有顶点要读,所以只有一个数组元素。如果引入了颜色值并和顶点放在一起,我们就要多声明一个数组元素,并将 offset 指定到颜色的位置。nk828资讯网——每日最新资讯28at.com

这个对象此时还没用到,后面设置渲染流水线时会用到。nk828资讯网——每日最新资讯28at.com

着色器

声明 WebGPU 的着色器,创建着色器模块(GPUShaderModule)。nk828资讯网——每日最新资讯28at.com

WebGPU 使用特有的 WGSL 着色器语言,顶点着色器和片元着色器可以写在一起的。nk828资讯网——每日最新资讯28at.com

// 创建着色器模块const vertexShaderModule = device.createShaderModule({  label: 'Vertex Shader',  code: `    @vertex    fn vertexMain(@location(0) pos: vec2f) -> @builtin(position) vec4f {      return vec4f(pos, 0, 1);    }    @fragment    fn fragmentMain() -> @location(0) vec4f {      return vec4f(1, 0, 0, 1);    }  `,});

顶点着色器函数。nk828资讯网——每日最新资讯28at.com

@vertex fn vertexMain(@location(0) pos: vec2f) -> @builtin(position) vec4f {  return vec4f(pos, 0, 1);}
  • @vertex:装饰器,表示顶点着色器主函数。
  • @location(0):缓冲区读取方式设置的 shaderLocation,这里拿到了两个浮点数。
  • vec2f:两个浮点数的向量,同理,vec4f 为 4 浮点数的向量。
  • -> @builtin(position):表示函数的返回值会被设置为内置的顶点位置变量。WebGPU 是利用函数的返回值配合修饰符的方式进行内部变量赋值的。

片元着色器。nk828资讯网——每日最新资讯28at.com

@fragmentfn fragmentMain() -> @location(0) vec4f {  return vec4f(1, 0, 0, 1); // 红色}
  • @fragment 表示片元着色器主函数。
  • -> @location(0) 表示将返回的颜色输出到位置为 0 的颜色附件上,简单来说,就是给对应点设置为对应颜色。

渲染流水线

创建渲染流水线,也就是把之前的设置组合起来,用哪个着色器的哪个函数作为入口、如何读取缓冲区等。nk828资讯网——每日最新资讯28at.com

const pipeline = device.createRenderPipeline({  label: 'pipeline', // 标识,定位错误用  layout: 'auto', // 自动流水线布局  vertex: {    module: vertexShaderModule, // 着色器模块    entryPoint: 'vertexMain', // 入口函数为 vertexMain    buffers: [vertexBufferLayout], // 读取缓冲区的方式  },  fragment: {    module: vertexShaderModule,    entryPoint: 'fragmentMain',    targets: [      {        format: canvasFormat, // 输出到 canvas 画布上      },    ],  },});

将渲染流水线设置到 pass 上。nk828资讯网——每日最新资讯28at.com

pass.setPipeline(pipeline);

将缓冲区绑定到管线的第一个顶点缓冲槽(slot)。nk828资讯网——每日最新资讯28at.com

pass.setVertexBuffer(0, vertexBuffer);

绘制图元,这里要设置绘制几组,一组是两个点,所以要处以 2。nk828资讯网——每日最新资讯28at.com

pass.draw(vertices.length / 2);

然后就是前面讲过的收尾代码。nk828资讯网——每日最新资讯28at.com

pass.end(); // 完成指令队列的记录const commandBuffer = encoder.finish(); // 结束编码device.queue.submit([commandBuffer]); // 提交给 GPU 命令队列

至此,一个三角形就画好了。nk828资讯网——每日最新资讯28at.com

绘制结果

nk828资讯网——每日最新资讯28at.com

完整代码

线上 demo 演示:nk828资讯网——每日最新资讯28at.com

https://codesandbox.io/s/lg4w27?file=/src/index.mjs。nk828资讯网——每日最新资讯28at.com

完整代码:nk828资讯网——每日最新资讯28at.com

const render = async () => {  const adapter = await navigator.gpu.requestAdapter();  const device = await adapter.requestDevice();  const canvas = document.querySelector('canvas');  const ctx = canvas.getContext('webgpu');  const canvasFormat = navigator.gpu.getPreferredCanvasFormat();  ctx.configure({    device,    format: canvasFormat,  });  const encoder = device.createCommandEncoder();  const pass = encoder.beginRenderPass({    colorAttachments: [      {        view: ctx.getCurrentTexture().createView(),        loadOp: 'clear',        clearValue: { r: 0.6, g: 0.8, b: 0.9, a: 1 },        storeOp: 'store',      },    ],  });  // 创建顶点数据  // prettier-ignore  const vertices = new Float32Array([    -0.5, -0.5,    0.5, -0.5,    0.5, 0.5,  ]);  // 缓冲区  const vertexBuffer = device.createBuffer({    // 标识,字符串随意写,报错时会通过它定位,    label: 'Triangle Vertices',    // 缓冲区大小,这里是 24 字节。6 个 4 字节(即 32 位)的浮点数    size: vertices.byteLength,    // 标识缓冲区用途(1)用于顶点着色器(2)可以从 CPU 复制数据到缓冲区    // eslint-disable-next-line no-undef    usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,  });  // 将顶点数据复制到缓冲区  device.queue.writeBuffer(vertexBuffer, /* bufferOffset */ 0, vertices);  // GPU 应该如何读取缓冲区中的数据  const vertexBufferLayout = {    arrayStride: 2 * 4, // 每一组的字节数,每组有两个数字(2 * 4字节)    attributes: [      {        format: 'float32x2', // 每个数字是32位浮点数        offset: 0, // 从每组的第一个数字开始        shaderLocation: 0, // 顶点着色器中的位置      },    ],  };  // 着色器用的是 WGSL 着色器语言  const vertexShaderModule = device.createShaderModule({    label: 'Vertex Shader',    code: `      @vertex      fn vertexMain(@location(0) pos: vec2f) -> @builtin(position) vec4f {        return vec4f(pos, 0, 1);      }      @fragment      fn fragmentMain() -> @location(0) vec4f {        return vec4f(1, 0, 0, 1);      }    `,  });  // 渲染流水线  const pipeline = device.createRenderPipeline({    label: 'pipeline',    layout: 'auto',    vertex: {      module: vertexShaderModule,      entryPoint: 'vertexMain',      buffers: [vertexBufferLayout],    },    fragment: {      module: vertexShaderModule,      entryPoint: 'fragmentMain',      targets: [        {          format: canvasFormat,        },      ],    },  });  pass.setPipeline(pipeline);  pass.setVertexBuffer(0, vertexBuffer);  pass.draw(vertices.length / 2);  pass.end();  const commandBuffer = encoder.finish();  device.queue.submit([commandBuffer]);};render();

结尾

本文讲解了如何用 WebGPU 绘制一个三角形。可以看到它和 WebGL 的逻辑有很多共同之处的,都要创建缓冲区、着色器、定义读取方式。nk828资讯网——每日最新资讯28at.com

本文链接://www.dmpip.com//www.dmpip.com/showinfo-26-16287-0.htmlWebGPU 入门:绘制一个三角形

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 掌握Spring事件监听器的内部逻辑与实现

下一篇: 转转Flutter实践之路

标签:
  • 热门焦点
  • 对标苹果的灵动岛 华为带来实况窗功能

    对标苹果的灵动岛 华为带来实况窗功能

    继苹果的灵动岛之后,华为也在今天正式推出了“实况窗”功能。据今天鸿蒙OS 4.0的现场演示显示,华为的实况窗可以更高效的展现出实时通知,比如锁屏上就能看到外卖、打车、银行
  • 7月安卓手机好评榜:三星S23Ultra好评率第一

    7月安卓手机好评榜:三星S23Ultra好评率第一

    性能榜和性价比榜之后,我们来看最后的安卓手机好评榜,数据来源安兔兔评测,收集时间2023年7月1日至7月31日,仅限国内市场。第一名:三星Galaxy S23 Ultra好评率:95.71%在即将迎来新
  • 太卷!Redmi MAX 100英寸电视便宜了:12999元买Redmi史上最大屏

    太卷!Redmi MAX 100英寸电视便宜了:12999元买Redmi史上最大屏

    8月5日消息,从小米商城了解到,Redmi MAX 100英寸巨屏电视日前迎来官方优惠,到手价12999元,比发布价便宜了7000元,在大屏电视市场开卷。据了解,Redmi MAX 100
  • 自动化在DevOps中的力量:简化软件开发和交付

    自动化在DevOps中的力量:简化软件开发和交付

    自动化在DevOps中扮演着重要角色,它提升了DevOps的效能。通过自动化工具和方法,DevOps团队可以实现以下目标:消除手动和重复性任务。简化流程。在整个软件开发生命周期中实现更
  • 使用AIGC工具提升安全工作效率

    使用AIGC工具提升安全工作效率

    在日常工作中,安全人员可能会涉及各种各样的安全任务,包括但不限于:开发某些安全工具的插件,满足自己特定的安全需求;自定义github搜索工具,快速查找所需的安全资料、漏洞poc、exp
  • 零售大模型“干中学”,攀爬数字化珠峰

    零售大模型“干中学”,攀爬数字化珠峰

    文/侯煜编辑/cc来源/华尔街科技眼对于绝大多数登山爱好者而言,攀爬珠穆朗玛峰可谓终极目标。攀登珠峰的商业路线有两条,一是尼泊尔境内的南坡路线,一是中国境内的北坡路线。相
  • 微博大门常打开,迎接海外画师漂洋东渡

    微博大门常打开,迎接海外画师漂洋东渡

    作者:互联网那些事&ldquo;起猛了,我能看得懂日语了&rdquo;。&ldquo;为什么日本人说话我能听懂?&rdquo;&ldquo;中文不像中文,日语不像日语,但是我竟然看懂了&rdquo;&hellip;&hell
  • OPPO Reno10 Pro英雄联盟定制礼盒公布:萨勒芬妮同款配色梦幻十足

    OPPO Reno10 Pro英雄联盟定制礼盒公布:萨勒芬妮同款配色梦幻十足

    5月24日,OPPO推出了全新的OPPO Reno 10系列,包含OPPO Reno10、OPPO Reno10 Pro和OPPO Reno10 Pro+三款新机,全系标配了超光影长焦镜头,是迄今为止拍照
  • 北京:科技教育体验基地开始登记

    北京:科技教育体验基地开始登记

      北京“科技馆之城”科技教育体验基地登记和认证工作日前启动。首批北京科技教育体验基地拟于2023年全国科普日期间挂牌,后续还将开展常态化登记。  北京科技教育体验基
Top
Baidu
map