<!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>Threejs中文网:http://www.webgl3d.cn/</title>
<style>
</style>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形1三个顶点坐标的x、y、z值
-0.3, -0.5, 0.0,//顶点1坐标
0.3, -0.5, 0.0,//顶点2坐标
0.3, 0.5, 0.0,//顶点3坐标
// 三角形2三个顶点坐标的x、y、z值
-0.3, -0.5, 0.0,//顶点4坐标 与顶点1重合
0.3, 0.5, 0.0,//顶点5坐标 与顶点3重合
-0.3, 0.5, 0.0,//顶点6坐标
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
renderPass.draw(6);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return vec4<f32>(pos,1.0);
}
`;
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main(@builtin(position) fragCoord : vec4<f32>) -> @location(0) vec4<f32> {
var x = fragCoord.x;//片元屏幕坐标x
var y = fragCoord.y;//片元屏幕坐标y
// fragCoord.z;
if(x < 250.0){
// 片元x屏幕坐标小于250,片元设置为红色
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}else{
// 片元x屏幕坐标不小于250,片元设置为绿色
return vec4<f32>(0.0, 1.0, 0.0, 1.0);
}
// 左上角红色,其他区域绿色
// if(x < 250.0 && y < 250.0){
// return vec4<f32>(1.0, 0.0, 0.0, 1.0);
// }else{
// return vec4<f32>(0.0, 1.0, 0.0, 1.0);
// }
}
`;
export { vertex, fragment };
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 0.0,
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return vec4<f32>(pos,1.0);
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main(@builtin(position) fragCoord : vec4<f32>) -> @location(0) vec4<f32> {
var x = fragCoord.x;//片元屏幕坐标x
var y = fragCoord.y;//片元屏幕坐标y
// 渐变色
var per: f32 = (x-250.0)/250.0;
return vec4<f32>(per, 0.0, 1.0-per, 1.0);
}
`
export { vertex, fragment }
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Three.js中文网:www.webgl3d.cn</title>
</head>
<body>
<script>
let i = 0;
// 循环动画
function render() {
i += 1;
console.log(i);
}
render();
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Three.js中文网:www.webgl3d.cn</title>
</head>
<body>
<script>
// requestAnimationFrame实现周期性循环执行
// requestAnimationFrame默认每秒钟执行60次,但不一定能做到,要看代码的性能
let i = 0;
function render() {
i+=1;
console.log('执行次数'+i);
requestAnimationFrame(render);//请求再次执行函数render
}
render();
</script>
</body>
</html>
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 引入gl-matrix库
import * as glMatrix from '../../gl-matrix/index.js'
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形1
-0.3, -0.5, 0.0,
0.3, -0.5, 0.0,
0.3, 0.5, 0.0,
// 三角形2
-0.3, -0.5, 0.0,
0.3, 0.5, 0.0,
-0.3, 0.5, 0.0,
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
const modelMatrix = glMatrix.mat4.create();
// 绕z旋转30度
glMatrix.mat4.rotateZ(modelMatrix, modelMatrix, Math.PI/6);
// 绕z旋转90度
// glMatrix.mat4.rotateZ(modelMatrix, modelMatrix, Math.PI/2);
// 在GPU显存上创建一个uniform数据缓冲区
const modelMatrixBuffer = device.createBuffer({
size: modelMatrix.byteLength,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(modelMatrixBuffer, 0, modelMatrix);
// 设置uniform数据的绑定组
const bindGroup = device.createBindGroup({
// .getBindGroupLayout(0)参数0对应shader中@group(0)代码的参数0
layout: pipeline.getBindGroupLayout(0),//绑定组,标记为0
// 一个组里面可以包含多个uniform数据
entries: [//每个元素可以用来设置一个uniform数据
{
//binding的值对应@binding(0)的参数,保持一致,比如都是0
binding: 0,//标记组里面的uniform数据
resource: { buffer: modelMatrixBuffer }
}
]
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
// 把绑定组里面的uniform数据传递给着色器中uniform变量
renderPass.setBindGroup(0, bindGroup);
renderPass.draw(6);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
@group(0) @binding(0) var<uniform> modelMatrix:mat4x4<f32>;
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return modelMatrix * vec4<f32>(pos,1.0);
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export { vertex, fragment }
// @group(0) @binding(0) var<uniform> t:f32;
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 引入gl-matrix库
import * as glMatrix from '../../gl-matrix/index.js'
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形1
-0.3, -0.5, 0.0,
0.3, -0.5, 0.0,
0.3, 0.5, 0.0,
// 三角形2
-0.3, -0.5, 0.0,
0.3, 0.5, 0.0,
-0.3, 0.5, 0.0,
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
const modelMatrix = glMatrix.mat4.create();
// 在GPU显存上创建一个uniform数据缓冲区
const modelMatrixBuffer = device.createBuffer({
size: modelMatrix.byteLength,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(modelMatrixBuffer, 0, modelMatrix);
// 设置uniform数据的绑定组
const bindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),//绑定组,标记为0
entries: [
{
//binding的值对应@binding(0)的参数,保持一致,比如都是0
binding: 0,//标记组里面的uniform数据
resource: { buffer: modelMatrixBuffer }
}
]
});
//渲染循环
let angle = 0.0;//初始旋转角度
function render() {
angle += 0.05;//每次渲染角度增加
const modelMatrix = glMatrix.mat4.create();
// 每次渲染,生成新的旋转矩阵
glMatrix.mat4.rotateZ(modelMatrix, modelMatrix, angle);
//模型矩阵modelMatrix重新写入uniform数据的缓冲区中
device.queue.writeBuffer(modelMatrixBuffer, 0, modelMatrix)
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
// 把绑定组里面的uniform数据传递给着色器中uniform变量
renderPass.setBindGroup(0, bindGroup);
renderPass.draw(6);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
requestAnimationFrame(render);
}
render()
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
@group(0) @binding(0) var<uniform> modelMatrix:mat4x4<f32>;
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return modelMatrix * vec4<f32>(pos,1.0);
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export { vertex, fragment }
// @group(0) @binding(0) var<uniform> t:f32;
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 引入gl-matrix库
import * as glMatrix from '../../gl-matrix/index.js'
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形三个顶点坐标的x、y、z值
0.0, 0.0, 0.0,//顶点1坐标
1.0, 0.0, 0.0,//顶点2坐标
0.0, 1.0, 0.0,//顶点3坐标
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 传递着色器对应uniform数据
const mat4Array = glMatrix.mat4.create();
//生成平移变换矩阵
glMatrix.mat4.translate(mat4Array, mat4Array, [-1, -1, 0]);
// 在GPU显存上创建一个uniform数据缓冲区
const mat4Buffer = device.createBuffer({
size: mat4Array.byteLength,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
// mat4Array里面矩阵数据写入uniform缓冲区mat4Buffer
device.queue.writeBuffer(mat4Buffer, 0, mat4Array);
// 设置uniform数据的绑定组
// 学习createBindGroup的参数,可以类比渲染管线中shaderLocation学习
const bindGroup = device.createBindGroup({
// .getBindGroupLayout(0)参数0对应shader中@group(0)代码的参数0
layout: pipeline.getBindGroupLayout(0),//绑定组,标记为0
// 一个组里面可以包含多个uniform数据
entries: [//每个元素可以用来设置一个uniform数据
{
//binding的值对应@binding(0)的参数,保持一致,比如都是0
binding: 0,//标记组里面的uniform数据
resource: { buffer: mat4Buffer }
}
]
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
// 把绑定组里面的uniform数据传递给着色器中uniform变量
renderPass.setBindGroup(0, bindGroup);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
// uniform关键字辅助var声明一个4x4矩阵变量
//@group(0)的参数0对应webgpu代码.getBindGroupLayout(0)参数0
//@binding(0)的参数对应webgpu代码.binding的值,保持一致,比如都是0
@group(0) @binding(0) var<uniform> modelMatrix:mat4x4<f32>;
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return modelMatrix * vec4<f32>(pos,1.0);
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export { vertex, fragment }
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 引入gl-matrix库
import * as glMatrix from '../../gl-matrix/index.js'
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形三个顶点坐标的x、y、z值
0.0, 0.0, 0.0,//顶点1坐标
1.0, 0.0, 0.0,//顶点2坐标
0.0, 1.0, 0.0,//顶点3坐标
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 传递着色器对应uniform数据
const modelMatrix = glMatrix.mat4.create();
//后发生平移变换,先乘
glMatrix.mat4.translate(modelMatrix, modelMatrix, [-1, -1, 0]);
//先发生缩放变换,后乘
glMatrix.mat4.scale(modelMatrix, modelMatrix, [0.5, 0.5, 1]);
// 在GPU显存上创建一个uniform数据缓冲区
const modelMatrixBuffer = device.createBuffer({
size: modelMatrix.byteLength,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(modelMatrixBuffer, 0, modelMatrix);
// 设置uniform数据的绑定组
// 学习createBindGroup的参数,可以类比渲染管线中shaderLocation学习
const bindGroup = device.createBindGroup({
// .getBindGroupLayout(0)参数0对应shader中@group(0)代码的参数0
layout: pipeline.getBindGroupLayout(0),//绑定组,标记为0
// 一个组里面可以包含多个uniform数据
entries: [//每个元素可以用来设置一个uniform数据
{
binding: 0,
resource: { buffer: modelMatrixBuffer }
}
]
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
// 把绑定组里面的uniform数据传递给着色器中uniform变量
renderPass.setBindGroup(0, bindGroup);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
@group(0) @binding(0) var<uniform> modelMatrix:mat4x4<f32>;
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return modelMatrix * vec4<f32>(pos,1.0);
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export { vertex, fragment }
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 引入gl-matrix库
import * as glMatrix from '../../gl-matrix/index.js'
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形三个顶点坐标的x、y、z值
0.0, 0.0, 0.0,//顶点1坐标
1.0, 0.0, 0.0,//顶点2坐标
0.0, 1.0, 0.0,//顶点3坐标
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 传递着色器对应uniform数据
const modelMatrix = glMatrix.mat4.create();
//后发生缩放变换,先乘
glMatrix.mat4.scale(modelMatrix, modelMatrix, [0.5, 0.5, 1]);
//先发生平移变换,后乘
glMatrix.mat4.translate(modelMatrix, modelMatrix, [-1, -1, 0]);
// 在GPU显存上创建一个uniform数据缓冲区
const modelMatrixBuffer = device.createBuffer({
size: modelMatrix.byteLength,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(modelMatrixBuffer, 0, modelMatrix);
// 设置uniform数据的绑定组
// 学习createBindGroup的参数,可以类比渲染管线中shaderLocation学习
const bindGroup = device.createBindGroup({
// .getBindGroupLayout(0)参数0对应shader中@group(0)代码的参数0
layout: pipeline.getBindGroupLayout(0),//绑定组,标记为0
// 一个组里面可以包含多个uniform数据
entries: [//每个元素可以用来设置一个uniform数据
{
binding: 0,//标记组里面的uniform数据
resource: { buffer: modelMatrixBuffer }
}
]
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
// 把绑定组里面的uniform数据传递给着色器中uniform变量
renderPass.setBindGroup(0, bindGroup);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
@group(0) @binding(0) var<uniform> modelMatrix:mat4x4<f32>;
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return modelMatrix * vec4<f32>(pos,1.0);
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export { vertex, fragment }
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 引入gl-matrix库
import * as glMatrix from '../../gl-matrix/index.js'
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形三个顶点坐标的x、y、z值
0.0, 0.0, 0.0,//顶点1坐标
1.0, 0.0, 0.0,//顶点2坐标
0.0, 1.0, 0.0,//顶点3坐标
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 传递着色器对应uniform数据
const mat4Array = glMatrix.mat4.create();
//缩放变换
glMatrix.mat4.scale(mat4Array, mat4Array, [0.5, 0.5, 1]);
// 在GPU显存上创建一个uniform数据缓冲区
const mat4Buffer = device.createBuffer({
size: mat4Array.byteLength,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
// mat4Array里面矩阵数据写入uniform缓冲区mat4Buffer
device.queue.writeBuffer(mat4Buffer, 0, mat4Array);
// 设置uniform数据的绑定组
// 学习createBindGroup的参数,可以类比渲染管线中shaderLocation学习
const bindGroup = device.createBindGroup({
// .getBindGroupLayout(0)参数0对应shader中@group(0)代码的参数0
layout: pipeline.getBindGroupLayout(0),//绑定组,标记为0
// 一个组里面可以包含多个uniform数据
entries: [//每个元素可以用来设置一个uniform数据
{
//binding的值对应@binding(0)的参数,保持一致,比如都是0
binding: 0,//标记组里面的uniform数据
resource: { buffer: mat4Buffer }
}
]
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
// 把绑定组里面的uniform数据传递给着色器中uniform变量
renderPass.setBindGroup(0, bindGroup);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
// uniform关键字辅助var声明一个4x4矩阵变量
//@group(0)的参数0对应webgpu代码.getBindGroupLayout(0)参数0
//@binding(0)的参数对应webgpu代码.binding的值,保持一致,比如都是0
@group(0) @binding(0) var<uniform> S:mat4x4<f32>;
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return S * vec4<f32>(pos,1.0);
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export { vertex, fragment }
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 引入gl-matrix库
import * as glMatrix from '../gl-matrix/index.js'
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形1
-0.3, -0.5, 0.0,
0.3, -0.5, 0.0,
0.3, 0.5, 0.0,
// 三角形2
-0.3, -0.5, 0.0,
0.3, 0.5, 0.0,
-0.3, 0.5, 0.0,
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// const modelMatrix = glMatrix.mat4.create();
// // 在GPU显存上创建一个uniform数据缓冲区
// const modelMatrixBuffer = device.createBuffer({
// size: modelMatrix.byteLength,
// usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
// });
const modelMatrixBuffer = device.createBuffer({
size: 16*4,//旋转矩阵16个元素,每个元素占4个字节
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
// 设置uniform数据的绑定组
const bindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),//绑定组,标记为0
entries: [
{
//binding的值对应@binding(0)的参数,保持一致,比如都是0
binding: 0,//标记组里面的uniform数据
resource: { buffer: modelMatrixBuffer }
}
]
});
//渲染循环
let angle = 0.0;
function render() {
angle += 0.05;
const modelMatrix = glMatrix.mat4.create();
// 每次操作(旋转后,再平移)
glMatrix.mat4.translate(modelMatrix, modelMatrix,[0,0,0.5]);//后平移,不平移矩形平面会被剪裁掉一半
glMatrix.mat4.rotateY(modelMatrix, modelMatrix,angle);//先旋转
device.queue.writeBuffer(modelMatrixBuffer, 0, modelMatrix)
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
// 把绑定组里面的uniform数据传递给着色器中uniform变量
renderPass.setBindGroup(0, bindGroup);
renderPass.draw(6);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
requestAnimationFrame(render);
}
render()
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
@group(0) @binding(0) var<uniform> modelMatrix:mat4x4<f32>;
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return modelMatrix * vec4<f32>(pos,1.0);
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export { vertex, fragment }
// @group(0) @binding(0) var<uniform> t:f32;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
0.0, 0.0, 0.0,
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
struct Out{
@builtin(position) position:vec4<f32>,
// 位置变量vPosition表示顶点位置坐标插值后的坐标
// 通过location标记改变量,location的参数可以是0、1、2等
// vPosition用来表示每个片元的xyz坐标
@location(0) vPosition:vec3<f32>,
}
@vertex
fn main(@location(0) pos: vec3<f32>) -> Out {
var out:Out;//通过结构体声明一个变量
out.position = vec4<f32>(pos,1.0);
out.vPosition = pos;//插值计算,生成的每个片元对应的xyz坐标
return out;
}
`;
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
// main参数通过@location(0)声明一个变量,和顶点着色器中vPosition变量关联起来
fn main(@location(0) vPosition:vec3<f32>) -> @location(0) vec4<f32> {
// 根据x坐标设置片元颜色
if(vPosition.x<0.5){
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}else{
return vec4<f32>(0.0, 1.0, 0.0, 1.0);
}
}
`;
export { vertex, fragment };
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
0.0, 0.0, 0.0,
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
struct Out{
@builtin(position) position:vec4<f32>,
}
@vertex
fn main(@location(0) pos: vec3<f32>) -> Out {
var out:Out;
out.position = vec4<f32>(pos,1.0);
return out;
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export { vertex, fragment }
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return vec4<f32>(pos,1.0);
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main(@builtin(position) fragCoord : vec4<f32>) -> @location(0) vec4<f32> {
//片元深度值
var z = fragCoord.z;
// if(z < 0.5){
// // 片元深度值小于0.5,片元设置为红色
// return vec4<f32>(1.0, 0.0, 0.0, 1.0);
// }else{
// // 片元深度值不小于250,片元设置为绿色
// return vec4<f32>(0.0, 1.0, 0.0, 1.0);
// }
// 可视化片元深度
// return vec4<f32>(z, 1.0, 0.0, 1.0);
return vec4<f32>(z,0.0, 1.0-z, 1.0);
}
`
export {
vertex,
fragment
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
struct Out{
@builtin(position) position:vec4<f32>,
@location(0) vPosition:vec3<f32>
}
@vertex
fn main(@location(0) pos: vec3<f32>) -> Out{
var out:Out;
out.position = vec4<f32>(pos,1.0);
out.vPosition = pos;////插值计算,生成的每个片元对应的xyz坐标
return out;
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main(@location(0) vPosition:vec3<f32>) -> @location(0) vec4<f32> {
// if(vPosition.y<0.5){
// return vec4<f32>(1.0, 0.0, 0.0, 1.0);
// }else{
// return vec4<f32>(0.0, 1.0, 0.0, 1.0);
// }
return vec4<f32>(vPosition.x, 0.0, 1.0-vPosition.x, 1.0);
}
`
export { vertex, fragment }
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<script type="module">
import * as glMatrix from './gl-matrix-master/dist/esm/index.js'
// 顶点先平移、后缩放
const modelMatrix = glMatrix.mat4.create();
//modelMatrix乘一个缩放矩阵(x方向缩放10倍)
glMatrix.mat4.scale(modelMatrix, modelMatrix, [10, 1, 1]);//后缩放
//modelMatrix乘一个平移矩阵(沿着x平移2)
glMatrix.mat4.translate(modelMatrix, modelMatrix, [2, 0, 0]);//先平移
console.log('modelMatrix', modelMatrix);
const p1 = glMatrix.vec3.fromValues(2, 0, 0);//表示一个顶点的坐标
const p2 = glMatrix.vec3.create();//默认(0,0,0)
console.log('p2',p2);
// //p1矩阵变换,变换后结果存储在p2
glMatrix.vec3.transformMat4(p2, p1, modelMatrix);
console.log('p2', p2);//Float32Array(3) [40, 0, 0]
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<script type="module">
import * as glMatrix from './gl-matrix-master/dist/esm/index.js'
// 顶点先平移、后缩放
// 沿着x平移2
// x方向缩放10倍
const modelMatrix = glMatrix.mat4.create();
//后发生缩放变换,先乘
glMatrix.mat4.scale(modelMatrix, modelMatrix, [10, 1, 1]);
//先发生平移变换,后乘
glMatrix.mat4.translate(modelMatrix, modelMatrix, [2, 0, 0]);
console.log('modelMatrix', modelMatrix);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<script type="module">
// 引入全部API
import * as glMatrix from './gl-matrix-master/dist/esm/index.js'
console.log('glMatrix.mat4', glMatrix.mat4);
// 创建一个平移矩阵(沿着x、y、z轴分别平移1、2、3)
//1 0 0 1
//0 1 0 2
//0 0 1 3
//0 0 0 1
//把矩阵按照列依次写入作为参数
const mat4T = glMatrix.mat4.fromValues(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1);
//创建一个缩放矩阵(x、y、z分别缩放1、2、3)
//1 0 0 0
//0 2 0 0
//0 0 3 0
//0 0 0 1
//把矩阵按照列依次写入作为参数
const mat4S = glMatrix.mat4.fromValues(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1);
// 创建的矩阵其实就是用JavaScript的类型化数组表示的
console.log('mat4T', mat4T);
console.log('mat4S', mat4S);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<script type="module">
import * as glMatrix from './gl-matrix-master/dist/esm/index.js'
console.log('glMatrix', glMatrix);
// glMatrix.mat4.create()创建的是单位矩阵(乘法运算不会旋转、缩放、平移改变坐标)
const mat4 = glMatrix.mat4.create();//单位矩阵
console.log('mat4',mat4);
// 创建一个平移矩阵(沿着x平移2)
const mat4T = glMatrix.mat4.create();
glMatrix.mat4.translate(mat4T,mat4,[2,0,0]);
// // 创建一个缩放矩阵(x缩放10)
const mat4S = glMatrix.mat4.create();
glMatrix.mat4.scale(mat4S,mat4,[10,1,1]);
console.log('mat4T',mat4T);
console.log('mat4S',mat4S);
// 生成一个旋转矩阵(绕z轴旋转45度)
const mat4X = glMatrix.mat4.create();
glMatrix.mat4.rotateX(mat4X,mat4,Math.PI/4);
console.log('mat4X',mat4X);
// 生成一个旋转矩阵(绕z轴旋转45度)
const mat4Y = glMatrix.mat4.create();
glMatrix.mat4.rotateY(mat4Y,mat4,Math.PI/4);
console.log('mat4Y',mat4Y);
// 生成一个旋转矩阵(绕z轴旋转45度)
const mat4Z = glMatrix.mat4.create();
glMatrix.mat4.rotateZ(mat4Z,mat4,Math.PI/4);
console.log('mat4Z',mat4Z);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<script type="module">
import * as glMatrix from './gl-matrix-master/dist/esm/index.js'
const mat4 = glMatrix.mat4.create();//单位矩阵
// 创建一个平移矩阵(沿着x平移2)
const mat4T = glMatrix.mat4.create();
glMatrix.mat4.translate(mat4T,mat4,[2,0,0]);
// 创建一个缩放矩阵(x缩放10)
const mat4S = glMatrix.mat4.create();
glMatrix.mat4.scale(mat4S,mat4,[10,1,1]);
// 矩阵乘法运算.multiply()
const modelMatrix = glMatrix.mat4.create();//模型矩阵
glMatrix.mat4.multiply(modelMatrix,modelMatrix,mat4S);//后缩放
glMatrix.mat4.multiply(modelMatrix,modelMatrix,mat4T);//先平移
console.log('modelMatrix',modelMatrix);
</script>
</body>
</html>
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形三个顶点坐标的x、y、z值
0.0, 0.0, 0.0,//顶点1坐标
1.0, 0.0, 0.0,//顶点2坐标
0.0, 1.0, 0.0,//顶点3坐标
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
// 创建一个平移矩阵(沿着x、y轴分别平移-1、-1)
var T:mat4x4<f32> = 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);
// 创建一个缩放矩阵(沿着x、y分别缩放0.5倍)
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 * T * vec4<f32>(pos,1.0);// 先平移、后缩放(矩阵顺序从右往左)
// return T * S * vec4<f32>(pos,1.0);// 先缩放、后平移(矩阵顺序从右往左)
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export {
vertex,
fragment
}
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形三个顶点坐标的x、y、z值
0.0, 0.0, 0.0,//顶点1坐标
1.0, 0.0, 0.0,//顶点2坐标
0.0, 1.0, 0.0,//顶点3坐标
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
// 创建一个平移矩阵(沿着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> = 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);//平移矩阵对顶点平移变换
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export {
vertex,
fragment
}
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形三个顶点坐标的x、y、z值
0.0, 0.0, 0.0,//顶点1坐标
1.0, 0.0, 0.0,//顶点2坐标
0.0, 1.0, 0.0,//顶点3坐标
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
// 创建一个平移矩阵(沿着x、y轴分别平移-1、-1)
var T:mat4x4<f32> = 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);
// 创建一个缩放矩阵(沿着x、y分别缩放0.5倍)
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 * T * vec4<f32>(pos,1.0);// 先平移、后缩放(矩阵顺序从右往左)
return T * S * vec4<f32>(pos,1.0);// 先缩放、后平移(矩阵顺序从右往左)
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export {
vertex,
fragment
}
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形三个顶点坐标的x、y、z值
0.0, 0.0, 0.0,//顶点1坐标
1.0, 0.0, 0.0,//顶点2坐标
0.0, 1.0, 0.0,//顶点3坐标
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
// 创建一个缩放矩阵(沿着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 * vec4<f32>(pos,1.0);//缩放矩阵对顶点缩放变换
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export { vertex, fragment }
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形三个顶点坐标的x、y、z值
0.0, 0.0, 0.0,//顶点1坐标
1.0, 0.0, 0.0,//顶点2坐标
0.0, 1.0, 0.0,//顶点3坐标
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 传递着色器对应uniform数据(传递一个浮点数)
const t = 0.5;//一个浮点数,表示三角形x和y两个方向的缩放倍数
const tArray = new Float32Array([t]);
// 在GPU显存上创建一个uniform数据缓冲区
const tBuffer = device.createBuffer({
size: tArray.byteLength,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
//tArray里面矩阵数据写入uniform缓冲区tBuffer
device.queue.writeBuffer(tBuffer, 0, tArray);
// 设置uniform数据的绑定组
// 学习createBindGroup的参数,可以类比渲染管线中shaderLocation学习
const bindGroup = device.createBindGroup({
// .getBindGroupLayout(0)参数0对应shader中@group(0)代码的参数0
layout: pipeline.getBindGroupLayout(0),//绑定组,标记为0
// 一个组里面可以包含多个uniform数据
entries: [//每个元素可以用来设置一个uniform数据
{
//binding的值对应@binding(0)的参数,保持一致,比如都是0
binding: 0,//标记组里面的uniform数据
resource: { buffer: tBuffer }
}
]
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
// 把绑定组里面的uniform数据传递给着色器中uniform变量
renderPass.setBindGroup( 0, bindGroup );
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
@group(0) @binding(0) var<uniform> t:f32;
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
// 创建一个缩放矩阵(沿着x、y分别缩放t倍)
//t 0 0 0
//0 t 0 0
//0 0 1 0
//0 0 0 1
// 矩阵元素一列一列输入mat4x4<f32>()
var S = mat4x4<f32>(t,0.0,0.0,0.0, 0.0,t,0.0,0.0, 0.0,0.0,1.0,0.0, 0.0,0.0,0.0,1.0);
return S * vec4<f32>(pos,1.0);//缩放矩阵对顶点缩放变换
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export { vertex, fragment }
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形三个顶点坐标的x、y、z值
0.0, 0.0, 0.0,//顶点1坐标
1.0, 0.0, 0.0,//顶点2坐标
0.0, 1.0, 0.0,//顶点3坐标
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 传递着色器对应uniform数据
// 创建一个缩放矩阵(沿着x、y分别缩放0.5倍)
//0.5 0 0 0
//0 0.5 0 0
//0 0 1 0
//0 0 0 1
// 矩阵元素一列一列输入作为类型化数组的参数
const mat4Array = 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]);
// 在GPU显存上创建一个uniform数据缓冲区
const mat4Buffer = device.createBuffer({
size: mat4Array.byteLength,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
// mat4Array里面矩阵数据写入uniform缓冲区mat4Buffer
device.queue.writeBuffer(mat4Buffer, 0, mat4Array);
// 给片元着色器传递一个颜色数据
const colorArray = new Float32Array([0.0,1.0,0.0]);//绿色
// 在GPU显存上创建一个uniform数据缓冲区
const colorBuffer = device.createBuffer({
size: colorArray.byteLength,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
// colorArray里面颜色数据写入uniform缓冲区colorBuffer
device.queue.writeBuffer(colorBuffer, 0, colorArray);
// 设置uniform数据的绑定组
// 学习createBindGroup的参数,可以类比渲染管线中shaderLocation学习
const bindGroup = device.createBindGroup({
// .getBindGroupLayout(0)参数0对应shader中@group(0)代码的参数0
layout: pipeline.getBindGroupLayout(0),//绑定组,标记为0
// 一个组里面可以包含多个uniform数据
entries: [//每个元素可以用来设置一个uniform数据
{
//binding的值对应@binding(0)的参数,保持一致,比如都是0
binding: 0,//标记组里面的uniform数据
resource: { buffer: mat4Buffer }
},
{
//binding的值对应@binding(1)的参数,保持一致,比如都是1
binding: 1,//标记组里面的uniform数据
resource: { buffer: colorBuffer }
}
]
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
// 把绑定组里面的uniform数据传递给着色器中uniform变量
renderPass.setBindGroup(0, bindGroup);
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
// uniform关键字辅助var声明一个4x4矩阵变量
//@group(0)的参数0对应webgpu代码.getBindGroupLayout(0)参数0
//@binding(0)的参数对应webgpu代码.binding的值,保持一致,比如都是0
@group(0) @binding(0) var<uniform> S:mat4x4<f32>;
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return S * vec4<f32>(pos,1.0);//缩放矩阵对顶点缩放变换
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
// uniform关键字辅助var声明一个三维向量变量color表示片元颜色
//@binding(1)的参数对应webgpu代码.binding的值,保持一致,比如都是1
@group(0) @binding(1) var<uniform> color:vec3<f32>;
@fragment
fn main() -> @location(0) vec4<f32> {
// return vec4<f32>(1.0, 0.0, 0.0, 1.0);
return vec4<f32>(color, 1.0);
}
`
export { vertex, fragment }
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形三个顶点坐标的x、y、z值
0.0, 0.0, 0.0,//顶点1坐标
1.0, 0.0, 0.0,//顶点2坐标
0.0, 1.0, 0.0,//顶点3坐标
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 传递着色器对应uniform数据
// 创建一个缩放矩阵(沿着x、y分别缩放0.5倍)
//0.5 0 0 0
//0 0.5 0 0
//0 0 1 0
//0 0 0 1
// 矩阵元素一列一列输入作为类型化数组的参数
const mat4Array = 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]);
// 在GPU显存上创建一个uniform数据缓冲区
const mat4Buffer = device.createBuffer({
size: mat4Array.byteLength,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
// mat4Array里面矩阵数据写入uniform缓冲区mat4Buffer
device.queue.writeBuffer(mat4Buffer, 0, mat4Array);
// 设置uniform数据的绑定组
// 学习createBindGroup的参数,可以类比渲染管线中shaderLocation学习
const bindGroup = device.createBindGroup({
// .getBindGroupLayout(0)参数0对应shader中@group(0)代码的参数0
layout: pipeline.getBindGroupLayout(0),//绑定组,标记为0
// 一个组里面可以包含多个uniform数据
entries: [//每个元素可以用来设置一个uniform数据
{
//binding的值对应@binding(0)的参数,保持一致,比如都是0
binding: 0,//标记组里面的uniform数据
resource: { buffer: mat4Buffer }
}
]
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
// 把绑定组里面的uniform数据传递给着色器中uniform变量
renderPass.setBindGroup( 0, bindGroup );
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
// uniform关键字辅助var声明一个4x4矩阵变量
//@group(0)的参数0对应webgpu代码.getBindGroupLayout(0)参数0
//@binding(0)的参数对应webgpu代码.binding的值,保持一致,比如都是0
@group(0) @binding(0) var<uniform> S:mat4x4<f32>;
@vertex
fn main(@location(0) pos: vec3<f32>) -> @builtin(position) vec4<f32> {
return S * vec4<f32>(pos,1.0);//缩放矩阵对顶点缩放变换
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export { vertex, fragment }
<!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>Threejs中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- canvas:用来展示WebGPU渲染的结果 -->
<canvas id="webgpu" width="500" height="500"></canvas>
<script type="module">
// 顶点着色器、片元着色器代码
import { vertex, fragment } from './shader.js'
// 配置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 vertexArray = new Float32Array([
// 三角形三个顶点坐标的x、y、z值
0.0, 0.0, 0.0,//顶点1坐标
1.0, 0.0, 0.0,//顶点2坐标
0.0, 1.0, 0.0,//顶点3坐标
]);
const vertexBuffer = device.createBuffer({// 创建顶点数据的缓冲区
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(vertexBuffer, 0, vertexArray);// 顶点数据写入缓冲区
// 渲染管线
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {//顶点相关配置
module: device.createShaderModule({ code: vertex }),
entryPoint: "main",
buffers: [//顶点缓冲区相关设置
{
arrayStride: 3 * 4,
attributes: [{
shaderLocation: 0,//顶点缓冲区存储位置标记
format: "float32x3",
offset: 0
}]
}
]
},
fragment: {//片元相关配置
module: device.createShaderModule({ code: fragment }),
entryPoint: "main",
targets: [{
format: format
}]
},
primitive: {
topology: "triangle-list",//绘制三角形
}
});
// 传递着色器对应uniform数据
// 创建一个缩放矩阵(沿着x、y分别缩放0.5倍)
//0.5 0 0 0
//0 0.5 0 0
//0 0 1 0
//0 0 0 1
// 矩阵元素一列一列输入作为类型化数组的参数
const mat4Array = 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]);
// 在GPU显存上创建一个uniform数据缓冲区
const mat4Buffer = device.createBuffer({
size: mat4Array.byteLength,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
// mat4Array里面矩阵数据写入uniform缓冲区mat4Buffer
device.queue.writeBuffer(mat4Buffer, 0, mat4Array);
// 平移矩阵
const mat4Array2 = 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]);
// 在GPU显存上创建一个uniform数据缓冲区
const mat4Buffer2 = device.createBuffer({
size: mat4Array2.byteLength,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
// mat4Array里面矩阵数据写入uniform缓冲区mat4Buffer
device.queue.writeBuffer(mat4Buffer2, 0, mat4Array2);
// 设置uniform数据的绑定组
// 学习createBindGroup的参数,可以类比渲染管线中shaderLocation学习
const bindGroup = device.createBindGroup({
// .getBindGroupLayout(0)参数0对应shader中@group(0)代码的参数0
layout: pipeline.getBindGroupLayout(0),//绑定组,标记为0
// 一个组里面可以包含多个uniform数据
entries: [//每个元素可以用来设置一个uniform数据
{
//binding的值对应@binding(0)的参数,保持一致,比如都是0
binding: 0,//标记组里面的uniform数据
resource: { buffer: mat4Buffer }
},
{
//binding的值对应@binding(1)的参数,保持一致,比如都是1
binding: 1,//标记组里面的uniform数据
resource: { buffer: mat4Buffer2 }
}
]
});
// 命令编码器
const commandEncoder = device.createCommandEncoder();
// 渲染通道
const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
storeOp: 'store',
loadOp: 'clear',
}]
});
renderPass.setPipeline(pipeline);
// 顶点缓冲区数据和渲染管线shaderLocation: 0表示存储位置关联起来
renderPass.setVertexBuffer(0, vertexBuffer);
// 把绑定组里面的uniform数据传递给着色器中uniform变量
renderPass.setBindGroup( 0, bindGroup );
renderPass.draw(3);// 绘制顶点数据
renderPass.end();
const commandBuffer = commandEncoder.finish();
device.queue.submit([commandBuffer]);
</script>
</body>
</html>
// 顶点着色器代码
const vertex = /* wgsl */ `
// uniform关键字辅助var声明一个4x4矩阵变量
//@group(0)的参数0对应webgpu代码.getBindGroupLayout(0)参数0
//@binding(1)的参数对应webgpu代码.binding的值,保持一致,比如都是1
@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> {
// 先缩放、后平移
return T * S * vec4<f32>(pos,1.0);//缩放矩阵对顶点缩放变换
}
`
// 片元着色器代码
const fragment = /* wgsl */ `
@fragment
fn main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
`
export { vertex, fragment }
参考
- threejs中文档,郭老师博客