<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>てst</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
//chrome setting:
//"C:\Program Files\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="D:\angular\webgpu\n" --disable-site-isolation-trials
//
//1,增加一个uniform buffer object(简称为ubo),
//用于传输“model矩阵 乘以 view矩阵 乘以 projection矩阵”的结果矩阵(简称为mvp矩阵),并在每帧被更新
//2.设置顶点
//3.开启面剔除
//4.开启深度测试
// 配置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,
});
const cubeVertexArray2 = new Float32Array([
// float4 position, float4 color, float2 uv,
1, -1, 1, 1, 1, 0, 1, 1, 1, 1,
-1, -1, 1, 1, 0, 0, 1, 1, 0, 1,
-1, -1, -1, 1, 0, 0, 0, 1, 0, 0,
1, -1, -1, 1, 1, 0, 0, 1, 1, 0,
1, -1, 1, 1, 1, 0, 1, 1, 1, 1,
-1, -1, -1, 1, 0, 0, 0, 1, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, -1, 1, 1, 1, 0, 1, 1, 0, 1,
1, -1, -1, 1, 1, 0, 0, 1, 0, 0,
1, 1, -1, 1, 1, 1, 0, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, -1, -1, 1, 1, 0, 0, 1, 0, 0,
-1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
1, 1, -1, 1, 1, 1, 0, 1, 0, 0,
-1, 1, -1, 1, 0, 1, 0, 1, 1, 0,
-1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
1, 1, -1, 1, 1, 1, 0, 1, 0, 0,
-1, -1, 1, 1, 0, 0, 1, 1, 1, 1,
-1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
-1, 1, -1, 1, 0, 1, 0, 1, 0, 0,
-1, -1, -1, 1, 0, 0, 0, 1, 1, 0,
-1, -1, 1, 1, 0, 0, 1, 1, 1, 1,
-1, 1, -1, 1, 0, 1, 0, 1, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
-1, -1, 1, 1, 0, 0, 1, 1, 0, 0,
-1, -1, 1, 1, 0, 0, 1, 1, 0, 0,
1, -1, 1, 1, 1, 0, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, -1, -1, 1, 1, 0, 0, 1, 1, 1,
-1, -1, -1, 1, 0, 0, 0, 1, 0, 1,
-1, 1, -1, 1, 0, 1, 0, 1, 0, 0,
1, 1, -1, 1, 1, 1, 0, 1, 1, 0,
1, -1, -1, 1, 1, 0, 0, 1, 1, 1,
-1, 1, -1, 1, 0, 1, 0, 1, 0, 0,
]);
//-------设置顶点--------------------------
//引入gl-matrix.js库
import * as glMatrix from './dist/esm/index.js';
// 定点缓冲区
const vertexBuffer = device.createBuffer({
size: cubeVertexArray2.byteLength, //顶点数据的字节长度
//usage设置该缓冲区的用途(作为顶点缓冲区|可以写入顶点数据)
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
// 将顶点信息写入缓冲器
device.queue.writeBuffer(vertexBuffer, 0, cubeVertexArray2);
//------------wsgl代码-------------------
const module = device.createShaderModule({
label: 'triangle shaders with uniforms',
code: `
struct Uniforms {
modelViewProjectionMatrix : mat4x4f//这里不能用分号
};
@group(0) @binding(0) var<uniform> uniforms : Uniforms;
struct VertexOutput {
@builtin(position) Position : vec4f,
@location(0) fragUV : vec2f,
@location(1) fragPosition: vec4f
};
@vertex
fn vs(@location(0) position : vec4f,@location(1) uv : vec2f) -> VertexOutput {
var output : VertexOutput;
output.Position = uniforms.modelViewProjectionMatrix * position;
output.fragUV = uv;
output.fragPosition = 0.5 * (position + vec4f(1.0, 1.0, 1.0, 1.0));
return output;
}
@fragment
fn fs(@location(0) fragUV: vec2<f32>,@location(1) fragPosition: vec4<f32>) -> @location(0) vec4<f32> {
return fragPosition;
}
`,
});
let cubePositionOffset=0;
let cubeUVOffset=4*8;
let cubeVertexSize=4*10;
const pipeline = device.createRenderPipeline({
layout: "auto",
vertex: {
module: module ,
entryPoint: 'vs',
buffers: [ // 为顶点着色器配置Buffer
{
arrayStride: cubeVertexSize,
attributes: [
{
// position
shaderLocation: 0,
offset: cubePositionOffset,
format: 'float32x4',
},
{
// uv
shaderLocation: 1,
offset: cubeUVOffset,
format: 'float32x2',
},
],
},
],
},
fragment: {
module: module ,
entryPoint: 'fs',
targets: [
{
format: format,
},
],
},
primitive: {
topology: 'triangle-list',
// Backface culling since the cube is solid piece of geometry.
// Faces pointing away from the camera will be occluded by faces
// pointing toward the camera.
//3.开启背面面剔除
cullMode: 'back',
},
//multisample: {
// count: 4
//},
// Enable depth testing so that the fragment closest to the camera
// is rendered in front.
//4.开启深度测试
depthStencil: {
depthWriteEnabled: true,
depthCompare: 'less',
format: 'depth24plus',
},
});
const uniformBufferSize = 4 * 16; // 4x4 matrix
const uniformBuffer = device.createBuffer({
size: uniformBufferSize,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});
const uniformBindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{
binding: 0,
resource: {
buffer: uniformBuffer,
},
},
],
});
const depthTexture = device.createTexture({
size: {
width: canvas.width,
height: canvas.height,
},
format: "depth24plus",
//sampleCount: 4,
usage: GPUTextureUsage.RENDER_ATTACHMENT
});
const renderPassDescriptor = {
colorAttachments: [
{
// view: context.getCurrentTexture().createView(), // Assigned later
loadOp: 'clear',
loadValue: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },
storeOp: 'store',
},
],
depthStencilAttachment: {
view: depthTexture.createView(),
depthStoreOp: 'store',
depthClearValue: 1.0,
depthLoadOp: "clear",
depthLoadValue: 1.0,
// depthStoreOp: 'store',
// stencilLoadValue: 0,
//stencilStoreOp: 'store',
},
};
//固定相机,透视投影
const aspect = Math.abs(canvas.width / canvas.height);
let projectionMatrix = glMatrix.mat4.create();
glMatrix.mat4.perspective(projectionMatrix, (2 * Math.PI) / 5, aspect, 1, 100.0);
//计算mvp矩阵
function getTransformationMatrix() {
//顺序:平移--》旋转--》缩放
let viewMatrix = glMatrix.mat4.create();
glMatrix.mat4.translate(viewMatrix, viewMatrix, glMatrix.vec3.fromValues(0, 0, -5));
let now = Date.now() / 1000;
glMatrix.mat4.rotate(viewMatrix, viewMatrix, 1, glMatrix.vec3.fromValues(Math.sin(now), Math.cos(now), 0));
let modelViewProjectionMatrix = glMatrix.mat4.create();
//顺序:透视投影 x 旋转矩阵
glMatrix.mat4.multiply(modelViewProjectionMatrix, projectionMatrix, viewMatrix);
return modelViewProjectionMatrix;
}
//------------------
//==============================
// return mvp matrix from given aspect, position, rotation, scale
/*
function getMvpMatrix(
aspect: number,
position: {x:number, y:number, z:number},
rotation: {x:number, y:number, z:number},
scale: {x:number, y:number, z:number}
){
*/
const center = glMatrix.vec3.fromValues(0,0,0)
const up = glMatrix.vec3.fromValues(0,1,0)
// default state
// let aspect = size.width / size.height
/*
let position;
position.x=0;
position.y=0
position.z= -5
let scale;
scale.x=1
scale.y=1
scale.z=1
let rotation;
rotation.x= 0
rotation.y= 0
rotation.z= 0
*/
function getMvpMatrix(
aspect,
position,
rotation ,
scale
){
// get modelView Matrix
const modelViewMatrix = getModelViewMatrix(position, rotation, scale)
// get projection Matrix
const projectionMatrix = getProjectionMatrix(aspect,60 / 180 * Math.PI,0.1,100.0,{x:0, y:0, z:0})
// get mvp matrix
const mvpMatrix = glMatrix.mat4.create()
glMatrix.mat4.multiply(mvpMatrix, projectionMatrix, modelViewMatrix)
// return matrix as Float32Array
return mvpMatrix;// as Float32Array
}
// return modelView matrix from given position, rotation, scale
/*
function getModelViewMatrix(
position = {x:0, y:0, z:0},
rotation = {x:0, y:0, z:0},
scale = {x:1, y:1, z:1}
){
*/
function getModelViewMatrix(
position ,
rotation,
scale
){
// get modelView Matrix
const modelViewMatrix = glMatrix.mat4.create()
// translate position
glMatrix.mat4.translate(modelViewMatrix, modelViewMatrix, glMatrix.vec3.fromValues(position.x, position.y, position.z))
// rotate
glMatrix.mat4.rotateX(modelViewMatrix, modelViewMatrix, rotation.x)
glMatrix.mat4.rotateY(modelViewMatrix, modelViewMatrix, rotation.y)
glMatrix.mat4.rotateZ(modelViewMatrix, modelViewMatrix, rotation.z)
// scale
glMatrix.mat4.scale(modelViewMatrix, modelViewMatrix, glMatrix.vec3.fromValues(scale.x, scale.y, scale.z))
// return matrix as Float32Array
return modelViewMatrix ;//as Float32Array
}
/*
function getProjectionMatrix(
aspect: number,
fov:number = 60 / 180 * Math.PI,
near:number = 0.1,
far:number = 100.0,
position = {x:0, y:0, z:0}
){
*/
function getProjectionMatrix(
aspect,
fov,
near,
far,
position
){
// create cameraview
const cameraView = glMatrix.mat4.create()
const eye = glMatrix.vec3.fromValues(position.x, position.y, position.z)
glMatrix.mat4.translate(cameraView, cameraView, eye)
glMatrix.mat4.lookAt(cameraView, eye, center, up)
// get a perspective Matrix
const projectionMatrix = glMatrix.mat4.create()
glMatrix.mat4.perspective(projectionMatrix, fov, aspect, near, far)
glMatrix.mat4.multiply(projectionMatrix, projectionMatrix, cameraView)
// return matrix as Float32Array
return projectionMatrix;// as Float32Array
}
//==============================
function frame() {
//=================================
/*
const transformationMatrix = getTransformationMatrix();
device.queue.writeBuffer(
uniformBuffer,
0,
transformationMatrix.buffer,
transformationMatrix.byteOffset,
transformationMatrix.byteLength
);
*/
let position = { x: 0, y: 0, z: -5 }
let scale = { x: 1, y: 1, z: 1 }
// let rotation = { x: 0, y: 2, z: 3 }
//-----------------
// let viewMatrix = glMatrix.mat4.create();
// glMatrix.mat4.translate(viewMatrix, viewMatrix, glMatrix.vec3.fromValues(0, 0, -5));
let now = Date.now() / 1000;
// glMatrix.mat4.rotate(viewMatrix, viewMatrix, 1, glMatrix.vec3.fromValues(Math.sin(now), Math.cos(now), 0));
let rotation={x:Math.sin(now), y:Math.cos(now), z:0};
//---------------------
const mvpMatrix = getMvpMatrix(aspect, position, rotation, scale)
/* device.queue.writeBuffer(
pipelineObj.mvpBuffer,
0,
mvpMatrix.buffer
);
*/
device.queue.writeBuffer(
uniformBuffer,
0,
mvpMatrix.buffer,
mvpMatrix.byteOffset,
mvpMatrix.byteLength
);
//=============================
//必须在这里设置texture,否则保存
renderPassDescriptor.colorAttachments[0].view = context
.getCurrentTexture()
.createView();
const commandEncoder = device.createCommandEncoder();
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setPipeline(pipeline);
passEncoder.setBindGroup(0, uniformBindGroup);
passEncoder.setVertexBuffer(0, vertexBuffer);
passEncoder.draw(36, 1, 0, 0);
passEncoder.end();
device.queue.submit([commandEncoder.finish()]);
requestAnimationFrame(frame);
};
frame();
</script>
</body>
</html>