<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>http://www.webgl3d.cn/</title>
</head>
<body>
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
if (navigator.gpu) {
console.log('你的浏览器支持WebGPU。');
} else {
console.log('你的浏览器不支持WebGPU,请更换新版本浏览器。');
}
const adapter = await navigator.gpu.requestAdapter()
const device = await adapter.requestDevice()
const canvas = document.getElementById("webgpu")
const context = canvas.getContext("webgpu")
const format = navigator.gpu.getPreferredCanvasFormat();//获取浏览器默认的颜色格式
context.configure({
device: device,
format: format,//颜色格式
});
import * as glmatrix from './dist/esm/index.js'
console.log(glmatrix.mat4)
const vertexArray = new Float32Array([
// 三角形三个顶点坐标的x、y、z值
0.0, 0.0, 0.0,//顶点1坐标
0.5, 0.0, 0.0,//顶点2坐标
0.0, 0.5, 0.0,//顶点3坐标
0.0, 0.5, 0.0,
0.5, 0.5, 0.0,
0.5, 0.0, 0.0
]);
const vertexBuffer = device.createBuffer({
size: vertexArray.byteLength,//顶点数据的字节长度
//usage设置该缓冲区的用途(作为顶点缓冲区|可以写入顶点数据)
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
//把vertexArray里面的顶点数据写入到vertexBuffer对应的GPU显存缓冲区中
//参数2的0表示从vertexArray的数据开头读取数据。
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);
const sarray = new Float32Array([0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0])
const sBuffer = device.createBuffer({
size: sarray.byteLength,//顶点数据的字节长度
//usage设置该缓冲区的用途(作为顶点缓冲区|可以写入顶点数据)
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(sBuffer, 0, sarray);
const tarray = new Float32Array([1.0,0.0,0.0,0.0, 0.0,1.0,0.0,0.0, 0.0,0.0,1.0,0.0, -1.0,-1.0,0.0,1.0])
const tBuffer = device.createBuffer({
size: tarray.byteLength,//顶点数据的字节长度
//usage设置该缓冲区的用途(作为顶点缓冲区|可以写入顶点数据)
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(tBuffer, 0, tarray);
const carray = new Float32Array([0, 1.0, 0.0, ])
const cBuffer = device.createBuffer({
size: carray.byteLength,//顶点数据的字节长度
//usage设置该缓冲区的用途(作为顶点缓冲区|可以写入顶点数据)
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(cBuffer, 0, carray);
// 引入顶点着色器vertex代码对应字符串
import { vertex, fragment } from './shader.js'
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {
// 顶点着色器
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [// 顶点所有的缓冲区模块设置
{//其中一个顶点缓冲区设置
arrayStride: 3 * 4,//一个顶点数据占用的字节长度,该缓冲区一个顶点包含xyz三个分量,每个数字是4字节浮点数,3*4字节长度
attributes: [{// 顶点缓冲区属性
shaderLocation: 0,//GPU显存上顶点缓冲区标记存储位置
format: "float32x3",//格式:loat32x3表示一个顶点数据包含3个32位浮点数
offset: 0//arrayStride表示每组顶点数据间隔字节数,offset表示读取改组的偏差字节数,没特殊需要一般设置0
}]
}
]
},
fragment: {
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format//和WebGPU上下文配置的颜色格式保持一致
}]
},
primitive: {
topology: "triangle-list",//三角形绘制顶点数据
}
});
// 设置uniform数据的绑定组
const bindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),//绑定组,标记为0
// 一个组里面可以包含多个uniform数据
entries: [//每个元素可以用来设置一个uniform数据
{
binding: 0,//标记组里面的uniform数据
resource: { buffer: sBuffer }
},
{
binding: 1,//标记组里面的uniform数据
resource: { buffer: tBuffer }
}
,
{
binding: 2,//标记组里面的uniform数据
resource: { buffer: cBuffer }
}
]
});
// 创建GPU命令编码器对象
const commandEncoder = device.createCommandEncoder();
const renderPass = commandEncoder.beginRenderPass({
// 给渲染通道指定颜色缓冲区,配置指定的缓冲区
colorAttachments: [{
// 指向用于Canvas画布的纹理视图对象(Canvas对应的颜色缓冲区)
// 该渲染通道renderPass输出的像素数据会存储到Canvas画布对应的颜色缓冲区(纹理视图对象)
view: context.getCurrentTexture().createView(),
storeOp: 'store',//像素数据写入颜色缓冲区
loadOp: 'clear',
clearValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 }, //背景颜色
}]
});
// 设置该渲染通道控制渲染管线
renderPass.setPipeline(pipeline);
//顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
renderPass.setBindGroup( 0, bindGroup );
// 绘制命令.draw()绘制顶点数据
renderPass.draw(6);
// 渲染通道结束命令.end()
renderPass.end();
// 命令编码器.finish()创建命令缓冲区(生成GPU指令存入缓冲区)
const commandBuffer = commandEncoder.finish();
// 命令编码器缓冲区中命令传入GPU设备对象的命令队列.queue
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
-----------
shader.js
------------
//@group(0)的参数0对应webgpu代码.getBindGroupLayout(0)参数0
//@binding(0)的参数对应webgpu代码.binding的值,保持一致,比如都是0
// 顶点着色器代码
const vertex = `
@group(0) @binding(0) var<uniform> S:mat4x4<f32>;
@group(0) @binding(1) var<uniform> T:mat4x4<f32>;
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
var poss= vec4<f32>(pos,1.0);
poss.x+=-0.2;
poss.y+=-0.3;
return S*T*poss;
}
`
const vertex2 = `
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
var poss= vec4<f32>(pos,1.0);
poss.x+=-0.2;
poss.y+=-0.3;
//return poss;
// 创建一个缩放矩阵(沿着x、y分别缩放0.5倍)
//0.5 0 0 0
//0 0.5 0 0
//0 0 1 0
//0 0 0 1
// 矩阵元素一列一列输入mat4x4<f32>()
var S = mat4x4<f32>(0.5,0.0,0.0,0.0, 0.0,0.5,0.0,0.0, 0.0,0.0,1.0,0.0, 0.0,0.0,0.0,1.0);
//return S*poss;
// 创建一个平移矩阵(沿着x、y轴分别平移-1、-1)
//1 0 0 -1
//0 1 0 -1
//0 0 1 0
//0 0 0 1
// 矩阵元素一列一列输入mat4x4<f32>()
var T = mat4x4<f32>(1.0,0.0,0.0,0.0, 0.0,1.0,0.0,0.0, 0.0,0.0,1.0,0.0, -1.0,-1.0,0.0,1.0);
///return T * vec4<f32>(pos,1.0);//平移矩阵对顶点平移变换
return S* T * vec4<f32>(pos,1.0);//平移矩阵对顶点平移变换
}
`
// 片元着色器代码
const fragment =`
@group(0) @binding(2) var<uniform> C:vec3<f32>;
@fragment
fn main() -> @location(0) vec4<f32> {
//return vec4<f32>(1.0, 0.0, 0.0, 1.0);//片元设置为红色
return vec4<f32>(C, 1.0);//片元设置为红色
}
`
export { vertex, fragment }