本节我们来复原一个彩色的正方形,前提告知,本节的shaders和main的代码从结构上有调整,我会更加详细的描述每行的代码意思;

源代码下载地址:https://github.com/jack1232/webgpu07

一、首先需要你安装所有的软件包

安装完软件包,确保你的本地生成node_modules文件夹

npm install

二、创建你的index.html文件

1.<canvas>的"canvas-webgpu"你可以理解为调用webgpu内的canvas接口;

2.<script>是调用打包好对webgpu操作指令的脚本文件bundle.js文件;

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>WebGPU Step-by-Step 7</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head> <body>
<div>
<h1>Create Square using GPU Buffer</h1><br>
<canvas id="canvas-webgpu" width="640" height="480"></canvas>
</div>
<script src="main.bundle.js"></script>
</body>
</html>

二、创建你的helper.ts文件

前面说过,代码结构上有调整,是因为我们把原来写在main.ts文件里面的一些声明方法,现在在helper.ts进行了声明封装,根据源码作者的意思,把一些通用的webgpuAPI调用接口声明出这样独立的一个外部方法文件,我们在main文件中进行直接调用函数方法即可;

我使用了三种颜色区分来说明每个代码块的用法,;

■代表:自定义创建一个CreateGPUBuffer函数,这个函数内包含创建device\data\usageFlage分别来应用webgpuAPI接口来实现buffer缓冲区启用GPUBuffer;

■代表:在此自定义对象函数,里面的定义好了大多通用的webgpu方法< device, canvas, format, context>,不需要你在声明方法,只接调用即可

■代表:这是一个检查函数,判定你的浏览器是否支持webgpu;

其中,我有个疑问还未解决:在helper.ts中,创建的CreateGPUBuffer缓冲区对象,其中输入变量usageFlag的.VERTEX和.COPY_DST代表什么意思呢?
usageFlag:GPUBufferUsageFlags = GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST

代码如下:

 1 export const CreateGPUBuffer = (device:GPUDevice, data:Float32Array,   //自定义创建一个CreateGPUBuffer函数,这个函数内包含创建device\data\usageFlage分别来应用webgpuAPI接口来实现
2 usageFlag:GPUBufferUsageFlags = GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST) => { //device:设备启用;data:数据类型;usageFlag:缓冲区资源使用
3 const buffer = device.createBuffer({ //使用device.createBuffer来产生GPUBuffer
4 size: data.byteLength, //size:分配的长度,以字节为单位;byteLength是js的一个属性,用来获取数组字节长度
5 usage: usageFlag, //对应上面usageFlag
6 mappedAtCreation: true //true表示这个API定义了GPU缓冲区可以被CPU拥有使用,可以通过typescript读取或者写入
7 });
8 new Float32Array(buffer.getMappedRange()).set(data); //一但程序处于map状态,我们的数据便会把data写入buffer
9 buffer.unmap(); //unmap是GPU使用的状态,map是CPU使用的状态
10 return buffer; //这里的buffer是返回unmap状态的buffer
11 }
12
13 export const InitGPU = async () => { //在此自定义对象函数,里面的定义好了大多通用的webgpu方法< device, canvas, format, context>,不需要你在声明方法,直接调用即可
14 const checkgpu = CheckWebGPU();
15 if(checkgpu.includes('Your current browser does not support WebGPU!')){
16 console.log(checkgpu);
17 throw('Your current browser does not support WebGPU!');
18 }
19 const canvas = document.getElementById('canvas-webgpu') as HTMLCanvasElement;
20 const adapter = await navigator.gpu?.requestAdapter();
21 const device = await adapter?.requestDevice() as GPUDevice;
22 const context = canvas.getContext('webgpu') as unknown as GPUCanvasContext;
23
24 const devicePixelRatio = window.devicePixelRatio || 1;
25 const size = [
26 canvas.clientWidth * devicePixelRatio,
27 canvas.clientHeight * devicePixelRatio,
28 ];
29 const format = context.getPreferredFormat(adapter!);
30
31 context.configure({
32 device: device,
33 format: format,
34 size: size
35 });
36 return{ device, canvas, format, context };
37 };
38
39 export const CheckWebGPU = () => { //这是一个检查函数,判定你的浏览器是否支持webgpu;
40 let result = 'Great, your current browser supports WebGPU!';
41 if (!navigator.gpu) {
42 result = `Your current browser does not support WebGPU! Make sure you are on a system
43 with WebGPU enabled. Currently, SPIR-WebGPU is only supported in
44 <a href="https://www.google.com/chrome/canary/">Chrome canary</a>
45 with the flag "enable-unsafe-webgpu" enabled. See the
46 <a href="https://github.com/gpuweb/gpuweb/wiki/Implementation-Status">
47 Implementation Status</a> page for more details.
48 `;
49 }
50 return result;
51 }

三、开始编写你的main.ts文件

需要你注意的是,原先我们把创建顶点和颜色的代码部分放到了shaders下实现,现在把创建顶点和颜色的数据放在main下实现,把顶点坐标和颜色数据放在缓冲区写,是因为main.ts是typescript写成的,有代码提示,相比文本的着色器,调试起来更方便。

代码如下:

 1 import { InitGPU, CreateGPUBuffer } from './helper';  //调用InitGPU(对GPU的权限读取等操作指令的封装方法接口) CreateGPUBuffer(对GPU缓冲区的设定封装)
2 import { Shaders } from './shaders'; //调用着色器
3
4 const CreateSquare = async () => { //声明一个常量块,并异步映射给定范围
5 const gpu = await InitGPU(); //第一个范围,声明gpu常量,给定范围是InitGPU接口
6 const device = gpu.device; //第二个范围,声明device常量,给定范围是gpu中的.device
7
8 const vertexData = new Float32Array([ //开始创建顶点具体数据,逆时针给定三角形顶点形成一个正方形,并初始化这个变量数组类型Float32Array
9 -0.5, -0.5, // vertex a
10 0.5, -0.5, // vertex b
11 -0.5, 0.5, // vertex d
12 -0.5, 0.5, // vertex d
13 0.5, -0.5, // vertex b
14 0.5, 0.5, // vertex c
15 ]);
16
17 const colorData = new Float32Array([ //开始给定颜色赋值,同样按照逆时针方向给定颜色,并初始化数组类型(这里的数组没有浮点小数,是因为typescript不区分1.0和1的区别;反之着色器代码要严格区分小数)
18 1, 0, 0, // vertex a: red
19 0, 1, 0, // vertex b: green
20 1, 1, 0, // vertex d: yellow
21 1, 1, 0, // vertex d: yellow
22 0, 1, 0, // vertex b: green
23 0, 0, 1 // vertex c: blue
24 ]);
25
26 const vertexBuffer = CreateGPUBuffer(device, vertexData); //创建对象,引用helper.ts中的CreateBuffer方法赋予创建的vertexBuffer数据vertexData
27 const colorBuffer = CreateGPUBuffer(device, colorData) //创建对象,引用helper.ts中的CreateBuffer方法赋予创建的colorBuffer数据colorData
28
29 const shader = Shaders(); //创建Shader变量引入着色器
30 const pipeline = device.createRenderPipeline({ //产生渲染管线,进行vertex和fragment设定
31 vertex: { //vertex描述pipeline入口着色器及输入的缓冲区布局
32 module: device.createShaderModule({ //创建着色器模块
33 code: shader.vertex //调用着色器代码部分的vertex方法
34 }),
35 entryPoint: "main", //入口位置
36 buffers:[ //buffers数组,具体定义前面创建的顶点和颜色
37 { //这是具体描述你前面创建的vertexData的顶点数据
38 // 描述vertexDara
39 arrayStride: 8, //arrayStride是一个api函数,表示该数组的步幅(以字节为单位)为什么是8?每一个顶点有两个步幅(理解为字节或坐标),2(x,y)x4(四个顶点)=8
40 attributes: [{ //结构成员,是一个api函数
41 shaderLocation: 0, //shaderLocation是一个API,它表示每个属性由数字location绑定,这里暂时我还不太理解为什么定义为0,目前只要记住vertexData的location定义为0
42 format: "float32x2", //定义顶点格式 ,因为有2个元素,所有float32x2
43 offset: 0
44 }]
45 },
46 {
47 //描述colorData
48 arrayStride: 12, //为什么是12?3(3个坐标)x4(四个顶点)=12
49 attributes: [{
50 shaderLocation: 1, //colorData的location定义为1
51 format: "float32x3",
52 offset: 0
53 }]
54 }
55 ]
56 },
57 fragment: { //fragment 描述 pipeline 的片段着色器入口点及其输出颜色
58 module: device.createShaderModule({
59 code: shader.fragment
60 }),
61 entryPoint: "main",
62 targets: [
63 {
64 format: gpu.format as GPUTextureFormat
65 }
66 ]
67 },
68 primitive:{
69 topology: "triangle-list",
70 }
71 });
72
73 const commandEncoder = device.createCommandEncoder();
74 const textureView = gpu.context.getCurrentTexture().createView();
75 const renderPass = commandEncoder.beginRenderPass({
76 colorAttachments: [{
77 view: textureView,
78 loadValue: { r: 0.5, g: 0.5, b: 0.8, a: 1.0 }, //background color
79 storeOp: 'store'
80 }]
81 });
82 renderPass.setPipeline(pipeline); //绑定管线到渲染通道上
83 renderPass.setVertexBuffer(0, vertexBuffer); //把 vertexBuffer内的顶点数据绑定到渲染通道上,<<这里的插槽理解还没有解决>>
84 renderPass.setVertexBuffer(1, colorBuffer);
85 renderPass.draw(6); //两个三角形,六个顶点,需要进行draw绘制
86 renderPass.endPass();
87
88 device.queue.submit([commandEncoder.finish()]); //结束device的渲染
89 }
90
91 CreateSquare();

从第8行开始创建的顶点数据,如下图进行理解,需要注意顶点和着色全部按照逆时针进行数组排列

在main文件中我有两个疑问没有解答,我把我在社区发问的地址公布出来,以便一些读者或者社区回复可以看到:

1.关于setVertexBuffer()插槽的理解(已解决)

2.顶点格式下的offset: 怎么理解?

四、接下来就是编写你的shaders文件

可以看到着色器代码简化了很多,是因为可以直接使用缓冲区里的vertexData顶点坐标和colorData颜色数据进行联系,联系方式就是location。

export const Shaders = () => {
const vertex = `
struct Output {
[[builtin(position)]] Position : vec4<f32>;
[[location(0)]] vColor : vec4<f32>;
};
[[stage(vertex)]]
fn main([[location(0)]] pos: vec4<f32>, [[location(1)]] color: vec4<f32>) -> Output {
var output: Output;
output.Position = pos;
output.vColor = color;
return output;
}`; const fragment = `
[[stage(fragment)]]
fn main([[location(0)]] vColor: vec4<f32>) -> [[location(0)]] vec4<f32> {
return vColor;
}`; return {
vertex,
fragment
};
}

五、捆绑文件,启用浏览器

npm run prod

 学习资料:

哔哩哔哩视频教程:https://www.bilibili.com/video/BV1M64y1r7zL?spm_id_from=333.999.0.0

WebGPU文档:https://www.orillusion.com/zh/webgpu.html#intro

WGSL文档:https://www.orillusion.com/zh/wgsl.html#intro

源码地址:https://github.com/jack1232/webgpu07

WebGPU图形编程(4):构建一个彩色的正方形<学习引自徐博士教程>的更多相关文章

  1. WebGPU图形编程(2):构建一个单色的三角形<学习引自徐博士教程>

    非常兴奋,我坚持了下来,开始更新我的第二篇博客,还是关于WebGPU的,我在学习过程中,对这项技术非常感兴趣,即使它非常抽象,难以理解,因为我看到未来Web3D的发展,WebGPU会成为主流技术,学习 ...

  2. WebGPU图形编程(1):建立开发环境 <学习引自徐博士教程>

    首先感谢徐博士提供的视频教程,我的博客记录也是学习徐博士进行的自我总结,老徐B站学习视频链接网址:WebGPU图形编程 - 免费视频教程(1):建立开发环境_哔哩哔哩_bilibili 创建之前你需要 ...

  3. WebGPU图形编程(3):构建三角形图元<学习引自徐博士教程>

    一.首先修改你的index.html文件 请注意主要在html页面修改添加的是需要加选择项:"triangle-list"和"triangle-strip",如 ...

  4. [网络编程] 自己构建一个cgi.FieldStorage()的对象

    问题描述: 通常cgi.FieldStorage()返回一个类似于Python字典的对象. 在cgi框架中必须通过浏览器发送表单过来才能接受消息 那么我该怎么进行本地调试呢? 或者说在没有搭建好一整套 ...

  5. 学废了系列 - WebGIS vs WebGL图形编程

    目前工作中有不少涉及到地图的项目,我参加了几次技术评审,前端伙伴们在 WebGIS 方面的知识储备稍有不足,这次分享的主要目的是科普一些在前端领域比较常用的 WebGIS 知识.另外,我之前的工作中积 ...

  6. OpenGL基础图形编程

    一.OpenGL与3D图形世界1.1.OpenGL使人们进入三维图形世界 我们生活在一个充满三维物体的三维世界中,为了使计算机能精确地再现这些物体,我们必须能在三维空间描绘这些物体.我们又生活在一个充 ...

  7. 【转】OpenGL基础图形编程(一)

    原文:http://blog.chinaunix.net/uid-20638550-id-1909183.html  分类: 一.OpenGL与3D图形世界 1.1.OpenGL使人们进入三维图形世界 ...

  8. 如何用 Swift 语言构建一个自定控件

    (via:破船之家,原文:How To Make a Custom Control in Swift)   用户界面控件是所有应用程序重要的组成部分之一.它们以图形组件的方式呈现给用户,用户可以通过它 ...

  9. 现代3D图形编程学习-你好,三角形(译)

    你好,三角形 传统的入门教程在介绍编程语言的时候,通常从"Hello,World!"的程序开始.这样的程序拥有最简单的能够直接输出"Hello, World!" ...

随机推荐

  1. 使用 juqery.media.js 实现 pdf 预览

    作用:可以实现在指定的位置预览PDF 缺点: (1)在iPad上只能预览一页PDF.(问题是iPad会将PDF转为img呈现,试了将img宽度设置为100%方法但并不好使) (2)在安卓上不能预览,依 ...

  2. 解决Centos7误删Python问题

    1.前言 昨天安装Python3.6的时候.不小心把原来的Python全删了.不知道咋办了.后面参考一篇博客.重新安装了一下.相关的包全回来了.所以还是得注意root模式下.慎用rm -rf命令.(笑 ...

  3. JAVA生成订单编号工具类

    JAVA根据时间戳和随机数方式生成订单编号工具类 OrderUtils.java package com.util; import java.text.DateFormat; import java. ...

  4. Qt5使用QSqlQuery读写sqlite3数据库

    概述 本文将介绍使用 Qt5使用QSqlQuery读写sqlite3. 设计初衷: 项目需要使用配置文件,配置文件使用的是sqlite3 , 这是V1.0.0, 后期增加其他功能. 需要C++11支持 ...

  5. soui(1)之一个半透明的窗口

    一个样式 xml源码 <SOUI name="mainWindow" title="@string/title" bigIcon="ICON_L ...

  6. 【LeetCode】98. Validate Binary Search Tree 解题报告(Python & C++ & Java)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 BST的中序遍历是有序的 日期 题目地址:ht ...

  7. 【LeetCode】88. Merge Sorted Array 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 新建数组 日期 题目地址:https://leetc ...

  8. 精通 MySQL 索引

    索引概念: 概念:索引是提高mysql查询效率的数据结构.总的一句话概括就是索引是一种提高查询效率的数据结构. 数据库查询是数据库的最主要功能之一.设计者们都希望查询数据的速度能尽可能的快,因此数据库 ...

  9. matplotlib 高阶之path tutorial

    目录 Bezier example 用path来画柱状图 随便玩玩 import matplotlib.pyplot as plt from matplotlib.path import Path i ...

  10. ADADELTA: AN ADAPTIVE LEARNING RATE METHOD

    目录 引 主要内容 算法 ADADELTA 代码 引 这篇论文比较短,先看了这篇,本来应该先把ADAGRAD看了的.普通的基于梯度下降的方法,普遍依赖于步长,起始点的选择,所以,受ADAGRAD的启发 ...