WebGPU图形编程(4):构建一个彩色的正方形<学习引自徐博士教程>
本节我们来复原一个彩色的正方形,前提告知,本节的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()插槽的理解(已解决)
四、接下来就是编写你的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):构建一个彩色的正方形<学习引自徐博士教程>的更多相关文章
- WebGPU图形编程(2):构建一个单色的三角形<学习引自徐博士教程>
非常兴奋,我坚持了下来,开始更新我的第二篇博客,还是关于WebGPU的,我在学习过程中,对这项技术非常感兴趣,即使它非常抽象,难以理解,因为我看到未来Web3D的发展,WebGPU会成为主流技术,学习 ...
- WebGPU图形编程(1):建立开发环境 <学习引自徐博士教程>
首先感谢徐博士提供的视频教程,我的博客记录也是学习徐博士进行的自我总结,老徐B站学习视频链接网址:WebGPU图形编程 - 免费视频教程(1):建立开发环境_哔哩哔哩_bilibili 创建之前你需要 ...
- WebGPU图形编程(3):构建三角形图元<学习引自徐博士教程>
一.首先修改你的index.html文件 请注意主要在html页面修改添加的是需要加选择项:"triangle-list"和"triangle-strip",如 ...
- [网络编程] 自己构建一个cgi.FieldStorage()的对象
问题描述: 通常cgi.FieldStorage()返回一个类似于Python字典的对象. 在cgi框架中必须通过浏览器发送表单过来才能接受消息 那么我该怎么进行本地调试呢? 或者说在没有搭建好一整套 ...
- 学废了系列 - WebGIS vs WebGL图形编程
目前工作中有不少涉及到地图的项目,我参加了几次技术评审,前端伙伴们在 WebGIS 方面的知识储备稍有不足,这次分享的主要目的是科普一些在前端领域比较常用的 WebGIS 知识.另外,我之前的工作中积 ...
- OpenGL基础图形编程
一.OpenGL与3D图形世界1.1.OpenGL使人们进入三维图形世界 我们生活在一个充满三维物体的三维世界中,为了使计算机能精确地再现这些物体,我们必须能在三维空间描绘这些物体.我们又生活在一个充 ...
- 【转】OpenGL基础图形编程(一)
原文:http://blog.chinaunix.net/uid-20638550-id-1909183.html 分类: 一.OpenGL与3D图形世界 1.1.OpenGL使人们进入三维图形世界 ...
- 如何用 Swift 语言构建一个自定控件
(via:破船之家,原文:How To Make a Custom Control in Swift) 用户界面控件是所有应用程序重要的组成部分之一.它们以图形组件的方式呈现给用户,用户可以通过它 ...
- 现代3D图形编程学习-你好,三角形(译)
你好,三角形 传统的入门教程在介绍编程语言的时候,通常从"Hello,World!"的程序开始.这样的程序拥有最简单的能够直接输出"Hello, World!" ...
随机推荐
- 【LeetCode】66. Plus One 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 数九 采用进位 日期 [LeetCode] 题目地址 ...
- hdu-5587 Array(递归)
Array Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Sub ...
- codeforces 624C Graph and String
C. Graph and String time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- Back to Underworld(lightoj 1009)
1009 - Back to Underworld PDF (English) Statistics Forum Time Limit: 4 second(s) Memory Limit: 32 ...
- fastapi(一)
废话不多说,直接上代码. 目录结构, 由于我也是刚开始学这个框架,只是了解了怎么注册蓝图,JWT的集成,数据库的集成,想了解更多,自行打开官方文档去详细阅读.fastapi官网文档链接 创建一个mai ...
- 第四个知识点 P类复杂问题
第四个知识点 P类复杂问题 原文地址:http://bristolcrypto.blogspot.com/2014/10/52-things-number-4-complexity-class-p.h ...
- 自动化集成:Docker容器入门简介
前言:该系列文章,围绕持续集成:Jenkins+Docker+K8S相关组件,实现自动化管理源码编译.打包.镜像构建.部署等操作:本篇文章主要描述Docker基础用法. 一.Docker简介 1.基础 ...
- Adaptive gradient descent without descent
目录 概 主要内容 算法1 AdGD 定理1 ADGD-L 算法2 定理2 算法3 ADGD-accel 算法4 Adaptive SGD 定理4 代码 Malitsky Y, Mishchenko ...
- Capstone通用 USB Type-C音视频拓展坞转换芯片
专业解决视频接口技术Capstone科技在2021年新推出四款低功耗单芯片USB Type-C音视频格式转换器方案──CS5266.CS5267.CS5268与CS5269.将为各种显示屏.外部显示设 ...
- 编写Java程序,模拟文件操作过程中的异常处理
返回本章节 返回作业目录 需求说明: 从控制中输入计算机磁盘中后缀名为".txt"的文件的完整物理路径. 如果该文件存在,则在控制台输出友好提示信息,告知用户该文件存在,如果文件不 ...