├── .gitignore
├── README.md
├── drawio
├── ortho.drawio
├── webgpu工作流.drawio
├── 渲染管线.drawio
└── 着色器传参.drawio
├── proj1_gameOfLife
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── bindGroup.ts
│ │ ├── gpuBuffer.ts
│ │ └── init.ts
│ ├── main.ts
│ ├── shader
│ │ ├── compute.wgsl
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ └── style.css
└── tsconfig.json
├── proj2_firework
├── .gitignore
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── bindGroup.ts
│ │ ├── gpuBuffer.ts
│ │ └── init.ts
│ ├── main.ts
│ ├── shader
│ │ ├── compute.wgsl
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ └── style.css
└── tsconfig.json
├── proj2_firework_2
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── bindGroup.ts
│ │ ├── gpuBuffer.ts
│ │ └── init.ts
│ ├── main.ts
│ ├── shader
│ │ ├── compute.wgsl
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ └── style.css
└── tsconfig.json
├── proj3_imageBlur
├── .gitignore
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── public
│ └── zs.png
├── src
│ ├── helper
│ │ ├── bindGroup.ts
│ │ ├── gpuBuffer.ts
│ │ └── init.ts
│ ├── main.ts
│ ├── shader
│ │ ├── compute.wgsl
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ └── style.css
└── tsconfig.json
├── proj3_imageBlur_Gaussian
├── .gitignore
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── public
│ └── zs.png
├── src
│ ├── helper
│ │ ├── bindGroup.ts
│ │ ├── gpuBuffer.ts
│ │ └── init.ts
│ ├── main.ts
│ ├── shader
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ └── style.css
└── tsconfig.json
├── proj4_galaxy
├── .gitignore
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── bindGroup.ts
│ │ ├── color.ts
│ │ ├── gpuBuffer.ts
│ │ ├── init.ts
│ │ └── math.ts
│ ├── main.ts
│ ├── shader
│ │ ├── compute.wgsl
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ └── style.css
└── tsconfig.json
├── vol0_triangle
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── main.ts
│ ├── shader
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ └── style.css
└── tsconfig.json
├── vol10_renderBundles
├── .gitignore
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── public
│ ├── moon.jpg
│ └── saturn.jpg
├── src
│ ├── helper
│ │ ├── bindGroup.ts
│ │ ├── color.ts
│ │ ├── gpuBuffer.ts
│ │ ├── init.ts
│ │ ├── math.ts
│ │ ├── sphere.ts
│ │ └── texture.ts
│ ├── main.ts
│ ├── shader
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ └── style.css
└── tsconfig.json
├── vol11_glb
├── .gitignore
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── public
│ ├── Buggy.glb
│ └── DamagedHelmet.glb
├── src
│ ├── components
│ │ ├── Camera.ts
│ │ └── InputManager.ts
│ ├── glb
│ │ ├── glb_accessor.ts
│ │ ├── glb_main.ts
│ │ ├── glb_material.ts
│ │ ├── glb_mesh.ts
│ │ ├── glb_model.ts
│ │ ├── glb_node.ts
│ │ ├── glb_primitive.ts
│ │ ├── glb_sampler.ts
│ │ ├── glb_shader_cache.ts
│ │ ├── glb_texture.ts
│ │ ├── glb_tool.ts
│ │ └── glb_viewbuffer.ts
│ ├── main.ts
│ ├── style.css
│ └── types
│ │ ├── glb.d.ts
│ │ └── index.d.ts
├── tsconfig.json
└── vite.config.js
├── vol11_glb_simple
├── .gitignore
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── public
│ ├── Buggy.glb
│ └── DamagedHelmet.glb
├── src
│ ├── components
│ │ ├── Camera.ts
│ │ └── InputManager.ts
│ ├── glb
│ │ ├── glb_accessor.ts
│ │ ├── glb_main.ts
│ │ ├── glb_mesh.ts
│ │ ├── glb_model.ts
│ │ ├── glb_node.ts
│ │ ├── glb_primitive.ts
│ │ ├── glb_tool.ts
│ │ └── glb_viewbuffer.ts
│ ├── main.ts
│ ├── shader
│ │ └── glb.wgsl
│ ├── style.css
│ └── types
│ │ ├── glb.d.ts
│ │ └── index.d.ts
├── tsconfig.json
└── vite.config.js
├── vol1_oneCube
├── .gitignore
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── public
│ └── ortho.svg
├── src
│ ├── main.ts
│ ├── shader
│ │ ├── cubeFrag.wgsl
│ │ └── cubeVert.wgsl
│ └── style.css
└── tsconfig.json
├── vol1_oneCube_MSAA
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── main.ts
│ ├── shader
│ │ ├── cubeFrag.wgsl
│ │ └── cubeVert.wgsl
│ └── style.css
└── tsconfig.json
├── vol1_oneCube_canvas_textureSampling
├── .gitignore
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── init.ts
│ │ ├── math.ts
│ │ └── vertexData.ts
│ ├── main.ts
│ ├── shader
│ │ ├── cubeFrag.wgsl
│ │ └── cubeVert.wgsl
│ └── style.css
└── tsconfig.json
├── vol1_oneCube_image_textureSampling
├── .gitignore
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── public
│ └── zs.png
├── src
│ ├── main.ts
│ ├── shader
│ │ ├── cubeFrag.wgsl
│ │ └── cubeVert.wgsl
│ └── style.css
└── tsconfig.json
├── vol1_oneCube_indexBuffer
├── .gitignore
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── init.ts
│ │ ├── math.ts
│ │ └── vertexData.ts
│ ├── main.ts
│ ├── shader
│ │ ├── cubeFrag.wgsl
│ │ └── cubeVert.wgsl
│ └── style.css
└── tsconfig.json
├── vol1_oneCube_video_textureSampling
├── .gitignore
├── README.md
├── index.html
├── package.json
├── pnpm-lock.yaml
├── public
│ └── 1.mp4
├── src
│ ├── helper
│ │ ├── init.ts
│ │ ├── math.ts
│ │ └── vertexData.ts
│ ├── main.ts
│ ├── shader
│ │ ├── cubeFrag.wgsl
│ │ └── cubeVert.wgsl
│ └── style.css
└── tsconfig.json
├── vol2_twoCubes
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── gpuBuffer.ts
│ │ ├── init.ts
│ │ ├── math.ts
│ │ └── vertexData.ts
│ ├── main.ts
│ ├── shader
│ │ ├── cubeFrag.wgsl
│ │ └── cubeVert.wgsl
│ └── style.css
└── tsconfig.json
├── vol2_twoCubes_MSAA
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── gpuBuffer.ts
│ │ ├── init.ts
│ │ ├── math.ts
│ │ └── vertexData.ts
│ ├── main.ts
│ ├── shader
│ │ ├── cubeFrag.wgsl
│ │ └── cubeVert.wgsl
│ └── style.css
└── tsconfig.json
├── vol3_sphere_wireFrame
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── gpuBuffer.ts
│ │ ├── init.ts
│ │ ├── math.ts
│ │ └── vertexData.ts
│ ├── main.ts
│ ├── shader
│ │ ├── sphereFrag.wgsl
│ │ └── sphereVert.wgsl
│ └── style.css
└── tsconfig.json
├── vol4_oneCube_light_mv+p
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── gpuBuffer.ts
│ │ ├── init.ts
│ │ ├── math.ts
│ │ └── vertexData.ts
│ ├── main.ts
│ ├── shader
│ │ ├── cubeFrag.wgsl
│ │ └── cubeVert.wgsl
│ └── style.css
└── tsconfig.json
├── vol4_oneCube_light_vp+m
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── gpuBuffer.ts
│ │ ├── init.ts
│ │ ├── math.ts
│ │ └── vertexData.ts
│ ├── main.ts
│ ├── shader
│ │ ├── cubeFrag.wgsl
│ │ └── cubeVert.wgsl
│ └── style.css
└── tsconfig.json
├── vol5_objects_light
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── box.ts
│ │ ├── gpuBuffer.ts
│ │ ├── init.ts
│ │ ├── math.ts
│ │ └── sphere.ts
│ ├── main.ts
│ ├── shader
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ └── style.css
└── tsconfig.json
├── vol5_objects_light_layout
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── box.ts
│ │ ├── gpuBuffer.ts
│ │ ├── init.ts
│ │ ├── math.ts
│ │ └── sphere.ts
│ ├── main.ts
│ ├── shader
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ └── style.css
└── tsconfig.json
├── vol6_shadowMapping
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── bindGroup.ts
│ │ ├── box.ts
│ │ ├── gpuBuffer.ts
│ │ ├── init.ts
│ │ └── math.ts
│ ├── main.ts
│ ├── shader
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ └── style.css
└── tsconfig.json
├── vol6_shadowMapping_two_lights
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── bindGroup.ts
│ │ ├── box.ts
│ │ ├── gpuBuffer.ts
│ │ ├── init.ts
│ │ └── math.ts
│ ├── main.ts
│ ├── shader
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ └── style.css
└── tsconfig.json
├── vol7_computeShader
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── bindGroup.ts
│ │ ├── box.ts
│ │ ├── gpuBuffer.ts
│ │ ├── init.ts
│ │ └── math.ts
│ ├── main.ts
│ ├── shader
│ │ ├── compute.wgsl
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ └── style.css
└── tsconfig.json
├── vol8_worker
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── helper
│ │ ├── bindGroup.ts
│ │ ├── cube.ts
│ │ ├── gpuBuffer.ts
│ │ └── math.ts
│ ├── main.ts
│ ├── shader
│ │ ├── frag.wgsl
│ │ └── vert.wgsl
│ ├── style.css
│ └── worker.ts
└── tsconfig.json
├── vol8_worker_axes
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── components
│ │ ├── Axes.ts
│ │ ├── Camera.ts
│ │ ├── Cube.ts
│ │ └── shader
│ │ │ ├── axes.frag.wgsl
│ │ │ ├── axes.vert.wgsl
│ │ │ ├── frag.wgsl
│ │ │ └── vert.wgsl
│ ├── helper
│ │ ├── bindGroup.ts
│ │ └── gpuBuffer.ts
│ ├── main.ts
│ ├── style.css
│ └── worker.ts
└── tsconfig.json
├── vol9_camera_control
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── components
│ │ ├── Axes.ts
│ │ ├── Camera.ts
│ │ ├── Cube.ts
│ │ ├── GPUManager.ts
│ │ ├── InputManager.ts
│ │ ├── RenderableObject.ts
│ │ ├── Scene.ts
│ │ └── shader
│ │ │ ├── axes.frag.wgsl
│ │ │ ├── axes.vert.wgsl
│ │ │ ├── cube.frag.wgsl
│ │ │ └── cube.vert.wgsl
│ ├── helper
│ │ ├── bindGroup.ts
│ │ ├── gpuBuffer.ts
│ │ └── init.ts
│ ├── main.ts
│ ├── math
│ │ └── quaternion.ts
│ └── style.css
└── tsconfig.json
└── vol9_camera_control_simple
├── .gitignore
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
├── components
│ ├── Axes.ts
│ ├── Camera.ts
│ ├── CameraController.ts
│ ├── Cube.ts
│ ├── GPUManager.ts
│ ├── RenderableObject.ts
│ ├── Scene.ts
│ └── shader
│ │ ├── axes.frag.wgsl
│ │ ├── axes.vert.wgsl
│ │ ├── cube.frag.wgsl
│ │ └── cube.vert.wgsl
├── helper
│ ├── bindGroup.ts
│ ├── gpuBuffer.ts
│ └── init.ts
├── main.ts
├── math
│ └── quaternion.ts
└── style.css
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 | .history
27 |
28 | test
29 |
30 | eng*
--------------------------------------------------------------------------------
/proj1_gameOfLife/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/proj1_gameOfLife/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/proj1_gameOfLife/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@types/dat.gui": "^0.7.10",
13 | "@webgpu/types": "^0.1.34",
14 | "typescript": "^5.0.4",
15 | "vite": "^4.3.2"
16 | },
17 | "dependencies": {
18 | "dat.gui": "^0.7.9",
19 | "wgpu-matrix": "^2.5.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/proj1_gameOfLife/src/helper/gpuBuffer.ts:
--------------------------------------------------------------------------------
1 | // 创建顶点缓冲区 VBO
2 | // 获取一块状态为映射了的显存,以及一个对应的 arrayBuffer 对象来写数据
3 | /**
4 | * 应用程序可以请求映射一个 GPUBuffer,这样它们就可以通过代表 GPUBuffer 分配的部分的 arraybuffer 访问它的内容。
5 | * 映射一个 GPUBuffer 是通过 mapAsync() 异步请求的,这样用户代理可以确保 GPU 在应用程序访问它的内容之前完成了对 GPUBuffer 的使用。
6 | * 映射的 GPUBuffer 不能被 GPU 使用,必须使用 unmap() 解除映射,然后才能将使用它的工作提交到 Queue 时间轴。
7 | * 一旦映射了 GPUBuffer,应用程序就可以通过 getMappedRange 同步请求访问其内容的范围
8 | */
9 | export const CreateGPUBuffer = (
10 | device: GPUDevice,
11 | data: Float32Array,
12 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.VERTEX |
13 | GPUBufferUsage.COPY_DST
14 | ) => {
15 | const buffer = device.createBuffer({
16 | size: data.byteLength,
17 | usage: usageFlag,
18 | mappedAtCreation: true,
19 | });
20 | new Float32Array(buffer.getMappedRange()).set(data);
21 | buffer.unmap();
22 | return buffer;
23 | };
24 |
25 | export const CreateGPUBufferUint = (
26 | device: GPUDevice,
27 | data: Uint32Array,
28 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
29 | GPUBufferUsage.COPY_DST
30 | ) => {
31 | const buffer = device.createBuffer({
32 | size: data.byteLength,
33 | usage: usageFlag,
34 | mappedAtCreation: true,
35 | });
36 | new Uint32Array(buffer.getMappedRange()).set(data);
37 | buffer.unmap();
38 | return buffer;
39 | };
40 |
41 | export const CreateGPUBufferUint16 = (
42 | device: GPUDevice,
43 | data: Uint16Array,
44 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
45 | GPUBufferUsage.COPY_DST
46 | ) => {
47 | const buffer = device.createBuffer({
48 | size: data.byteLength,
49 | usage: usageFlag,
50 | mappedAtCreation: true,
51 | });
52 | new Uint16Array(buffer.getMappedRange()).set(data);
53 | buffer.unmap();
54 | return buffer;
55 | };
56 |
--------------------------------------------------------------------------------
/proj1_gameOfLife/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.querySelector("canvas") as HTMLCanvasElement;
10 | canvas.width = window.innerWidth;
11 | canvas.height = window.innerHeight;
12 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
13 | // 请求WebGPU适配器与GPU设备
14 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
15 | const device = await adapter.requestDevice();
16 | const format = navigator.gpu.getPreferredCanvasFormat();
17 | // 配置上下文
18 | context.configure({
19 | device: device,
20 | // 上下文格式
21 | format: format,
22 | // 不透明度
23 | alphaMode: "opaque",
24 | });
25 | return { device, canvas, format, context };
26 | };
27 |
--------------------------------------------------------------------------------
/proj1_gameOfLife/src/shader/frag.wgsl:
--------------------------------------------------------------------------------
1 | @fragment
2 | fn main(@location(0) cell: f32) -> @location(0) vec4 {
3 | return vec4(cell, cell, cell, 1.);
4 | }
5 |
--------------------------------------------------------------------------------
/proj1_gameOfLife/src/shader/vert.wgsl:
--------------------------------------------------------------------------------
1 | struct Out {
2 | @builtin(position) pos: vec4,
3 | @location(0) cell: f32, // 表示每个顶点的细胞属性
4 | }
5 |
6 | @binding(0) @group(0) var size: vec2;
7 |
8 | @vertex
9 | fn main(
10 | @builtin(instance_index) i: u32,
11 | @location(0) cell: u32,
12 | @location(1) pos: vec2
13 | ) -> Out {
14 | let w = size.x;
15 | let h = size.y;
16 | // 这两行代码计算了顶点的标准化设备坐标(Normalized Device Coordinates,NDC),用于将顶点的位置从模拟世界坐标映射到屏幕上的坐标
17 | // 考虑 x 坐标。模拟世界的 x 坐标可能在 [0, width] 的范围内,其中 width 是模拟世界的宽度。但 NDC 的范围是 [-1, 1]。所以,我们需要将模拟世界的 x 坐标映射到 NDC 范围。
18 | // i % w + pos.x 计算出顶点在模拟世界中的 x 坐标
19 | // f32(i % w + pos.x) / f32(w) 将上述计算结果除以宽度 w,以将 x 坐标映射到 [0, 1] 范围内的浮点数。
20 | // - 0.5:将范围限制到 [-0.5, 0.5]
21 | // * 2. * f32(w) / f32(max(w, h)):将范围扩展到 [-w/h, w/h] 范围内,确保横纵比保持一致。
22 | let x = (f32(i % w + pos.x) / f32(w) - 0.5) * 2. * f32(w) / f32(max(w, h));
23 | // (i - (i % w)) / w + pos.y:这是为了计算每一行的 y 坐标。
24 | // i - (i % w) 将 i 对齐到当前行的起始索引,然后除以 w 得到行索引,再加上顶点属性中的 y 坐标偏移量 pos.y。
25 | let y = (f32((i - (i % w)) / w + pos.y) / f32(h) - 0.5) * 2. * f32(h) / f32(max(w, h));
26 | return Out(vec4(x, y, 0., 1.), f32(cell));
27 | }
28 |
--------------------------------------------------------------------------------
/proj1_gameOfLife/src/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | html,
7 | body {
8 | margin: 0;
9 | width: 100%;
10 | height: 100%;
11 | background: #000;
12 | color: #fff;
13 | display: flex;
14 | text-align: center;
15 | flex-direction: column;
16 | justify-content: center;
17 | align-items: center;
18 | font-family: Avenir, Helvetica, Arial, sans-serif;
19 | -webkit-font-smoothing: antialiased;
20 | }
21 | p {
22 | font-size: 14px;
23 | margin: 0;
24 | }
25 |
26 | canvas {
27 | width: 60vw;
28 | height: 60vw;
29 | }
30 |
--------------------------------------------------------------------------------
/proj1_gameOfLife/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"],
19 | "typeRoots": ["./node_modules/@webgpu/types", "./node_modules/@types"]
20 | },
21 | "include": ["src"]
22 | }
23 |
--------------------------------------------------------------------------------
/proj2_firework/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/proj2_firework/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/proj2_firework/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@types/dat.gui": "^0.7.10",
13 | "@webgpu/types": "^0.1.34",
14 | "typescript": "^5.0.4",
15 | "vite": "^4.3.2"
16 | },
17 | "dependencies": {
18 | "dat.gui": "^0.7.9",
19 | "wgpu-matrix": "^2.5.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/proj2_firework/src/helper/gpuBuffer.ts:
--------------------------------------------------------------------------------
1 | // 创建顶点缓冲区 VBO
2 | // 获取一块状态为映射了的显存,以及一个对应的 arrayBuffer 对象来写数据
3 | /**
4 | * 应用程序可以请求映射一个 GPUBuffer,这样它们就可以通过代表 GPUBuffer 分配的部分的 arraybuffer 访问它的内容。
5 | * 映射一个 GPUBuffer 是通过 mapAsync() 异步请求的,这样用户代理可以确保 GPU 在应用程序访问它的内容之前完成了对 GPUBuffer 的使用。
6 | * 映射的 GPUBuffer 不能被 GPU 使用,必须使用 unmap() 解除映射,然后才能将使用它的工作提交到 Queue 时间轴。
7 | * 一旦映射了 GPUBuffer,应用程序就可以通过 getMappedRange 同步请求访问其内容的范围
8 | */
9 | export const CreateGPUBuffer = (
10 | device: GPUDevice,
11 | data: Float32Array,
12 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.VERTEX |
13 | GPUBufferUsage.COPY_DST
14 | ) => {
15 | const buffer = device.createBuffer({
16 | size: data.byteLength,
17 | usage: usageFlag,
18 | mappedAtCreation: true,
19 | });
20 | new Float32Array(buffer.getMappedRange()).set(data);
21 | buffer.unmap();
22 | return buffer;
23 | };
24 |
25 | export const CreateGPUBufferUint = (
26 | device: GPUDevice,
27 | data: Uint32Array,
28 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
29 | GPUBufferUsage.COPY_DST
30 | ) => {
31 | const buffer = device.createBuffer({
32 | size: data.byteLength,
33 | usage: usageFlag,
34 | mappedAtCreation: true,
35 | });
36 | new Uint32Array(buffer.getMappedRange()).set(data);
37 | buffer.unmap();
38 | return buffer;
39 | };
40 |
41 | export const CreateGPUBufferUint16 = (
42 | device: GPUDevice,
43 | data: Uint16Array,
44 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
45 | GPUBufferUsage.COPY_DST
46 | ) => {
47 | const buffer = device.createBuffer({
48 | size: data.byteLength,
49 | usage: usageFlag,
50 | mappedAtCreation: true,
51 | });
52 | new Uint16Array(buffer.getMappedRange()).set(data);
53 | buffer.unmap();
54 | return buffer;
55 | };
56 |
--------------------------------------------------------------------------------
/proj2_firework/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.querySelector("canvas") as HTMLCanvasElement;
10 | canvas.width = window.innerWidth;
11 | canvas.height = window.innerHeight;
12 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
13 | // 请求WebGPU适配器与GPU设备
14 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
15 | const device = await adapter.requestDevice();
16 | const format = navigator.gpu.getPreferredCanvasFormat();
17 | // 配置上下文
18 | context.configure({
19 | device: device,
20 | // 上下文格式
21 | format: format,
22 | // 不透明度
23 | alphaMode: "opaque",
24 | });
25 | return { device, canvas, format, context };
26 | };
27 |
--------------------------------------------------------------------------------
/proj2_firework/src/shader/compute.wgsl:
--------------------------------------------------------------------------------
1 | struct Particle {
2 | position : vec2,
3 | velocity : vec2,
4 | lifetime : f32,
5 | r: f32,
6 | g: f32,
7 | b: f32,
8 | };
9 |
10 | struct ParticleBuffer {
11 | particles : array
12 | };
13 |
14 | @group(0) @binding(0) var particleBuffer: ParticleBuffer;
15 |
16 |
17 | const size = u32(64);
18 | @compute @workgroup_size(size)
19 | fn main(
20 | @builtin(global_invocation_id) GlobalInvocationID : vec3
21 | ) {
22 | // 由于这是一个1维的线程分配(只有x轴),所以只需要使用GlobalInvocationID.x
23 | var index = GlobalInvocationID.x;
24 | var particle = particleBuffer.particles[index];
25 | particle.position += particle.velocity;
26 | particle.velocity *= 0.5;
27 | particle.lifetime = max(0.0, particle.lifetime - 0.005);
28 | if (particle.lifetime <= 0.02) {
29 | particle.position = vec2(0.0, 0.0); // 重置到初始位置
30 | particle.velocity = vec2(0.0, 0.0);
31 | }
32 | particleBuffer.particles[index] = particle;
33 | }
--------------------------------------------------------------------------------
/proj2_firework/src/shader/frag.wgsl:
--------------------------------------------------------------------------------
1 | @fragment
2 | fn main(
3 | @location(0) Color : vec4,
4 | ) -> @location(0) vec4 {
5 | return Color;
6 | }
--------------------------------------------------------------------------------
/proj2_firework/src/shader/vert.wgsl:
--------------------------------------------------------------------------------
1 | struct Particle {
2 | position : vec2,
3 | velocity : vec2,
4 | lifetime : f32,
5 | r: f32,
6 | g: f32,
7 | b: f32,
8 | };
9 |
10 | struct ParticleBuffer {
11 | particles : array
12 | };
13 |
14 | @group(0) @binding(0) var particleBuffer: ParticleBuffer;
15 |
16 | struct VertexOutput {
17 | @builtin(position) Position : vec4,
18 | @location(0) Color : vec4,
19 | };
20 |
21 | @vertex
22 | fn main(
23 | @builtin(vertex_index) index : u32,
24 | ) -> VertexOutput {
25 | var output : VertexOutput;
26 | var particle = particleBuffer.particles[index];
27 | output.Position = vec4(particle.position, 0.0, 1.0);
28 | output.Color = vec4(particle.r, particle.g, particle.b, particle.lifetime);
29 | return output;
30 | }
--------------------------------------------------------------------------------
/proj2_firework/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/proj2_firework/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"],
19 | "typeRoots": ["./node_modules/@webgpu/types", "./node_modules/@types"]
20 | },
21 | "include": ["src"]
22 | }
23 |
--------------------------------------------------------------------------------
/proj2_firework_2/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/proj2_firework_2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/proj2_firework_2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@types/dat.gui": "^0.7.10",
13 | "@types/stats.js": "^0.17.0",
14 | "@webgpu/types": "^0.1.34",
15 | "typescript": "^5.0.4",
16 | "vite": "^4.3.2"
17 | },
18 | "dependencies": {
19 | "dat.gui": "^0.7.9",
20 | "stats.js": "^0.17.0",
21 | "wgpu-matrix": "^2.5.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/proj2_firework_2/src/helper/gpuBuffer.ts:
--------------------------------------------------------------------------------
1 | // 创建顶点缓冲区 VBO
2 | // 获取一块状态为映射了的显存,以及一个对应的 arrayBuffer 对象来写数据
3 | /**
4 | * 应用程序可以请求映射一个 GPUBuffer,这样它们就可以通过代表 GPUBuffer 分配的部分的 arraybuffer 访问它的内容。
5 | * 映射一个 GPUBuffer 是通过 mapAsync() 异步请求的,这样用户代理可以确保 GPU 在应用程序访问它的内容之前完成了对 GPUBuffer 的使用。
6 | * 映射的 GPUBuffer 不能被 GPU 使用,必须使用 unmap() 解除映射,然后才能将使用它的工作提交到 Queue 时间轴。
7 | * 一旦映射了 GPUBuffer,应用程序就可以通过 getMappedRange 同步请求访问其内容的范围
8 | */
9 | export const CreateGPUBuffer = (
10 | device: GPUDevice,
11 | data: Float32Array,
12 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.VERTEX |
13 | GPUBufferUsage.COPY_DST
14 | ) => {
15 | const buffer = device.createBuffer({
16 | size: data.byteLength,
17 | usage: usageFlag,
18 | mappedAtCreation: true,
19 | });
20 | new Float32Array(buffer.getMappedRange()).set(data);
21 | buffer.unmap();
22 | return buffer;
23 | };
24 |
25 | export const CreateGPUBufferUint = (
26 | device: GPUDevice,
27 | data: Uint32Array,
28 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
29 | GPUBufferUsage.COPY_DST
30 | ) => {
31 | const buffer = device.createBuffer({
32 | size: data.byteLength,
33 | usage: usageFlag,
34 | mappedAtCreation: true,
35 | });
36 | new Uint32Array(buffer.getMappedRange()).set(data);
37 | buffer.unmap();
38 | return buffer;
39 | };
40 |
41 | export const CreateGPUBufferUint16 = (
42 | device: GPUDevice,
43 | data: Uint16Array,
44 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
45 | GPUBufferUsage.COPY_DST
46 | ) => {
47 | const buffer = device.createBuffer({
48 | size: data.byteLength,
49 | usage: usageFlag,
50 | mappedAtCreation: true,
51 | });
52 | new Uint16Array(buffer.getMappedRange()).set(data);
53 | buffer.unmap();
54 | return buffer;
55 | };
56 |
--------------------------------------------------------------------------------
/proj2_firework_2/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.querySelector("canvas") as HTMLCanvasElement;
10 | canvas.width = window.innerWidth;
11 | canvas.height = window.innerHeight;
12 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
13 | // 请求WebGPU适配器与GPU设备
14 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
15 | const device = await adapter.requestDevice();
16 | const format = navigator.gpu.getPreferredCanvasFormat();
17 | // 配置上下文
18 | context.configure({
19 | device: device,
20 | // 上下文格式
21 | format: format,
22 | // 不透明度
23 | alphaMode: "opaque",
24 | });
25 | return { device, canvas, format, context };
26 | };
27 |
--------------------------------------------------------------------------------
/proj2_firework_2/src/shader/frag.wgsl:
--------------------------------------------------------------------------------
1 | @fragment
2 | fn main(
3 | @builtin(position) Position : vec4,
4 | @location(0) Color : vec4,
5 | ) -> @location(0) vec4 {
6 | return Color;
7 | }
--------------------------------------------------------------------------------
/proj2_firework_2/src/shader/vert.wgsl:
--------------------------------------------------------------------------------
1 | struct Particle {
2 | position : vec2,
3 | velocity : vec2,
4 | lifetime : f32,
5 | r: f32,
6 | g: f32,
7 | b: f32,
8 | };
9 |
10 | struct ParticleBuffer {
11 | particles : array
12 | };
13 |
14 | @group(0) @binding(0) var particleBuffer: ParticleBuffer;
15 |
16 | struct VertexOutput {
17 | @builtin(position) Position : vec4,
18 | @location(0) Color : vec4,
19 | };
20 |
21 | @vertex
22 | fn main(
23 | @builtin(vertex_index) index : u32,
24 | ) -> VertexOutput {
25 | var output : VertexOutput;
26 | var particle = particleBuffer.particles[index];
27 | output.Position = vec4(particle.position, 0.0, 1.0);
28 | output.Color = vec4(particle.r, particle.g, particle.b, particle.lifetime);
29 | return output;
30 | }
--------------------------------------------------------------------------------
/proj2_firework_2/src/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | html,
7 | body {
8 | margin: 0;
9 | width: 100%;
10 | height: 100%;
11 | background: #000;
12 | color: #fff;
13 | display: flex;
14 | text-align: center;
15 | flex-direction: column;
16 | justify-content: center;
17 | align-items: center;
18 | font-family: Avenir, Helvetica, Arial, sans-serif;
19 | -webkit-font-smoothing: antialiased;
20 | }
21 | p {
22 | font-size: 14px;
23 | margin: 0;
24 | }
25 |
26 | canvas {
27 | width: 60vw;
28 | height: 60vw;
29 | }
30 |
--------------------------------------------------------------------------------
/proj2_firework_2/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"],
19 | "typeRoots": ["./node_modules/@webgpu/types", "./node_modules/@types"]
20 | },
21 | "include": ["src"]
22 | }
23 |
--------------------------------------------------------------------------------
/proj3_imageBlur/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/proj3_imageBlur/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/proj3_imageBlur/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@types/dat.gui": "^0.7.10",
13 | "@webgpu/types": "^0.1.34",
14 | "typescript": "^5.0.4",
15 | "vite": "^4.3.2"
16 | },
17 | "dependencies": {
18 | "dat.gui": "^0.7.9",
19 | "wgpu-matrix": "^2.5.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/proj3_imageBlur/public/zs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyirs/webgpu_study/effbf26b3cb71d1c05cb6f7ed77aafcaad35d3e9/proj3_imageBlur/public/zs.png
--------------------------------------------------------------------------------
/proj3_imageBlur/src/helper/gpuBuffer.ts:
--------------------------------------------------------------------------------
1 | // 创建顶点缓冲区 VBO
2 | // 获取一块状态为映射了的显存,以及一个对应的 arrayBuffer 对象来写数据
3 | /**
4 | * 应用程序可以请求映射一个 GPUBuffer,这样它们就可以通过代表 GPUBuffer 分配的部分的 arraybuffer 访问它的内容。
5 | * 映射一个 GPUBuffer 是通过 mapAsync() 异步请求的,这样用户代理可以确保 GPU 在应用程序访问它的内容之前完成了对 GPUBuffer 的使用。
6 | * 映射的 GPUBuffer 不能被 GPU 使用,必须使用 unmap() 解除映射,然后才能将使用它的工作提交到 Queue 时间轴。
7 | * 一旦映射了 GPUBuffer,应用程序就可以通过 getMappedRange 同步请求访问其内容的范围
8 | */
9 | export const CreateGPUBuffer = (
10 | device: GPUDevice,
11 | data: Float32Array,
12 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.VERTEX |
13 | GPUBufferUsage.COPY_DST
14 | ) => {
15 | const buffer = device.createBuffer({
16 | size: data.byteLength,
17 | usage: usageFlag,
18 | mappedAtCreation: true,
19 | });
20 | new Float32Array(buffer.getMappedRange()).set(data);
21 | buffer.unmap();
22 | return buffer;
23 | };
24 |
25 | export const CreateGPUBufferUint = (
26 | device: GPUDevice,
27 | data: Uint32Array,
28 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
29 | GPUBufferUsage.COPY_DST
30 | ) => {
31 | const buffer = device.createBuffer({
32 | size: data.byteLength,
33 | usage: usageFlag,
34 | mappedAtCreation: true,
35 | });
36 | new Uint32Array(buffer.getMappedRange()).set(data);
37 | buffer.unmap();
38 | return buffer;
39 | };
40 |
41 | export const CreateGPUBufferUint16 = (
42 | device: GPUDevice,
43 | data: Uint16Array,
44 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
45 | GPUBufferUsage.COPY_DST
46 | ) => {
47 | const buffer = device.createBuffer({
48 | size: data.byteLength,
49 | usage: usageFlag,
50 | mappedAtCreation: true,
51 | });
52 | new Uint16Array(buffer.getMappedRange()).set(data);
53 | buffer.unmap();
54 | return buffer;
55 | };
56 |
--------------------------------------------------------------------------------
/proj3_imageBlur/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.querySelector("canvas") as HTMLCanvasElement;
10 | canvas.width = window.innerWidth;
11 | canvas.height = window.innerHeight;
12 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
13 | // 请求WebGPU适配器与GPU设备
14 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
15 | const device = await adapter.requestDevice();
16 | const format = navigator.gpu.getPreferredCanvasFormat();
17 | // 配置上下文
18 | context.configure({
19 | device: device,
20 | // 上下文格式
21 | format: format,
22 | // 不透明度
23 | alphaMode: "opaque",
24 | });
25 | return { device, canvas, format, context };
26 | };
27 |
--------------------------------------------------------------------------------
/proj3_imageBlur/src/shader/frag.wgsl:
--------------------------------------------------------------------------------
1 | @group(0) @binding(0) var mySampler : sampler;
2 | @group(0) @binding(1) var myTexture : texture_2d;
3 |
4 | @fragment
5 | fn main(@location(0) fragUV : vec2) -> @location(0) vec4 {
6 | return textureSample(myTexture, mySampler, fragUV);
7 | }
8 |
--------------------------------------------------------------------------------
/proj3_imageBlur/src/shader/vert.wgsl:
--------------------------------------------------------------------------------
1 | struct VertexOutput {
2 | @builtin(position) Position : vec4,
3 | @location(0) fragUV : vec2,
4 | }
5 |
6 | @vertex
7 | fn main(@builtin(vertex_index) VertexIndex : u32) -> VertexOutput {
8 | const pos = array(
9 | vec2( 1.0, 1.0),
10 | vec2( 1.0, -1.0),
11 | vec2(-1.0, -1.0),
12 | vec2( 1.0, 1.0),
13 | vec2(-1.0, -1.0),
14 | vec2(-1.0, 1.0),
15 | );
16 |
17 | const uv = array(
18 | vec2(1.0, 0.0),
19 | vec2(1.0, 1.0),
20 | vec2(0.0, 1.0),
21 | vec2(1.0, 0.0),
22 | vec2(0.0, 1.0),
23 | vec2(0.0, 0.0),
24 | );
25 |
26 | var output : VertexOutput;
27 | output.Position = vec4(pos[VertexIndex], 0.0, 1.0);
28 | output.fragUV = uv[VertexIndex];
29 | return output;
30 | }
--------------------------------------------------------------------------------
/proj3_imageBlur/src/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | html,
7 | body {
8 | margin: 0;
9 | width: 100%;
10 | height: 100%;
11 | background: #000;
12 | color: #fff;
13 | display: flex;
14 | text-align: center;
15 | flex-direction: column;
16 | justify-content: center;
17 | align-items: center;
18 | font-family: Avenir, Helvetica, Arial, sans-serif;
19 | -webkit-font-smoothing: antialiased;
20 | }
21 | p {
22 | font-size: 14px;
23 | margin: 0;
24 | }
25 |
26 | canvas {
27 | width: 60vw;
28 | height: 60vw;
29 | }
30 |
--------------------------------------------------------------------------------
/proj3_imageBlur/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"],
19 | "typeRoots": ["./node_modules/@webgpu/types", "./node_modules/@types"]
20 | },
21 | "include": ["src"]
22 | }
23 |
--------------------------------------------------------------------------------
/proj3_imageBlur_Gaussian/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/proj3_imageBlur_Gaussian/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/proj3_imageBlur_Gaussian/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@types/dat.gui": "^0.7.10",
13 | "@webgpu/types": "^0.1.34",
14 | "typescript": "^5.0.4",
15 | "vite": "^4.3.2"
16 | },
17 | "dependencies": {
18 | "dat.gui": "^0.7.9",
19 | "wgpu-matrix": "^2.5.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/proj3_imageBlur_Gaussian/public/zs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyirs/webgpu_study/effbf26b3cb71d1c05cb6f7ed77aafcaad35d3e9/proj3_imageBlur_Gaussian/public/zs.png
--------------------------------------------------------------------------------
/proj3_imageBlur_Gaussian/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.querySelector("canvas") as HTMLCanvasElement;
10 | canvas.width = 256;
11 | canvas.height = 256;
12 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
13 | // 请求WebGPU适配器与GPU设备
14 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
15 | const device = await adapter.requestDevice();
16 | const format = navigator.gpu.getPreferredCanvasFormat();
17 | // 配置上下文
18 | context.configure({
19 | device: device,
20 | // 上下文格式
21 | format: format,
22 | // 不透明度
23 | alphaMode: "opaque",
24 | });
25 | return { device, canvas, format, context };
26 | };
27 |
--------------------------------------------------------------------------------
/proj3_imageBlur_Gaussian/src/shader/frag.wgsl:
--------------------------------------------------------------------------------
1 | // 首先将纹理的颜色从 RGB 转换到 YUV 空间,然后对亮度(Y 分量)应用高斯模糊,最后将模糊后的亮度值用于输出颜色的 RGB 分量。
2 | // 这种方法特别适用于灰度图像或者只关注亮度变化的场景。
3 |
4 | @group(0) @binding(0) var rgb2yuv : mat3x3; // 注意缓冲区
5 | @group(0) @binding(1) var gaussian : array,3>; // 注意缓冲区
6 | @group(0) @binding(2) var kernel_offsets : array,9>;
7 | @group(0) @binding(3) var mySampler : sampler;
8 | @group(0) @binding(4) var myTexture : texture_2d;
9 |
10 | struct VertexOutput {
11 | @builtin(position) Position: vec4,
12 | @location(0) fragUV: vec2,
13 | }
14 |
15 | @fragment
16 | fn main(input: VertexOutput) -> @location(0) vec4 {
17 | var val = 0.0;
18 | for (var i = 0u; i < 3; i++) {
19 | // 将采样得到的 RGB 颜色转换为 YUV 颜色空间,并提取出 Y 分量(亮度)
20 | let a = vec3f(
21 | (rgb2yuv * textureSample(myTexture, mySampler, input.fragUV + kernel_offsets[i * 3].xy).xyz).x,
22 | (rgb2yuv * textureSample(myTexture, mySampler, input.fragUV + kernel_offsets[i * 3 + 1].xy).xyz).x,
23 | (rgb2yuv * textureSample(myTexture, mySampler, input.fragUV + kernel_offsets[i * 3 + 2].xy).xyz).x
24 | );
25 | val += dot(a, gaussian[i]);
26 | }
27 | return vec4(val, val, val, 1.0);
28 | }
29 |
--------------------------------------------------------------------------------
/proj3_imageBlur_Gaussian/src/shader/vert.wgsl:
--------------------------------------------------------------------------------
1 | struct VertexOutput {
2 | @builtin(position) Position: vec4,
3 | @location(0) fragUV: vec2,
4 | }
5 |
6 | @vertex
7 | fn main(@location(0) pos: vec2) -> VertexOutput {
8 | var output: VertexOutput;
9 | output.Position = vec4(pos, 0.0, 1.0);
10 | output.fragUV = pos * 0.5 + 0.5;
11 | return output;
12 | }
--------------------------------------------------------------------------------
/proj3_imageBlur_Gaussian/src/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | html,
7 | body {
8 | margin: 0;
9 | width: 100%;
10 | height: 100%;
11 | background: #000;
12 | color: #fff;
13 | display: flex;
14 | text-align: center;
15 | flex-direction: column;
16 | justify-content: center;
17 | align-items: center;
18 | font-family: Avenir, Helvetica, Arial, sans-serif;
19 | -webkit-font-smoothing: antialiased;
20 | }
21 | p {
22 | font-size: 14px;
23 | margin: 0;
24 | }
25 |
--------------------------------------------------------------------------------
/proj3_imageBlur_Gaussian/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"],
19 | "typeRoots": ["./node_modules/@webgpu/types", "./node_modules/@types"]
20 | },
21 | "include": ["src"]
22 | }
23 |
--------------------------------------------------------------------------------
/proj4_galaxy/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/proj4_galaxy/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/proj4_galaxy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@types/dat.gui": "^0.7.10",
13 | "@webgpu/types": "^0.1.34",
14 | "typescript": "^5.0.4",
15 | "vite": "^4.3.2"
16 | },
17 | "dependencies": {
18 | "dat.gui": "^0.7.9",
19 | "wgpu-matrix": "^2.5.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/proj4_galaxy/src/helper/color.ts:
--------------------------------------------------------------------------------
1 | export class Color {
2 | r: number;
3 | g: number;
4 | b: number;
5 | constructor(hex: string);
6 | constructor(r: number, g: number, b: number);
7 | constructor(r: string | number, g?: number, b?: number) {
8 | if (typeof r === "string") {
9 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(r);
10 | if (result) {
11 | this.r = parseInt(result[1], 16) / 255.0;
12 | this.g = parseInt(result[2], 16) / 255.0;
13 | this.b = parseInt(result[3], 16) / 255.0;
14 | } else {
15 | throw new Error("Invalid color format. Use hex format: #RRGGBB");
16 | }
17 | } else {
18 | if (g === undefined || b === undefined) {
19 | throw new Error("Invalid arguments.");
20 | }
21 |
22 | this.r = r;
23 | this.g = g;
24 | this.b = b;
25 | }
26 | }
27 |
28 | clone() {
29 | return new Color(this.r, this.g, this.b);
30 | }
31 |
32 | lerp(targetColor: Color, alpha: number) {
33 | this.r += (targetColor.r - this.r) * alpha;
34 | this.g += (targetColor.g - this.g) * alpha;
35 | this.b += (targetColor.b - this.b) * alpha;
36 | return this;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/proj4_galaxy/src/helper/gpuBuffer.ts:
--------------------------------------------------------------------------------
1 | // 创建顶点缓冲区 VBO
2 | // 获取一块状态为映射了的显存,以及一个对应的 arrayBuffer 对象来写数据
3 | /**
4 | * 应用程序可以请求映射一个 GPUBuffer,这样它们就可以通过代表 GPUBuffer 分配的部分的 arraybuffer 访问它的内容。
5 | * 映射一个 GPUBuffer 是通过 mapAsync() 异步请求的,这样用户代理可以确保 GPU 在应用程序访问它的内容之前完成了对 GPUBuffer 的使用。
6 | * 映射的 GPUBuffer 不能被 GPU 使用,必须使用 unmap() 解除映射,然后才能将使用它的工作提交到 Queue 时间轴。
7 | * 一旦映射了 GPUBuffer,应用程序就可以通过 getMappedRange 同步请求访问其内容的范围
8 | */
9 | export const CreateGPUBuffer = (
10 | device: GPUDevice,
11 | data: Float32Array,
12 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.VERTEX |
13 | GPUBufferUsage.COPY_DST
14 | ) => {
15 | const buffer = device.createBuffer({
16 | size: data.byteLength,
17 | usage: usageFlag,
18 | mappedAtCreation: true,
19 | });
20 | new Float32Array(buffer.getMappedRange()).set(data);
21 | buffer.unmap();
22 | return buffer;
23 | };
24 |
25 | export const CreateGPUBufferUint = (
26 | device: GPUDevice,
27 | data: Uint32Array,
28 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
29 | GPUBufferUsage.COPY_DST
30 | ) => {
31 | const buffer = device.createBuffer({
32 | size: data.byteLength,
33 | usage: usageFlag,
34 | mappedAtCreation: true,
35 | });
36 | new Uint32Array(buffer.getMappedRange()).set(data);
37 | buffer.unmap();
38 | return buffer;
39 | };
40 |
41 | export const CreateGPUBufferUint16 = (
42 | device: GPUDevice,
43 | data: Uint16Array,
44 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
45 | GPUBufferUsage.COPY_DST
46 | ) => {
47 | const buffer = device.createBuffer({
48 | size: data.byteLength,
49 | usage: usageFlag,
50 | mappedAtCreation: true,
51 | });
52 | new Uint16Array(buffer.getMappedRange()).set(data);
53 | buffer.unmap();
54 | return buffer;
55 | };
56 |
--------------------------------------------------------------------------------
/proj4_galaxy/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.querySelector("canvas") as HTMLCanvasElement;
10 | canvas.width = window.innerWidth;
11 | canvas.height = window.innerHeight;
12 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
13 | // 请求WebGPU适配器与GPU设备
14 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
15 | const device = await adapter.requestDevice();
16 | const format = navigator.gpu.getPreferredCanvasFormat();
17 | // 配置上下文
18 | context.configure({
19 | device: device,
20 | // 上下文格式
21 | format: format,
22 | // 不透明度
23 | alphaMode: "opaque",
24 | });
25 | return { device, canvas, format, context };
26 | };
27 |
--------------------------------------------------------------------------------
/proj4_galaxy/src/shader/compute.wgsl:
--------------------------------------------------------------------------------
1 | struct Particle {
2 | position : vec3,
3 | r: f32,
4 | g: f32,
5 | b: f32,
6 | pad : vec2
7 | };
8 |
9 | struct ParticleBuffer {
10 | particles : array
11 | };
12 |
13 | @group(0) @binding(0) var particleBuffer: ParticleBuffer;
14 |
15 |
16 | const size = u32(64);
17 | @compute @workgroup_size(size)
18 | fn main(
19 | @builtin(global_invocation_id) GlobalInvocationID : vec3
20 | ) {
21 | // 由于这是一个1维的线程分配(只有x轴),所以只需要使用GlobalInvocationID.x
22 | var index = GlobalInvocationID.x;
23 | var particle = particleBuffer.particles[index];
24 | particleBuffer.particles[index] = particle;
25 | }
--------------------------------------------------------------------------------
/proj4_galaxy/src/shader/frag.wgsl:
--------------------------------------------------------------------------------
1 | @fragment
2 | fn main(
3 | @location(0) Color : vec4,
4 | ) -> @location(0) vec4 {
5 | return Color;
6 | }
--------------------------------------------------------------------------------
/proj4_galaxy/src/shader/vert.wgsl:
--------------------------------------------------------------------------------
1 | struct Particle {
2 | position : vec3,
3 | r: f32,
4 | g: f32,
5 | b: f32,
6 | pad : vec2
7 | };
8 |
9 | struct ParticleBuffer {
10 | particles : array
11 | };
12 |
13 | struct Uniforms {
14 | modelViewProjectionMatrix : mat4x4,
15 | }
16 |
17 | @group(0) @binding(0) var particleBuffer: ParticleBuffer;
18 | @group(1) @binding(0) var uniforms : Uniforms;
19 |
20 |
21 | struct VertexOutput {
22 | @builtin(position) Position : vec4,
23 | @location(0) Color : vec4,
24 | };
25 |
26 | @vertex
27 | fn main(
28 | @builtin(vertex_index) index : u32,
29 | ) -> VertexOutput {
30 | var output : VertexOutput;
31 | var particle = particleBuffer.particles[index];
32 | output.Position = uniforms.modelViewProjectionMatrix * vec4(particle.position, 1.0);
33 | output.Color = vec4(particle.r, particle.g, particle.b, 1.0);
34 | return output;
35 | }
--------------------------------------------------------------------------------
/proj4_galaxy/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/proj4_galaxy/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"],
19 | "typeRoots": ["./node_modules/@webgpu/types", "./node_modules/@types"]
20 | },
21 | "include": ["src"]
22 | }
23 |
--------------------------------------------------------------------------------
/vol0_triangle/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol0_triangle/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/vol0_triangle/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/vol0_triangle/src/shader/frag.wgsl:
--------------------------------------------------------------------------------
1 | @fragment
2 | fn main() -> @location(0) vec4 {
3 | return vec4(1.0, 0.0, 0.0, 1.0);
4 | }
--------------------------------------------------------------------------------
/vol0_triangle/src/shader/vert.wgsl:
--------------------------------------------------------------------------------
1 | @vertex
2 | fn main(
3 | @builtin(vertex_index) vertexIndex: u32,
4 | ) -> @builtin(position) vec4 {
5 | // 设置三角形顶点坐标
6 | var pos = array, 3>(
7 | vec2(0.0, 0.5),
8 | vec2(-0.5, -0.5),
9 | vec2(0.5, -0.5),
10 | );
11 | // 返回顶点坐标
12 | return vec4(pos[vertexIndex], 0.0, 1.0);
13 | }
--------------------------------------------------------------------------------
/vol0_triangle/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/vol0_triangle/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"],
21 | }
22 |
--------------------------------------------------------------------------------
/vol10_renderBundles/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol10_renderBundles/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 💡 **命令束** 💡
4 |
5 |
6 | passEncoder.executeBundles 是 WebGPU API 中的一个方法,它允许你执行预先录制的命令束(bundles)。
7 |
8 | 命令束是一组预先录制的渲染命令,这些命令可以在多个渲染通道中重复使用。
9 |
10 | - 减少 CPU 与 GPU 之间的通信:当你录制一个命令束,你实际上是在 CPU 上预先组织和优化一组命令,然后在需要时发送给 GPU。这减少了每帧都重新组织和发送命令的开销。
11 | - 命令重用:如果在多个渲染通道或多个帧中有相同的命令序列,你可以简单地重复使用同一个命令束,而不是每次都重新录制这些命令。
12 | - 并行录制:在某些实现中,命令束可以在多个线程上并行录制,从而利用多核 CPU 的优势。
13 | - 状态设置优化:由于命令束是预先录制的,某些实现可能会对状态设置进行优化,例如合并连续的状态设置命令或消除不必要的状态更改。
14 |
15 |
16 |
17 | device.createRenderBundleEncoder 是 WebGPU API 的一部分,它允许开发者创建一个 GPURenderBundleEncoder 对象。
18 |
19 | 这个对象可以预先录制渲染命令,然后在渲染过程中快速重复执行这些命令,而不需要每帧重新编码它们。这种方法可以提高渲染性能,特别是当有大量重复的渲染命令时。
20 |
21 | ```
22 | const renderBundleEncoder = device.createRenderBundleEncoder(descriptor);
23 | ```
24 |
25 | - descriptor: 一个对象,描述了渲染束编码器的配置。它包括以下属性:
26 |
27 | - colorFormats: 一个数组,列出了渲染目标的颜色格式。
28 | - depthStencilFormat (可选): 深度/模板附件的格式。
29 | - sampleCount (可选): 多重采样的数量,默认为 1。
30 |
31 | 1.创建渲染束编码器:
32 |
33 | ```
34 | const renderBundleEncoder = device.createRenderBundleEncoder({
35 | colorFormats: ['rgba8unorm'],
36 | depthStencilFormat: 'depth24plus',
37 | });
38 | ```
39 |
40 | 2.编码渲染命令:
41 |
42 | 使用渲染束编码器的方法(如 setPipeline, setVertexBuffer 等)来编码渲染命令。
43 |
44 | ```
45 | renderBundleEncoder.setPipeline(pipeline);
46 | renderBundleEncoder.setVertexBuffer(0, vertexBuffer);
47 | // ... 其他渲染命令
48 | ```
49 |
50 | 3.完成渲染束:
51 |
52 | ```
53 | const renderBundle = renderBundleEncoder.finish();
54 | ```
55 |
56 | 4.在渲染过程中使用渲染束:
57 |
58 | 在渲染过程中,使用 executeBundles 方法执行预先录制的渲染束。
59 |
60 | ```
61 | renderPassEncoder.executeBundles([renderBundle]);
62 | ```
63 |
--------------------------------------------------------------------------------
/vol10_renderBundles/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/vol10_renderBundles/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@types/dat.gui": "^0.7.10",
13 | "@webgpu/types": "^0.1.34",
14 | "typescript": "^5.0.4",
15 | "vite": "^4.3.2"
16 | },
17 | "dependencies": {
18 | "dat.gui": "^0.7.9",
19 | "wgpu-matrix": "^2.5.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/vol10_renderBundles/public/moon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyirs/webgpu_study/effbf26b3cb71d1c05cb6f7ed77aafcaad35d3e9/vol10_renderBundles/public/moon.jpg
--------------------------------------------------------------------------------
/vol10_renderBundles/public/saturn.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyirs/webgpu_study/effbf26b3cb71d1c05cb6f7ed77aafcaad35d3e9/vol10_renderBundles/public/saturn.jpg
--------------------------------------------------------------------------------
/vol10_renderBundles/src/helper/color.ts:
--------------------------------------------------------------------------------
1 | export class Color {
2 | r: number;
3 | g: number;
4 | b: number;
5 | constructor(hex: string);
6 | constructor(r: number, g: number, b: number);
7 | constructor(r: string | number, g?: number, b?: number) {
8 | if (typeof r === "string") {
9 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(r);
10 | if (result) {
11 | this.r = parseInt(result[1], 16) / 255.0;
12 | this.g = parseInt(result[2], 16) / 255.0;
13 | this.b = parseInt(result[3], 16) / 255.0;
14 | } else {
15 | throw new Error("Invalid color format. Use hex format: #RRGGBB");
16 | }
17 | } else {
18 | if (g === undefined || b === undefined) {
19 | throw new Error("Invalid arguments.");
20 | }
21 |
22 | this.r = r;
23 | this.g = g;
24 | this.b = b;
25 | }
26 | }
27 |
28 | clone() {
29 | return new Color(this.r, this.g, this.b);
30 | }
31 |
32 | lerp(targetColor: Color, alpha: number) {
33 | this.r += (targetColor.r - this.r) * alpha;
34 | this.g += (targetColor.g - this.g) * alpha;
35 | this.b += (targetColor.b - this.b) * alpha;
36 | return this;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/vol10_renderBundles/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.querySelector("canvas") as HTMLCanvasElement;
10 | canvas.width = window.innerWidth;
11 | canvas.height = window.innerHeight;
12 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
13 | // 请求WebGPU适配器与GPU设备
14 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
15 | const device = await adapter.requestDevice();
16 | const format = navigator.gpu.getPreferredCanvasFormat();
17 | // 配置上下文
18 | context.configure({
19 | device: device,
20 | // 上下文格式
21 | format: format,
22 | // 不透明度
23 | alphaMode: "opaque",
24 | });
25 | return { device, canvas, format, context };
26 | };
27 |
--------------------------------------------------------------------------------
/vol10_renderBundles/src/helper/texture.ts:
--------------------------------------------------------------------------------
1 | export const CreateTextureFromImage = async (
2 | device: GPUDevice,
3 | imageSrc: string
4 | ) => {
5 | let texture: GPUTexture;
6 | // const response = await fetch(new URL(imageSrc, import.meta.url).toString());
7 | // const imageBitmap = await createImageBitmap(await response.blob());
8 | const image = new Image();
9 | image.src = imageSrc;
10 | await image.decode();
11 | const imageBitmap = await createImageBitmap(image);
12 | texture = device.createTexture({
13 | size: [imageBitmap.width, imageBitmap.height, 1],
14 | format: "rgba8unorm",
15 | usage:
16 | GPUTextureUsage.TEXTURE_BINDING |
17 | GPUTextureUsage.COPY_DST |
18 | GPUTextureUsage.RENDER_ATTACHMENT,
19 | });
20 | device.queue.copyExternalImageToTexture(
21 | { source: imageBitmap },
22 | { texture: texture },
23 | [imageBitmap.width, imageBitmap.height]
24 | );
25 | return texture;
26 | };
27 |
--------------------------------------------------------------------------------
/vol10_renderBundles/src/shader/frag.wgsl:
--------------------------------------------------------------------------------
1 | @group(1) @binding(1) var meshSampler: sampler;
2 | @group(1) @binding(2) var meshTexture: texture_2d;
3 |
4 | struct VertexOutput {
5 | @builtin(position) position: vec4f,
6 | @location(0) normal: vec3f,
7 | @location(1) uv: vec2f,
8 | }
9 |
10 | // Static directional lighting
11 | const lightDir = vec3f(1, 1, 1);
12 | const dirColor = vec3(1);
13 | const ambientColor = vec3f(0.05);
14 |
15 | @fragment
16 | fn main(input: VertexOutput) -> @location(0) vec4f {
17 | let textureColor = textureSample(meshTexture, meshSampler, input.uv);
18 | // Very simplified lighting algorithm.
19 | let lightColor = saturate(ambientColor + max(dot(input.normal, lightDir), 0.0) * dirColor);
20 | return vec4f(textureColor.rgb * lightColor, textureColor.a);
21 | }
--------------------------------------------------------------------------------
/vol10_renderBundles/src/shader/vert.wgsl:
--------------------------------------------------------------------------------
1 | struct Uniforms {
2 | viewProjectionMatrix: mat4x4f
3 | }
4 | @group(0) @binding(0) var uniforms : Uniforms;
5 | @group(1) @binding(0) var modelMatrix : mat4x4f;
6 |
7 | struct VertexInput {
8 | @location(0) position: vec4f,
9 | @location(1) normal: vec3f,
10 | @location(2) uv: vec2f
11 | }
12 |
13 | struct VertexOutput {
14 | @builtin(position) position: vec4f,
15 | @location(0) normal: vec3f,
16 | @location(1) uv: vec2f,
17 | }
18 |
19 | @vertex
20 | fn main(input: VertexInput) -> VertexOutput {
21 | var output: VertexOutput;
22 | output.position = uniforms.viewProjectionMatrix * modelMatrix * input.position;
23 | output.normal = normalize((modelMatrix * vec4(input.normal, 0)).xyz);
24 | output.uv = input.uv;
25 | return output;
26 | }
--------------------------------------------------------------------------------
/vol10_renderBundles/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/vol10_renderBundles/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"],
19 | "typeRoots": ["./node_modules/@webgpu/types", "./node_modules/@types"]
20 | },
21 | "include": ["src"]
22 | }
23 |
--------------------------------------------------------------------------------
/vol11_glb/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol11_glb/README.md:
--------------------------------------------------------------------------------
1 | [参考代码](https://github.com/Twinklebear/webgpu-gltf)
2 |
3 | ## materials
4 |
5 | 在没有任何扩展的情况下,glTf 仅支持一种材质,即 pbrMetallicRoughness 材质模型,这是一种物理渲染模型,通过表面金属度和粗糙度进行描述,还可以定义表面基本颜色和反射率,以及法线贴图,遮挡贴图,以及其他一些属性控制几何形状和混合状态。完整的属性:
6 |
7 | ```
8 | "materials": [{
9 | "pbrMetallicRoughness": {
10 | "baseColorTexture": { "index": 1 },
11 | "baseColorFactor": [ 1.0, 0.75, 0.35, 1.0 ],
12 | "metallicRoughnessTexture": { "index": 5 },
13 | "metallicFactor": 1.0,
14 | "roughnessFactor": 0.0
15 | },
16 | "normalTexture": { "index": 2 },
17 | "occlusionTexture": {
18 | "index": 4,
19 | "strength": 0.9
20 | },
21 | "emissiveTexture": { "index": 3 },
22 | "emissiveFactor": [0.4, 0.8, 0.6],
23 | "alphaMode": "OPAQUE",
24 | "doubleSided": true,
25 | }]
26 | ```
27 |
--------------------------------------------------------------------------------
/vol11_glb/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/vol11_glb/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol11_glb/public/Buggy.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyirs/webgpu_study/effbf26b3cb71d1c05cb6f7ed77aafcaad35d3e9/vol11_glb/public/Buggy.glb
--------------------------------------------------------------------------------
/vol11_glb/public/DamagedHelmet.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyirs/webgpu_study/effbf26b3cb71d1c05cb6f7ed77aafcaad35d3e9/vol11_glb/public/DamagedHelmet.glb
--------------------------------------------------------------------------------
/vol11_glb/src/glb/glb_accessor.ts:
--------------------------------------------------------------------------------
1 | import { gltfTypeNumComponents, gltfTypeSize } from "./glb_tool";
2 | import { GLTFBufferView } from "./glb_viewbuffer";
3 |
4 | // 访问GLB文件中的顶点、索引等数据。
5 | export class GLTFAccessor {
6 | count: number;
7 | componentType: GLTFComponentType;
8 | gltfType: string;
9 | numComponents: number;
10 | numScalars: number;
11 | view: GLTFBufferView;
12 | byteOffset: number;
13 | constructor(view: GLTFBufferView, accessor: IAccessor) {
14 | this.count = accessor.count;
15 | this.componentType = accessor.componentType;
16 | this.gltfType = accessor.type;
17 | this.numComponents = gltfTypeNumComponents(accessor["type"])!;
18 | this.numScalars = this.count * this.numComponents;
19 | this.view = view;
20 | this.byteOffset = 0;
21 | if (accessor.byteOffset !== undefined) {
22 | this.byteOffset = accessor.byteOffset;
23 | }
24 | }
25 |
26 | get byteStride() {
27 | let elementSize = gltfTypeSize(this.componentType, this.gltfType);
28 | return Math.max(elementSize, this.view.byteStride);
29 | }
30 |
31 | get byteLength() {
32 | return this.count * this.byteStride;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/vol11_glb/src/glb/glb_mesh.ts:
--------------------------------------------------------------------------------
1 | import { GLTFPrimitive } from "./glb_primitive";
2 |
3 | export class GLTFMesh {
4 | name: string;
5 | primitives: GLTFPrimitive[];
6 | constructor(name: string, primitives: GLTFPrimitive[]) {
7 | this.name = name;
8 | this.primitives = primitives;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/vol11_glb/src/glb/glb_model.ts:
--------------------------------------------------------------------------------
1 | import { GLTFNode } from "./glb_node";
2 | import { GLBShaderCache } from "./glb_shader_cache";
3 |
4 | export class GLBModel {
5 | nodes: GLTFNode[];
6 | constructor(nodes: GLTFNode[]) {
7 | this.nodes = nodes;
8 | }
9 |
10 | buildRenderBundles(
11 | device: GPUDevice,
12 | shaderCache: GLBShaderCache,
13 | viewParamsLayout: GPUBindGroupLayout,
14 | viewParamsBindGroup: GPUBindGroup | null,
15 | swapChainFormat: GPUTextureFormat,
16 | depthFormat: GPUTextureFormat
17 | ) {
18 | let renderBundles = [];
19 | for (let i = 0; i < this.nodes.length; ++i) {
20 | let n = this.nodes[i];
21 | let bundle = n.buildRenderBundle(
22 | device,
23 | shaderCache,
24 | viewParamsLayout,
25 | viewParamsBindGroup,
26 | swapChainFormat,
27 | depthFormat
28 | );
29 | renderBundles.push(bundle);
30 | }
31 | return renderBundles;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/vol11_glb/src/glb/glb_sampler.ts:
--------------------------------------------------------------------------------
1 | import { GLTFTextureFilter } from "./glb_tool";
2 |
3 | export class GLTFSampler {
4 | sampler: GPUSampler;
5 | constructor(sampler: IGLTFSampler, device: GPUDevice) {
6 | let magFilter: GPUFilterMode =
7 | sampler.magFilter === undefined ||
8 | sampler.magFilter == GLTFTextureFilter.LINEAR
9 | ? "linear"
10 | : "nearest";
11 | let minFilter: GPUFilterMode =
12 | sampler.minFilter === undefined ||
13 | sampler.minFilter == GLTFTextureFilter.LINEAR
14 | ? "linear"
15 | : "nearest";
16 | let wrapS: GPUAddressMode = "repeat";
17 | if (sampler.wrapS !== undefined) {
18 | if (sampler.wrapS == GLTFTextureFilter.REPEAT) {
19 | wrapS = "repeat";
20 | } else if (sampler.wrapS == GLTFTextureFilter.CLAMP_TO_EDGE) {
21 | wrapS = "clamp-to-edge";
22 | } else {
23 | wrapS = "mirror-repeat";
24 | }
25 | }
26 | let wrapT: GPUAddressMode = "repeat";
27 | if (sampler.wrapT !== undefined) {
28 | if (sampler.wrapT == GLTFTextureFilter.REPEAT) {
29 | wrapT = "repeat";
30 | } else if (sampler.wrapT == GLTFTextureFilter.CLAMP_TO_EDGE) {
31 | wrapT = "clamp-to-edge";
32 | } else {
33 | wrapT = "mirror-repeat";
34 | }
35 | }
36 | this.sampler = device.createSampler({
37 | magFilter: magFilter,
38 | minFilter: minFilter,
39 | addressModeU: wrapS,
40 | addressModeV: wrapT,
41 | mipmapFilter: "linear",
42 | });
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/vol11_glb/src/glb/glb_texture.ts:
--------------------------------------------------------------------------------
1 | import { GLTFSampler } from "./glb_sampler";
2 |
3 | // GLTFTexture和GLTFSampler类 处理GLB文件中的纹理和采样器,包括纹理的创建和配置
4 | export class GLTFTexture {
5 | gltfsampler: GLTFSampler;
6 | sampler: GPUSampler;
7 | image: GPUTexture;
8 | imageView: GPUTextureView;
9 | constructor(sampler: GLTFSampler, image: GPUTexture) {
10 | this.gltfsampler = sampler;
11 | this.sampler = sampler.sampler;
12 | this.image = image;
13 | this.imageView = image.createView();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/vol11_glb/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/vol11_glb/src/types/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.glb" {
2 | const src: string;
3 | export default src;
4 | }
5 |
--------------------------------------------------------------------------------
/vol11_glb/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"]
21 | }
22 |
--------------------------------------------------------------------------------
/vol11_glb/vite.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | assetsInclude: ["**/*.glb"],
3 | };
4 |
--------------------------------------------------------------------------------
/vol11_glb_simple/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol11_glb_simple/README.md:
--------------------------------------------------------------------------------
1 | [参考代码](https://github.com/Twinklebear/webgpu-gltf)
2 |
3 | ## materials
4 |
5 | 在没有任何扩展的情况下,glTf 仅支持一种材质,即 pbrMetallicRoughness 材质模型,这是一种物理渲染模型,通过表面金属度和粗糙度进行描述,还可以定义表面基本颜色和反射率,以及法线贴图,遮挡贴图,以及其他一些属性控制几何形状和混合状态。完整的属性:
6 |
7 | ```
8 | "materials": [{
9 | "pbrMetallicRoughness": {
10 | "baseColorTexture": { "index": 1 },
11 | "baseColorFactor": [ 1.0, 0.75, 0.35, 1.0 ],
12 | "metallicRoughnessTexture": { "index": 5 },
13 | "metallicFactor": 1.0,
14 | "roughnessFactor": 0.0
15 | },
16 | "normalTexture": { "index": 2 },
17 | "occlusionTexture": {
18 | "index": 4,
19 | "strength": 0.9
20 | },
21 | "emissiveTexture": { "index": 3 },
22 | "emissiveFactor": [0.4, 0.8, 0.6],
23 | "alphaMode": "OPAQUE",
24 | "doubleSided": true,
25 | }]
26 | ```
27 |
--------------------------------------------------------------------------------
/vol11_glb_simple/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/vol11_glb_simple/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol11_glb_simple/public/Buggy.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyirs/webgpu_study/effbf26b3cb71d1c05cb6f7ed77aafcaad35d3e9/vol11_glb_simple/public/Buggy.glb
--------------------------------------------------------------------------------
/vol11_glb_simple/public/DamagedHelmet.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyirs/webgpu_study/effbf26b3cb71d1c05cb6f7ed77aafcaad35d3e9/vol11_glb_simple/public/DamagedHelmet.glb
--------------------------------------------------------------------------------
/vol11_glb_simple/src/glb/glb_accessor.ts:
--------------------------------------------------------------------------------
1 | import { gltfTypeNumComponents, gltfTypeSize } from "./glb_tool";
2 | import { GLTFBufferView } from "./glb_viewbuffer";
3 |
4 | // 访问GLB文件中的顶点、索引等数据。
5 | export class GLTFAccessor {
6 | count: number;
7 | componentType: GLTFComponentType;
8 | gltfType: string;
9 | numComponents: number;
10 | numScalars: number;
11 | view: GLTFBufferView;
12 | byteOffset: number;
13 | constructor(view: GLTFBufferView, accessor: IAccessor) {
14 | this.count = accessor.count;
15 | this.componentType = accessor.componentType;
16 | this.gltfType = accessor.type;
17 | this.numComponents = gltfTypeNumComponents(accessor["type"])!;
18 | this.numScalars = this.count * this.numComponents;
19 | this.view = view;
20 | this.byteOffset = 0;
21 | if (accessor.byteOffset !== undefined) {
22 | this.byteOffset = accessor.byteOffset;
23 | }
24 | }
25 |
26 | get byteStride() {
27 | let elementSize = gltfTypeSize(this.componentType, this.gltfType);
28 | return Math.max(elementSize, this.view.byteStride);
29 | }
30 |
31 | get byteLength() {
32 | return this.count * this.byteStride;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/vol11_glb_simple/src/glb/glb_mesh.ts:
--------------------------------------------------------------------------------
1 | import { GLTFPrimitive } from "./glb_primitive";
2 |
3 | export class GLTFMesh {
4 | name: string;
5 | primitives: GLTFPrimitive[];
6 | constructor(name: string, primitives: GLTFPrimitive[]) {
7 | this.name = name;
8 | this.primitives = primitives;
9 | }
10 |
11 | render(renderPassEncoder: GPURenderPassEncoder) {
12 | for (let prim of this.primitives) {
13 | prim.render(renderPassEncoder);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/vol11_glb_simple/src/glb/glb_model.ts:
--------------------------------------------------------------------------------
1 | import { GLTFNode } from "./glb_node";
2 |
3 | export class GLBModel {
4 | nodes: GLTFNode[];
5 | constructor(nodes: GLTFNode[]) {
6 | this.nodes = nodes;
7 | }
8 |
9 | buildRenderPipeline(
10 | device: GPUDevice,
11 | shaderModule: GPUShaderModule,
12 | uniformsBindGroupLayout: GPUBindGroupLayout,
13 | swapChainFormat: GPUTextureFormat,
14 | depthFormat: GPUTextureFormat
15 | ) {
16 | for (let i = 0; i < this.nodes.length; ++i) {
17 | let n = this.nodes[i];
18 | n.buildRenderPipeline(
19 | device,
20 | shaderModule,
21 | uniformsBindGroupLayout,
22 | swapChainFormat,
23 | depthFormat
24 | );
25 | }
26 | }
27 |
28 | render(renderPassEncoder: GPURenderPassEncoder, uniformsBindGroup: GPUBindGroup) {
29 | renderPassEncoder.setBindGroup(0, uniformsBindGroup);
30 | for (let n of this.nodes) {
31 | n.render(renderPassEncoder);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/vol11_glb_simple/src/shader/glb.wgsl:
--------------------------------------------------------------------------------
1 | struct VertexInput {
2 | @location(0) position: vec3,
3 | };
4 |
5 | struct VertexOutput {
6 | @builtin(position) position: vec4,
7 | @location(0) world_pos: vec3,
8 | };
9 |
10 | struct ViewParams {
11 | view_proj: mat4x4,
12 | };
13 |
14 | struct NodeParams {
15 | transform: mat4x4,
16 | };
17 |
18 | @group(0) @binding(0)
19 | var view_params: ViewParams;
20 |
21 | @group(1) @binding(0)
22 | var node_params: NodeParams;
23 |
24 | @vertex
25 | fn vertex_main(vert: VertexInput) -> VertexOutput {
26 | var out: VertexOutput;
27 | out.position = view_params.view_proj * node_params.transform * vec4(vert.position, 1.0);
28 | out.world_pos = vert.position.xyz;
29 | return out;
30 | }
31 |
32 | @fragment
33 | fn fragment_main(in: VertexOutput) -> @location(0) vec4 {
34 | let dx = dpdx(in.world_pos);
35 | let dy = dpdy(in.world_pos);
36 | let n = normalize(cross(dx, dy));
37 | return vec4((n + 1.0) * 0.5, 1.0);
38 | }
39 |
--------------------------------------------------------------------------------
/vol11_glb_simple/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/vol11_glb_simple/src/types/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.glb" {
2 | const src: string;
3 | export default src;
4 | }
5 |
--------------------------------------------------------------------------------
/vol11_glb_simple/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"]
21 | }
22 |
--------------------------------------------------------------------------------
/vol11_glb_simple/vite.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | assetsInclude: ["**/*.glb"],
3 | };
4 |
--------------------------------------------------------------------------------
/vol1_oneCube/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol1_oneCube/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/vol1_oneCube/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol1_oneCube/src/shader/cubeFrag.wgsl:
--------------------------------------------------------------------------------
1 | @fragment
2 | fn main(
3 | @location(0) fragUV: vec2,
4 | @location(1) fragPosition: vec4,
5 | ) -> @location(0) vec4 {
6 | return fragPosition;
7 | }
--------------------------------------------------------------------------------
/vol1_oneCube/src/shader/cubeVert.wgsl:
--------------------------------------------------------------------------------
1 | struct Uniforms {
2 | modelViewProjectionMatrix: mat4x4,
3 | }
4 | @binding(0) @group(0) var uniforms: Uniforms;
5 |
6 | struct VertexOutput {
7 | @builtin(position) position: vec4,
8 | @location(0) fragUV: vec2,
9 | @location(1) fragPosition: vec4,
10 | }
11 |
12 | @vertex
13 | fn main(
14 | @location(0) position:vec4,
15 | @location(1) uv:vec2,
16 | ) -> VertexOutput {
17 | var output:VertexOutput;
18 | output.position = uniforms.modelViewProjectionMatrix * position;
19 | output.fragUV = uv;
20 | output.fragPosition = (position + vec4(1.0,1.0,1.0,1.0))* 0.5;
21 | return output;
22 | }
23 |
24 |
25 | // output.position:
26 | // 这是顶点着色器的输出,它决定了当前顶点在屏幕上的位置。
27 | // uniforms.modelViewProjectionMatrix * position 这个操作是将模型坐标转换为屏幕坐标。这里使用的 modelViewProjectionMatrix 是模型矩阵、视图矩阵和投影矩阵的组合。它将模型坐标转换为归一化设备坐标 (NDC)。
28 | // NDC 范围是 [-1, 1]。这意味着,经过这个变换后,任何在视野之外的顶点将有一个超出这个范围的 x、y 或 z 值。
29 | // 在顶点着色器执行后,图形管线将执行裁剪,删除那些超出 NDC 范围的部分,并将剩余的部分转换为屏幕坐标。
30 |
31 | // fragPosition:
32 | // 这是顶点着色器为每个顶点输出的一个值,之后将由光栅化器插值并传递给片元着色器。
33 | // fragPosition 是模型空间中的坐标值,它被稍微调整了以使其范围在 [0, 1] 而不是 [-1, 1]。这样做可能是为了满足某种特定需求,例如将其用作纹理坐标或其他计算。
34 | // 与 output.position 不同,fragPosition 不影响顶点在屏幕上的位置。它只是一个额外的数据,可以在后续的计算中使用。
--------------------------------------------------------------------------------
/vol1_oneCube/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/vol1_oneCube/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"],
21 | }
22 |
--------------------------------------------------------------------------------
/vol1_oneCube_MSAA/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol1_oneCube_MSAA/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/vol1_oneCube_MSAA/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol1_oneCube_MSAA/src/shader/cubeFrag.wgsl:
--------------------------------------------------------------------------------
1 | @fragment
2 | fn main(
3 | @location(0) fragUV: vec2,
4 | @location(1) fragPosition: vec4,
5 | ) -> @location(0) vec4 {
6 | return fragPosition;
7 | }
--------------------------------------------------------------------------------
/vol1_oneCube_MSAA/src/shader/cubeVert.wgsl:
--------------------------------------------------------------------------------
1 | struct Uniforms {
2 | modelViewProjectionMatrix: mat4x4,
3 | }
4 | @binding(0) @group(0) var uniforms: Uniforms;
5 |
6 | struct VertexOutput {
7 | @builtin(position) position: vec4,
8 | @location(0) fragUV: vec2,
9 | @location(1) fragPosition: vec4,
10 | }
11 |
12 | @vertex
13 |
14 | fn main(
15 | @location(0) position:vec4,
16 | @location(1) uv:vec2,
17 | ) -> VertexOutput {
18 | var output:VertexOutput;
19 | output.position = uniforms.modelViewProjectionMatrix * position;
20 | output.fragUV = uv;
21 | output.fragPosition = (position + vec4(1.0,1.0,1.0,1.0))* 0.5;
22 | return output;
23 | }
--------------------------------------------------------------------------------
/vol1_oneCube_MSAA/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/vol1_oneCube_MSAA/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"],
21 | }
22 |
--------------------------------------------------------------------------------
/vol1_oneCube_canvas_textureSampling/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol1_oneCube_canvas_textureSampling/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/vol1_oneCube_canvas_textureSampling/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol1_oneCube_canvas_textureSampling/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.querySelector("canvas#webgpu") as HTMLCanvasElement;
10 | canvas.width = window.innerWidth;
11 | canvas.height = window.innerHeight;
12 | const drawCanvas = document.querySelector(
13 | "canvas#canvas"
14 | ) as HTMLCanvasElement;
15 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
16 | // 请求WebGPU适配器与GPU设备
17 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
18 | const device = await adapter.requestDevice();
19 | const format = navigator.gpu.getPreferredCanvasFormat();
20 | // 配置上下文
21 | context.configure({
22 | device: device,
23 | // 上下文格式
24 | format: format,
25 | // 不透明度
26 | alphaMode: "opaque",
27 | });
28 | return { device, canvas, drawCanvas, format, context };
29 | };
30 |
--------------------------------------------------------------------------------
/vol1_oneCube_canvas_textureSampling/src/helper/vertexData.ts:
--------------------------------------------------------------------------------
1 | export const CubeData = () => {
2 | const vertexData = new Float32Array([
3 | // float3 position, float2 uv
4 | // face1
5 | +1, -1, +1, 1, 1,
6 | -1, -1, +1, 0, 1,
7 | -1, -1, -1, 0, 0,
8 | +1, -1, -1, 1, 0,
9 | +1, -1, +1, 1, 1,
10 | -1, -1, -1, 0, 0,
11 | // face2
12 | +1, +1, +1, 1, 1,
13 | +1, -1, +1, 0, 1,
14 | +1, -1, -1, 0, 0,
15 | +1, +1, -1, 1, 0,
16 | +1, +1, +1, 1, 1,
17 | +1, -1, -1, 0, 0,
18 | // face3
19 | -1, +1, +1, 1, 1,
20 | +1, +1, +1, 0, 1,
21 | +1, +1, -1, 0, 0,
22 | -1, +1, -1, 1, 0,
23 | -1, +1, +1, 1, 1,
24 | +1, +1, -1, 0, 0,
25 | // face4
26 | -1, -1, +1, 1, 1,
27 | -1, +1, +1, 0, 1,
28 | -1, +1, -1, 0, 0,
29 | -1, -1, -1, 1, 0,
30 | -1, -1, +1, 1, 1,
31 | -1, +1, -1, 0, 0,
32 | // face5
33 | +1, +1, +1, 1, 1,
34 | -1, +1, +1, 0, 1,
35 | -1, -1, +1, 0, 0,
36 | -1, -1, +1, 0, 0,
37 | +1, -1, +1, 1, 0,
38 | +1, +1, +1, 1, 1,
39 | // face6
40 | +1, -1, -1, 1, 1,
41 | -1, -1, -1, 0, 1,
42 | -1, +1, -1, 0, 0,
43 | +1, +1, -1, 1, 0,
44 | +1, -1, -1, 1, 1,
45 | -1, +1, -1, 0, 0
46 | ])
47 |
48 | return {
49 | vertexData,
50 | };
51 | };
--------------------------------------------------------------------------------
/vol1_oneCube_canvas_textureSampling/src/shader/cubeFrag.wgsl:
--------------------------------------------------------------------------------
1 | @group(1) @binding(0) var Sampler: sampler;
2 | @group(1) @binding(1) var Texture: texture_2d;
3 |
4 | @fragment
5 | fn main(@location(0) fragUV: vec2,
6 | @location(1) fragPosition: vec4) -> @location(0) vec4 {
7 | return textureSample(Texture, Sampler, fragUV) * fragPosition;
8 | }
--------------------------------------------------------------------------------
/vol1_oneCube_canvas_textureSampling/src/shader/cubeVert.wgsl:
--------------------------------------------------------------------------------
1 | @binding(0) @group(0) var mvpMatrix : mat4x4;
2 |
3 | struct VertexOutput {
4 | @builtin(position) Position : vec4,
5 | @location(0) fragUV : vec2,
6 | @location(1) fragPosition: vec4
7 | };
8 |
9 | @vertex
10 | fn main(
11 | @location(0) position : vec4,
12 | @location(1) uv : vec2
13 | ) -> VertexOutput {
14 | var output : VertexOutput;
15 | output.Position = mvpMatrix * position;
16 | output.fragUV = uv;
17 | output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));
18 | return output;
19 | }
--------------------------------------------------------------------------------
/vol1_oneCube_canvas_textureSampling/src/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | html,
7 | body {
8 | margin: 0;
9 | width: 100%;
10 | height: 100%;
11 | background: #000;
12 | color: #fff;
13 | display: flex;
14 | text-align: center;
15 | flex-direction: column;
16 | justify-content: center;
17 | align-items: center;
18 | font-family: Avenir, Helvetica, Arial, sans-serif;
19 | -webkit-font-smoothing: antialiased;
20 | }
21 |
22 | canvas#webgpu {
23 | width: 80vw;
24 | height: 80vw;
25 | }
26 | canvas#canvas {
27 | position: fixed;
28 | left: 0;
29 | bottom: 0;
30 | }
31 |
--------------------------------------------------------------------------------
/vol1_oneCube_canvas_textureSampling/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"]
21 | }
22 |
--------------------------------------------------------------------------------
/vol1_oneCube_image_textureSampling/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol1_oneCube_image_textureSampling/README.md:
--------------------------------------------------------------------------------
1 | ### GPUTextureUsage 标志
2 |
3 | GPUTextureUsage 标志决定了 GPUTexture 在创建后如何使用:
4 | | 标志 | 描述 | 示例 |
5 | | ------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
6 | | COPY_SRC | 纹理可以用作复制操作的来源。 | 作为 copyTextureToTexture() 或 copyTextureToBuffer() 调用的 source 参数。 |
7 | | COPY_DST | 纹理可用作复制或写入操作的目标。 |作为 copyTextureToTexture() 或 copyBufferToTexture() 调用的“目标”参数,或作为 writeTexture() 调用的目标。 |
8 | | TEXTURE_BINDING | 纹理可以绑定用作着色器中的采样纹理 | 作为绑定组 GPUTextureBindingLayout 的条目。 |
9 | | STORAGE_BINDING | 纹理可以绑定用作着色器中的存储纹理 | 作为 GPUStorageTextureBindingLayout 的绑定组条目。 |
10 | | RENDER_ATTACHMENT | 纹理可以用作渲染过程中的颜色或深度/模板附件。 | 作为 GPURenderPassColorAttachment.view 或 GPURenderPassDepthStencilAttachment.view。 |
11 |
--------------------------------------------------------------------------------
/vol1_oneCube_image_textureSampling/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/vol1_oneCube_image_textureSampling/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol1_oneCube_image_textureSampling/public/zs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyirs/webgpu_study/effbf26b3cb71d1c05cb6f7ed77aafcaad35d3e9/vol1_oneCube_image_textureSampling/public/zs.png
--------------------------------------------------------------------------------
/vol1_oneCube_image_textureSampling/src/shader/cubeFrag.wgsl:
--------------------------------------------------------------------------------
1 | @group(0) @binding(1) var mySampler: sampler;
2 | @group(0) @binding(2) var myTexture: texture_2d;
3 |
4 | @fragment
5 | fn main(
6 | @location(0) fragUV: vec2,
7 | @location(1) fragPosition: vec4,
8 | ) -> @location(0) vec4 {
9 | return fragPosition + textureSample(myTexture, mySampler, fragUV);
10 | }
--------------------------------------------------------------------------------
/vol1_oneCube_image_textureSampling/src/shader/cubeVert.wgsl:
--------------------------------------------------------------------------------
1 | struct Uniforms {
2 | modelViewProjectionMatrix: mat4x4,
3 | }
4 | @binding(0) @group(0) var uniforms: Uniforms;
5 |
6 | struct VertexOutput {
7 | @builtin(position) position: vec4,
8 | @location(0) fragUV: vec2,
9 | @location(1) fragPosition: vec4,
10 | }
11 |
12 | @vertex
13 |
14 | fn main(
15 | @location(0) position:vec4,
16 | @location(1) uv:vec2,
17 | ) -> VertexOutput {
18 | var output:VertexOutput;
19 | output.position = uniforms.modelViewProjectionMatrix * position;
20 | output.fragUV = uv;
21 | output.fragPosition = (position + vec4(1.0,1.0,1.0,1.0))* 0.5;
22 | return output;
23 | }
--------------------------------------------------------------------------------
/vol1_oneCube_image_textureSampling/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/vol1_oneCube_image_textureSampling/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"]
21 | }
22 |
--------------------------------------------------------------------------------
/vol1_oneCube_indexBuffer/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol1_oneCube_indexBuffer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/vol1_oneCube_indexBuffer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol1_oneCube_indexBuffer/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.querySelector("canvas#webgpu") as HTMLCanvasElement;
10 | canvas.width = window.innerWidth;
11 | canvas.height = window.innerHeight;
12 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
13 | // 请求WebGPU适配器与GPU设备
14 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
15 | const device = await adapter.requestDevice();
16 | const format = navigator.gpu.getPreferredCanvasFormat();
17 | // 配置上下文
18 | context.configure({
19 | device: device,
20 | // 上下文格式
21 | format: format,
22 | // 不透明度
23 | alphaMode: "opaque",
24 | });
25 | return { device, canvas, format, context };
26 | };
27 |
--------------------------------------------------------------------------------
/vol1_oneCube_indexBuffer/src/helper/vertexData.ts:
--------------------------------------------------------------------------------
1 | export const CubeData = () => {
2 | const vertexData = new Float32Array([
3 | // float3 position, float2 uv
4 | +1, -1, +1, 1, 1, // 0
5 | -1, -1, +1, 0, 1, // 1
6 | -1, -1, -1, 0, 0, // 2
7 | +1, -1, -1, 1, 0, // 3
8 | +1, +1, +1, 1, 1, // 4
9 | +1, -1, +1, 0, 1, // 5
10 | +1, -1, -1, 0, 0, // 6
11 | +1, +1, -1, 1, 0, // 7
12 | -1, +1, +1, 1, 1, // 8
13 | +1, +1, +1, 0, 1, // 9
14 | +1, +1, -1, 0, 0, // 10
15 | -1, +1, -1, 1, 0, // 11
16 | -1, -1, +1, 1, 1, // 12
17 | -1, +1, +1, 0, 1, // 13
18 | -1, +1, -1, 0, 0, // 14
19 | -1, -1, -1, 1, 0, // 15
20 | -1, -1, +1, 0, 0, // 16
21 | +1, -1, +1, 1, 0, // 17
22 | +1, -1, -1, 1, 1, // 18
23 | -1, -1, -1, 0, 1, // 19
24 | ]);
25 |
26 | const indexData = new Uint32Array([
27 | 0, 1, 2, 3, 0, 2, // face1
28 | 4, 5, 6, 7, 4, 6, // face2
29 | 8, 9, 10, 11, 8, 10, // face3
30 | 12, 13, 14, 15, 12, 14, // face4
31 | 4, 13, 16, 16, 17, 4, // face5
32 | 18, 19, 14, 7, 18, 14, // face6
33 | ]);
34 |
35 | return {
36 | vertexData,
37 | indexData
38 | };
39 | };
40 |
--------------------------------------------------------------------------------
/vol1_oneCube_indexBuffer/src/shader/cubeFrag.wgsl:
--------------------------------------------------------------------------------
1 | @fragment
2 | fn main(@location(0) fragUV: vec2,
3 | @location(1) fragPosition: vec4) -> @location(0) vec4 {
4 | return fragPosition;
5 | }
--------------------------------------------------------------------------------
/vol1_oneCube_indexBuffer/src/shader/cubeVert.wgsl:
--------------------------------------------------------------------------------
1 | @binding(0) @group(0) var mvpMatrix : mat4x4;
2 |
3 | struct VertexOutput {
4 | @builtin(position) Position : vec4,
5 | @location(0) fragUV : vec2,
6 | @location(1) fragPosition: vec4
7 | };
8 |
9 | @vertex
10 | fn main(
11 | @location(0) position : vec4,
12 | @location(1) uv : vec2
13 | ) -> VertexOutput {
14 | var output : VertexOutput;
15 | output.Position = mvpMatrix * position;
16 | output.fragUV = uv;
17 | output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));
18 | return output;
19 | }
--------------------------------------------------------------------------------
/vol1_oneCube_indexBuffer/src/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | html,
7 | body {
8 | margin: 0;
9 | width: 100%;
10 | height: 100%;
11 | background: #000;
12 | color: #fff;
13 | display: flex;
14 | text-align: center;
15 | flex-direction: column;
16 | justify-content: center;
17 | align-items: center;
18 | font-family: Avenir, Helvetica, Arial, sans-serif;
19 | -webkit-font-smoothing: antialiased;
20 | }
21 |
22 | canvas#webgpu {
23 | width: 60vw;
24 | height: 60vw;
25 | }
--------------------------------------------------------------------------------
/vol1_oneCube_indexBuffer/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"]
21 | }
22 |
--------------------------------------------------------------------------------
/vol1_oneCube_video_textureSampling/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol1_oneCube_video_textureSampling/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/vol1_oneCube_video_textureSampling/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol1_oneCube_video_textureSampling/public/1.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lyirs/webgpu_study/effbf26b3cb71d1c05cb6f7ed77aafcaad35d3e9/vol1_oneCube_video_textureSampling/public/1.mp4
--------------------------------------------------------------------------------
/vol1_oneCube_video_textureSampling/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.querySelector("canvas#webgpu") as HTMLCanvasElement;
10 | canvas.width = window.innerWidth;
11 | canvas.height = window.innerHeight;
12 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
13 | // 请求WebGPU适配器与GPU设备
14 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
15 | const device = await adapter.requestDevice();
16 | const format = navigator.gpu.getPreferredCanvasFormat();
17 | // 配置上下文
18 | context.configure({
19 | device: device,
20 | // 上下文格式
21 | format: format,
22 | // 不透明度
23 | alphaMode: "opaque",
24 | });
25 | return { device, canvas, format, context };
26 | };
27 |
--------------------------------------------------------------------------------
/vol1_oneCube_video_textureSampling/src/helper/vertexData.ts:
--------------------------------------------------------------------------------
1 | export const CubeData = () => {
2 | const vertexData = new Float32Array([
3 | // float3 position, float2 uv
4 | // face1
5 | +1, -1, +1, 1, 1,
6 | -1, -1, +1, 0, 1,
7 | -1, -1, -1, 0, 0,
8 | +1, -1, -1, 1, 0,
9 | +1, -1, +1, 1, 1,
10 | -1, -1, -1, 0, 0,
11 | // face2
12 | +1, +1, +1, 1, 1,
13 | +1, -1, +1, 0, 1,
14 | +1, -1, -1, 0, 0,
15 | +1, +1, -1, 1, 0,
16 | +1, +1, +1, 1, 1,
17 | +1, -1, -1, 0, 0,
18 | // face3
19 | -1, +1, +1, 1, 1,
20 | +1, +1, +1, 0, 1,
21 | +1, +1, -1, 0, 0,
22 | -1, +1, -1, 1, 0,
23 | -1, +1, +1, 1, 1,
24 | +1, +1, -1, 0, 0,
25 | // face4
26 | -1, -1, +1, 1, 1,
27 | -1, +1, +1, 0, 1,
28 | -1, +1, -1, 0, 0,
29 | -1, -1, -1, 1, 0,
30 | -1, -1, +1, 1, 1,
31 | -1, +1, -1, 0, 0,
32 | // face5
33 | +1, +1, +1, 1, 1,
34 | -1, +1, +1, 0, 1,
35 | -1, -1, +1, 0, 0,
36 | -1, -1, +1, 0, 0,
37 | +1, -1, +1, 1, 0,
38 | +1, +1, +1, 1, 1,
39 | // face6
40 | +1, -1, -1, 1, 1,
41 | -1, -1, -1, 0, 1,
42 | -1, +1, -1, 0, 0,
43 | +1, +1, -1, 1, 0,
44 | +1, -1, -1, 1, 1,
45 | -1, +1, -1, 0, 0
46 | ])
47 |
48 | return {
49 | vertexData,
50 | };
51 | };
--------------------------------------------------------------------------------
/vol1_oneCube_video_textureSampling/src/shader/cubeFrag.wgsl:
--------------------------------------------------------------------------------
1 | @group(1) @binding(0) var Sampler: sampler;
2 | @group(1) @binding(1) var Texture: texture_external;
3 |
4 | @fragment
5 | fn main(@location(0) fragUV: vec2,
6 | @location(1) fragPosition: vec4) -> @location(0) vec4 {
7 | return textureSampleBaseClampToEdge(Texture, Sampler, fragUV) + fragPosition;
8 | }
--------------------------------------------------------------------------------
/vol1_oneCube_video_textureSampling/src/shader/cubeVert.wgsl:
--------------------------------------------------------------------------------
1 | @binding(0) @group(0) var mvpMatrix : mat4x4;
2 |
3 | struct VertexOutput {
4 | @builtin(position) Position : vec4,
5 | @location(0) fragUV : vec2,
6 | @location(1) fragPosition: vec4
7 | };
8 |
9 | @vertex
10 | fn main(
11 | @location(0) position : vec4,
12 | @location(1) uv : vec2
13 | ) -> VertexOutput {
14 | var output : VertexOutput;
15 | output.Position = mvpMatrix * position;
16 | output.fragUV = uv;
17 | output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0));
18 | return output;
19 | }
--------------------------------------------------------------------------------
/vol1_oneCube_video_textureSampling/src/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | html,
7 | body {
8 | margin: 0;
9 | width: 100%;
10 | height: 100%;
11 | background: #000;
12 | color: #fff;
13 | display: flex;
14 | text-align: center;
15 | flex-direction: column;
16 | justify-content: center;
17 | align-items: center;
18 | font-family: Avenir, Helvetica, Arial, sans-serif;
19 | -webkit-font-smoothing: antialiased;
20 | }
21 |
22 | canvas#webgpu {
23 | width: 60vw;
24 | height: 60vw;
25 | }
--------------------------------------------------------------------------------
/vol1_oneCube_video_textureSampling/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"]
21 | }
22 |
--------------------------------------------------------------------------------
/vol2_twoCubes/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol2_twoCubes/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/vol2_twoCubes/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol2_twoCubes/src/helper/gpuBuffer.ts:
--------------------------------------------------------------------------------
1 | // 创建顶点缓冲区 VBO
2 | // 获取一块状态为映射了的显存,以及一个对应的 arrayBuffer 对象来写数据
3 | /**
4 | * 应用程序可以请求映射一个 GPUBuffer,这样它们就可以通过代表 GPUBuffer 分配的部分的 arraybuffer 访问它的内容。
5 | * 映射一个 GPUBuffer 是通过 mapAsync() 异步请求的,这样用户代理可以确保 GPU 在应用程序访问它的内容之前完成了对 GPUBuffer 的使用。
6 | * 映射的 GPUBuffer 不能被 GPU 使用,必须使用 unmap() 解除映射,然后才能将使用它的工作提交到 Queue 时间轴。
7 | * 一旦映射了 GPUBuffer,应用程序就可以通过 getMappedRange 同步请求访问其内容的范围
8 | */
9 | export const CreateGPUBuffer = (
10 | device: GPUDevice,
11 | data: Float32Array,
12 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.VERTEX |
13 | GPUBufferUsage.COPY_DST
14 | ) => {
15 | const buffer = device.createBuffer({
16 | size: data.byteLength,
17 | usage: usageFlag,
18 | mappedAtCreation: true,
19 | });
20 | new Float32Array(buffer.getMappedRange()).set(data);
21 | buffer.unmap();
22 | return buffer;
23 | };
24 |
25 | export const CreateGPUBufferUint = (
26 | device: GPUDevice,
27 | data: Uint32Array,
28 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
29 | GPUBufferUsage.COPY_DST
30 | ) => {
31 | const buffer = device.createBuffer({
32 | size: data.byteLength,
33 | usage: usageFlag,
34 | mappedAtCreation: true,
35 | });
36 | new Uint32Array(buffer.getMappedRange()).set(data);
37 | buffer.unmap();
38 | return buffer;
39 | };
40 |
--------------------------------------------------------------------------------
/vol2_twoCubes/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.createElement("canvas");
10 | document.body.appendChild(canvas);
11 | canvas.width = window.innerWidth;
12 | canvas.height = window.innerHeight;
13 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
14 | // 请求WebGPU适配器与GPU设备
15 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
16 | const device = await adapter.requestDevice();
17 | const format = navigator.gpu.getPreferredCanvasFormat();
18 | // 配置上下文
19 | context.configure({
20 | device: device,
21 | // 上下文格式
22 | format: format,
23 | // 不透明度
24 | alphaMode: "opaque",
25 | });
26 | return { device, canvas, format, context };
27 | };
28 |
--------------------------------------------------------------------------------
/vol2_twoCubes/src/helper/vertexData.ts:
--------------------------------------------------------------------------------
1 | export const CubeData = () => {
2 | const vertexData = new Float32Array([
3 | // position, color
4 | -1, -1, 1, 0, 0, 1, // vertex a, index 0
5 | 1, -1, 1, 1, 0, 1, // vertex b, index 1
6 | 1, 1, 1, 1, 1, 1, // vertex c, index 2
7 | -1, 1, 1, 0, 1, 1, // vertex d, index 3
8 | -1, -1, -1, 0, 0, 0, // vertex e, index 4
9 | 1, -1, -1, 1, 0, 0, // vertex f, index 5
10 | 1, 1, -1, 1, 1, 0, // vertex g, index 6
11 | -1, 1, -1, 0, 1, 0, // vertex h, index 7
12 | ]);
13 |
14 | const indexData = new Uint32Array([
15 | // front
16 | 0, 1, 2, 2, 3, 0,
17 | // right
18 | 1, 5, 6, 6, 2, 1,
19 | // back
20 | 4, 7, 6, 6, 5, 4,
21 | // left
22 | 0, 3, 7, 7, 4, 0,
23 | // top
24 | 3, 2, 6, 6, 7, 3,
25 | // bottom
26 | 0, 4, 5, 5, 1, 0
27 | ]);
28 |
29 | return {
30 | vertexData,
31 | indexData
32 | };
33 | };
--------------------------------------------------------------------------------
/vol2_twoCubes/src/shader/cubeFrag.wgsl:
--------------------------------------------------------------------------------
1 | @fragment
2 | fn main(
3 | @location(0) vColor: vec4
4 | ) -> @location(0) vec4 {
5 | return vColor;
6 | }
--------------------------------------------------------------------------------
/vol2_twoCubes/src/shader/cubeVert.wgsl:
--------------------------------------------------------------------------------
1 | struct Uniforms {
2 | modelViewProjectionMatrix: mat4x4,
3 | }
4 | @binding(0) @group(0) var uniforms: Uniforms;
5 |
6 | struct VertexOutput {
7 | @builtin(position) position : vec4,
8 | @location(0) vColor : vec4,
9 | }
10 |
11 | @vertex
12 |
13 | fn main(
14 | @location(0) position: vec4,
15 | @location(1) color: vec4
16 | ) -> VertexOutput {
17 | var output:VertexOutput;
18 | output.position = uniforms.modelViewProjectionMatrix * position;
19 | output.vColor = color;
20 | return output;
21 | }
--------------------------------------------------------------------------------
/vol2_twoCubes/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/vol2_twoCubes/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"],
21 | }
22 |
--------------------------------------------------------------------------------
/vol2_twoCubes_MSAA/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol2_twoCubes_MSAA/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/vol2_twoCubes_MSAA/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol2_twoCubes_MSAA/src/helper/gpuBuffer.ts:
--------------------------------------------------------------------------------
1 | // 创建顶点缓冲区 VBO
2 | // 获取一块状态为映射了的显存,以及一个对应的 arrayBuffer 对象来写数据
3 | /**
4 | * 应用程序可以请求映射一个 GPUBuffer,这样它们就可以通过代表 GPUBuffer 分配的部分的 arraybuffer 访问它的内容。
5 | * 映射一个 GPUBuffer 是通过 mapAsync() 异步请求的,这样用户代理可以确保 GPU 在应用程序访问它的内容之前完成了对 GPUBuffer 的使用。
6 | * 映射的 GPUBuffer 不能被 GPU 使用,必须使用 unmap() 解除映射,然后才能将使用它的工作提交到 Queue 时间轴。
7 | * 一旦映射了 GPUBuffer,应用程序就可以通过 getMappedRange 同步请求访问其内容的范围
8 | */
9 | export const CreateGPUBuffer = (
10 | device: GPUDevice,
11 | data: Float32Array,
12 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.VERTEX |
13 | GPUBufferUsage.COPY_DST
14 | ) => {
15 | const buffer = device.createBuffer({
16 | size: data.byteLength,
17 | usage: usageFlag,
18 | mappedAtCreation: true,
19 | });
20 | new Float32Array(buffer.getMappedRange()).set(data);
21 | buffer.unmap();
22 | return buffer;
23 | };
24 |
25 | export const CreateGPUBufferUint = (
26 | device: GPUDevice,
27 | data: Uint32Array,
28 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
29 | GPUBufferUsage.COPY_DST
30 | ) => {
31 | const buffer = device.createBuffer({
32 | size: data.byteLength,
33 | usage: usageFlag,
34 | mappedAtCreation: true,
35 | });
36 | new Uint32Array(buffer.getMappedRange()).set(data);
37 | buffer.unmap();
38 | return buffer;
39 | };
40 |
--------------------------------------------------------------------------------
/vol2_twoCubes_MSAA/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.createElement("canvas");
10 | document.body.appendChild(canvas);
11 | canvas.width = window.innerWidth;
12 | canvas.height = window.innerHeight;
13 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
14 | // 请求WebGPU适配器与GPU设备
15 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
16 | const device = await adapter.requestDevice();
17 | const format = navigator.gpu.getPreferredCanvasFormat();
18 | // 配置上下文
19 | context.configure({
20 | device: device,
21 | // 上下文格式
22 | format: format,
23 | // 不透明度
24 | alphaMode: "opaque",
25 | });
26 | return { device, canvas, format, context };
27 | };
28 |
--------------------------------------------------------------------------------
/vol2_twoCubes_MSAA/src/helper/vertexData.ts:
--------------------------------------------------------------------------------
1 | export const CubeData = () => {
2 | const vertexData = new Float32Array([
3 | // position, color
4 | -1, -1, 1, 0, 0, 1, // vertex a, index 0
5 | 1, -1, 1, 1, 0, 1, // vertex b, index 1
6 | 1, 1, 1, 1, 1, 1, // vertex c, index 2
7 | -1, 1, 1, 0, 1, 1, // vertex d, index 3
8 | -1, -1, -1, 0, 0, 0, // vertex e, index 4
9 | 1, -1, -1, 1, 0, 0, // vertex f, index 5
10 | 1, 1, -1, 1, 1, 0, // vertex g, index 6
11 | -1, 1, -1, 0, 1, 0, // vertex h, index 7
12 | ]);
13 |
14 | const indexData = new Uint32Array([
15 | // front
16 | 0, 1, 2, 2, 3, 0,
17 | // right
18 | 1, 5, 6, 6, 2, 1,
19 | // back
20 | 4, 7, 6, 6, 5, 4,
21 | // left
22 | 0, 3, 7, 7, 4, 0,
23 | // top
24 | 3, 2, 6, 6, 7, 3,
25 | // bottom
26 | 0, 4, 5, 5, 1, 0
27 | ]);
28 |
29 | return {
30 | vertexData,
31 | indexData
32 | };
33 | };
--------------------------------------------------------------------------------
/vol2_twoCubes_MSAA/src/shader/cubeFrag.wgsl:
--------------------------------------------------------------------------------
1 | @fragment
2 | fn main(
3 | @location(0) vColor: vec4
4 | ) -> @location(0) vec4 {
5 | return vColor;
6 | }
--------------------------------------------------------------------------------
/vol2_twoCubes_MSAA/src/shader/cubeVert.wgsl:
--------------------------------------------------------------------------------
1 | struct Uniforms {
2 | modelViewProjectionMatrix: mat4x4,
3 | }
4 | @binding(0) @group(0) var uniforms: Uniforms;
5 |
6 | struct VertexOutput {
7 | @builtin(position) position : vec4,
8 | @location(0) vColor : vec4,
9 | }
10 |
11 | @vertex
12 | fn main(
13 | @location(0) position: vec4,
14 | @location(1) color: vec4
15 | ) -> VertexOutput {
16 | var output:VertexOutput;
17 | output.position = uniforms.modelViewProjectionMatrix * position;
18 | output.vColor = color;
19 | return output;
20 | }
--------------------------------------------------------------------------------
/vol2_twoCubes_MSAA/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/vol2_twoCubes_MSAA/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"],
21 | }
22 |
--------------------------------------------------------------------------------
/vol3_sphere_wireFrame/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol3_sphere_wireFrame/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/vol3_sphere_wireFrame/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol3_sphere_wireFrame/src/helper/gpuBuffer.ts:
--------------------------------------------------------------------------------
1 | // 创建顶点缓冲区 VBO
2 | // 获取一块状态为映射了的显存,以及一个对应的 arrayBuffer 对象来写数据
3 | /**
4 | * 应用程序可以请求映射一个 GPUBuffer,这样它们就可以通过代表 GPUBuffer 分配的部分的 arraybuffer 访问它的内容。
5 | * 映射一个 GPUBuffer 是通过 mapAsync() 异步请求的,这样用户代理可以确保 GPU 在应用程序访问它的内容之前完成了对 GPUBuffer 的使用。
6 | * 映射的 GPUBuffer 不能被 GPU 使用,必须使用 unmap() 解除映射,然后才能将使用它的工作提交到 Queue 时间轴。
7 | * 一旦映射了 GPUBuffer,应用程序就可以通过 getMappedRange 同步请求访问其内容的范围
8 | */
9 | export const CreateGPUBuffer = (
10 | device: GPUDevice,
11 | data: Float32Array,
12 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.VERTEX |
13 | GPUBufferUsage.COPY_DST
14 | ) => {
15 | const buffer = device.createBuffer({
16 | size: data.byteLength,
17 | usage: usageFlag,
18 | mappedAtCreation: true,
19 | });
20 | new Float32Array(buffer.getMappedRange()).set(data);
21 | buffer.unmap();
22 | return buffer;
23 | };
24 |
25 | export const CreateGPUBufferUint = (
26 | device: GPUDevice,
27 | data: Uint32Array,
28 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
29 | GPUBufferUsage.COPY_DST
30 | ) => {
31 | const buffer = device.createBuffer({
32 | size: data.byteLength,
33 | usage: usageFlag,
34 | mappedAtCreation: true,
35 | });
36 | new Uint32Array(buffer.getMappedRange()).set(data);
37 | buffer.unmap();
38 | return buffer;
39 | };
40 |
--------------------------------------------------------------------------------
/vol3_sphere_wireFrame/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.createElement("canvas");
10 | document.body.appendChild(canvas);
11 | canvas.width = window.innerWidth;
12 | canvas.height = window.innerHeight;
13 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
14 | // 请求WebGPU适配器与GPU设备
15 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
16 | const device = await adapter.requestDevice();
17 | const format = navigator.gpu.getPreferredCanvasFormat();
18 | // 配置上下文
19 | context.configure({
20 | device: device,
21 | // 上下文格式
22 | format: format,
23 | // 不透明度
24 | alphaMode: "opaque",
25 | });
26 | return { device, canvas, format, context };
27 | };
28 |
--------------------------------------------------------------------------------
/vol3_sphere_wireFrame/src/helper/vertexData.ts:
--------------------------------------------------------------------------------
1 | import { vec3 } from "wgpu-matrix";
2 |
3 | const SpherePosition = (
4 | radius: number,
5 | theta: number,
6 | phi: number,
7 | center = [0, 0, 0]
8 | ) => {
9 | const snt = Math.sin((theta * Math.PI) / 180);
10 | const cnt = Math.cos((theta * Math.PI) / 180);
11 | const snp = Math.sin((phi * Math.PI) / 180);
12 | const cnp = Math.cos((phi * Math.PI) / 180);
13 | return vec3.fromValues(
14 | radius * snt * cnp + center[0],
15 | radius * cnt + center[1],
16 | -radius * snt * snp + center[2]
17 | );
18 | };
19 |
20 | export const SphereWireframeData = (
21 | radius: number,
22 | u: number, // 经度分段数
23 | v: number, // 纬度分段数
24 | center: any = [0, 0, 0]
25 | ) => {
26 | if (u < 2 || v < 2) return;
27 | let pts = [];
28 | let pt;
29 | for (let i = 0; i < u; i++) {
30 | let pt1 = [];
31 | for (let j = 0; j < v; j++) {
32 | pt = SpherePosition(
33 | radius,
34 | (i * 180) / (u - 1),
35 | (j * 360) / (v - 1),
36 | center
37 | );
38 | pt1.push(pt);
39 | }
40 | pts.push(pt1);
41 | }
42 |
43 | let p = [] as any;
44 | let p0, p1, p2, p3;
45 | for (let i = 0; i < u - 1; i++) {
46 | for (let j = 0; j < v - 1; j++) {
47 | p0 = pts[i][j];
48 | p1 = pts[i + 1][j];
49 | //p2 = pts[i+1][j+1];
50 | p3 = pts[i][j + 1];
51 | p.push([
52 | p0[0],
53 | p0[1],
54 | p0[2],
55 | p1[0],
56 | p1[1],
57 | p1[2],
58 | p0[0],
59 | p0[1],
60 | p0[2],
61 | p3[0],
62 | p3[1],
63 | p3[2],
64 | ]);
65 | }
66 | }
67 | return new Float32Array(p.flat());
68 | };
69 |
--------------------------------------------------------------------------------
/vol3_sphere_wireFrame/src/shader/sphereFrag.wgsl:
--------------------------------------------------------------------------------
1 | @fragment
2 | fn main() -> @location(0) vec4 {
3 | return vec4(1.0, 1.0, 0.0, 1.0);
4 | }
--------------------------------------------------------------------------------
/vol3_sphere_wireFrame/src/shader/sphereVert.wgsl:
--------------------------------------------------------------------------------
1 | struct Uniforms {
2 | modelViewProjectionMatrix: mat4x4,
3 | }
4 | @binding(0) @group(0) var uniforms: Uniforms;
5 |
6 | @vertex
7 |
8 | fn main(
9 | @location(0) position: vec4,
10 | ) -> @builtin(position) vec4 {
11 | return uniforms.modelViewProjectionMatrix * position;
12 | }
--------------------------------------------------------------------------------
/vol3_sphere_wireFrame/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/vol3_sphere_wireFrame/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"],
21 | }
22 |
--------------------------------------------------------------------------------
/vol4_oneCube_light_mv+p/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol4_oneCube_light_mv+p/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/vol4_oneCube_light_mv+p/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol4_oneCube_light_mv+p/src/helper/gpuBuffer.ts:
--------------------------------------------------------------------------------
1 | // 创建顶点缓冲区 VBO
2 | // 获取一块状态为映射了的显存,以及一个对应的 arrayBuffer 对象来写数据
3 | /**
4 | * 应用程序可以请求映射一个 GPUBuffer,这样它们就可以通过代表 GPUBuffer 分配的部分的 arraybuffer 访问它的内容。
5 | * 映射一个 GPUBuffer 是通过 mapAsync() 异步请求的,这样用户代理可以确保 GPU 在应用程序访问它的内容之前完成了对 GPUBuffer 的使用。
6 | * 映射的 GPUBuffer 不能被 GPU 使用,必须使用 unmap() 解除映射,然后才能将使用它的工作提交到 Queue 时间轴。
7 | * 一旦映射了 GPUBuffer,应用程序就可以通过 getMappedRange 同步请求访问其内容的范围
8 | */
9 | export const CreateGPUBuffer = (
10 | device: GPUDevice,
11 | data: Float32Array,
12 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.VERTEX |
13 | GPUBufferUsage.COPY_DST
14 | ) => {
15 | const buffer = device.createBuffer({
16 | size: data.byteLength,
17 | usage: usageFlag,
18 | mappedAtCreation: true,
19 | });
20 | new Float32Array(buffer.getMappedRange()).set(data);
21 | buffer.unmap();
22 | return buffer;
23 | };
24 |
25 | export const CreateGPUBufferUint = (
26 | device: GPUDevice,
27 | data: Uint32Array,
28 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
29 | GPUBufferUsage.COPY_DST
30 | ) => {
31 | const buffer = device.createBuffer({
32 | size: data.byteLength,
33 | usage: usageFlag,
34 | mappedAtCreation: true,
35 | });
36 | new Uint32Array(buffer.getMappedRange()).set(data);
37 | buffer.unmap();
38 | return buffer;
39 | };
40 |
--------------------------------------------------------------------------------
/vol4_oneCube_light_mv+p/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.createElement("canvas");
10 | document.body.appendChild(canvas);
11 | canvas.width = window.innerWidth;
12 | canvas.height = window.innerHeight;
13 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
14 | // 请求WebGPU适配器与GPU设备
15 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
16 | const device = await adapter.requestDevice();
17 | const format = navigator.gpu.getPreferredCanvasFormat();
18 | // 配置上下文
19 | context.configure({
20 | device: device,
21 | // 上下文格式
22 | format: format,
23 | // 不透明度
24 | alphaMode: "opaque",
25 | });
26 | return { device, canvas, format, context };
27 | };
28 |
--------------------------------------------------------------------------------
/vol4_oneCube_light_mv+p/src/shader/cubeFrag.wgsl:
--------------------------------------------------------------------------------
1 | struct FragUniforms {
2 | light_position : vec4,
3 | eye_position : vec4,
4 | };
5 | @binding(1) @group(0) var frag_uniforms : FragUniforms;
6 |
7 | struct LightUniforms {
8 | color : vec4,
9 | specular_color : vec4,
10 | params: vec4, // ambient_intensity, diffuse_intensity, specular_intensity, specular_shininess
11 | };
12 | @binding(2) @group(0) var light_uniforms : LightUniforms;
13 |
14 | @fragment
15 | fn main(@location(0) v_position: vec4, @location(1) v_normal: vec4) -> @location(0) vec4 {
16 | let N:vec3 = normalize(v_normal.xyz);
17 | let L:vec3 = normalize(frag_uniforms.light_position.xyz - v_position.xyz); // Both in view space
18 | let V:vec3 = -v_position.xyz; // Eye position is at origin in view space
19 | let H:vec3 = normalize(L + V);
20 | let diffuse:f32 = light_uniforms.params[1] * max(dot(N, L), 0.0);
21 | let specular: f32 = light_uniforms.params[2] * pow(max(dot(N, H),0.0), light_uniforms.params[3]);
22 | let ambient:f32 = light_uniforms.params[0];
23 | let final_color = light_uniforms.color*(ambient + diffuse) + light_uniforms.specular_color * specular;
24 | return vec4(final_color.rgb, 1.0);
25 | }
--------------------------------------------------------------------------------
/vol4_oneCube_light_mv+p/src/shader/cubeVert.wgsl:
--------------------------------------------------------------------------------
1 | struct Uniforms {
2 | model_view_mat : mat4x4,
3 | project_mat : mat4x4,
4 | normal_mat : mat4x4,
5 | };
6 | @binding(0) @group(0) var uniforms : Uniforms;
7 |
8 | struct Output {
9 | @builtin(position) position : vec4,
10 | @location(0) v_position : vec4,
11 | @location(1) v_normal : vec4,
12 | };
13 |
14 | @vertex
15 | fn main(@location(0) pos: vec4, @location(1) normal: vec4) -> Output {
16 | var output: Output;
17 | let m_position:vec4 = uniforms.model_view_mat * pos;
18 | output.v_position = m_position;
19 | output.v_normal = uniforms.normal_mat * normal;
20 | output.position = uniforms.project_mat * m_position;
21 | return output;
22 | }
23 |
24 | // mv + p 实现
25 | // 模型矩阵(Model Matrix):这个矩阵负责把模型从模型空间(Model Space)变换到世界空间(World Space)。模型空间是模型的原始坐标系统,原点通常在模型的中心。世界空间是一个更大的坐标系统,用于表示场景中所有对象的位置。
26 | // 视图矩阵(View Matrix):这个矩阵负责把模型从世界空间变换到视图空间(View Space,也叫相机空间)。视图空间的原点是相机的位置,向前看的方向是Z轴的负方向。
27 | // 投影矩阵(Projection Matrix):这个矩阵负责把模型从视图空间变换到裁剪空间(Clip Space)。在这个空间中,所有可见的对象都会被映射到一个单位立方体(从-1到1的范围)。
28 |
29 | // 在vp+m方式中,你先在世界空间进行物体的变换(模型变换),然后将变换后的坐标投影到摄像机空间(视图投影变换)。在这个过程中,光源位置和视点位置都是在世界空间中定义的,因此它们无需进行任何转换。
30 | // 而在mv+p方式中,你先将物体从世界空间变换到视图空间(视图变换),然后在视图空间中进行投影变换(投影变换)。这就意味着你的着色器是在视图空间中进行计算的,因此需要将光源位置和视点位置也转换到视图空间中,以便于进行正确的光照计算。
--------------------------------------------------------------------------------
/vol4_oneCube_light_mv+p/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/vol4_oneCube_light_mv+p/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"],
21 | }
22 |
--------------------------------------------------------------------------------
/vol4_oneCube_light_vp+m/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol4_oneCube_light_vp+m/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite App
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/vol4_oneCube_light_vp+m/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol4_oneCube_light_vp+m/src/helper/gpuBuffer.ts:
--------------------------------------------------------------------------------
1 | // 创建顶点缓冲区 VBO
2 | // 获取一块状态为映射了的显存,以及一个对应的 arrayBuffer 对象来写数据
3 | /**
4 | * 应用程序可以请求映射一个 GPUBuffer,这样它们就可以通过代表 GPUBuffer 分配的部分的 arraybuffer 访问它的内容。
5 | * 映射一个 GPUBuffer 是通过 mapAsync() 异步请求的,这样用户代理可以确保 GPU 在应用程序访问它的内容之前完成了对 GPUBuffer 的使用。
6 | * 映射的 GPUBuffer 不能被 GPU 使用,必须使用 unmap() 解除映射,然后才能将使用它的工作提交到 Queue 时间轴。
7 | * 一旦映射了 GPUBuffer,应用程序就可以通过 getMappedRange 同步请求访问其内容的范围
8 | */
9 | export const CreateGPUBuffer = (
10 | device: GPUDevice,
11 | data: Float32Array,
12 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.VERTEX |
13 | GPUBufferUsage.COPY_DST
14 | ) => {
15 | const buffer = device.createBuffer({
16 | size: data.byteLength,
17 | usage: usageFlag,
18 | mappedAtCreation: true,
19 | });
20 | new Float32Array(buffer.getMappedRange()).set(data);
21 | buffer.unmap();
22 | return buffer;
23 | };
24 |
25 | export const CreateGPUBufferUint = (
26 | device: GPUDevice,
27 | data: Uint32Array,
28 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
29 | GPUBufferUsage.COPY_DST
30 | ) => {
31 | const buffer = device.createBuffer({
32 | size: data.byteLength,
33 | usage: usageFlag,
34 | mappedAtCreation: true,
35 | });
36 | new Uint32Array(buffer.getMappedRange()).set(data);
37 | buffer.unmap();
38 | return buffer;
39 | };
40 |
--------------------------------------------------------------------------------
/vol4_oneCube_light_vp+m/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.createElement("canvas");
10 | document.body.appendChild(canvas);
11 | canvas.width = window.innerWidth;
12 | canvas.height = window.innerHeight;
13 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
14 | // 请求WebGPU适配器与GPU设备
15 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
16 | const device = await adapter.requestDevice();
17 | const format = navigator.gpu.getPreferredCanvasFormat();
18 | // 配置上下文
19 | context.configure({
20 | device: device,
21 | // 上下文格式
22 | format: format,
23 | // 不透明度
24 | alphaMode: "opaque",
25 | });
26 | return { device, canvas, format, context };
27 | };
28 |
--------------------------------------------------------------------------------
/vol4_oneCube_light_vp+m/src/shader/cubeFrag.wgsl:
--------------------------------------------------------------------------------
1 | struct FragUniforms {
2 | light_position : vec4,
3 | eye_position : vec4,
4 | };
5 | @binding(1) @group(0) var frag_uniforms : FragUniforms;
6 |
7 | struct LightUniforms {
8 | color : vec4,
9 | specular_color : vec4,
10 | params: vec4, // ambient_intensity, diffuse_intensity, specular_intensity, specular_shininess
11 | };
12 | @binding(2) @group(0) var light_uniforms : LightUniforms;
13 |
14 | @fragment
15 | fn main(@location(0) v_position: vec4, @location(1) v_normal: vec4) -> @location(0) vec4 {
16 | let N:vec3 = normalize(v_normal.xyz); // 法线
17 | let L:vec3 = normalize(frag_uniforms.light_position.xyz - v_position.xyz); // 光线方向
18 | let V:vec3 = normalize(frag_uniforms.eye_position.xyz - v_position.xyz); // 视线方向
19 | let H:vec3 = normalize(L + V); // 半向量
20 | let diffuse:f32 = light_uniforms.params[1] * max(dot(N, L), 0.0); // 漫反射光分量(取决于N和L的点积)
21 | let specular: f32 = light_uniforms.params[2] * pow(max(dot(N, H),0.0), light_uniforms.params[3]); // 高光分量 (取决于N和H的点积以及高光光泽度)
22 | let ambient:f32 = light_uniforms.params[0];
23 | // 该颜色是环境光、漫反射光和高光的组合,每种光的颜色由光源的颜色(对于环境光和漫反射光)和光源的高光颜色(对于高光)决定。每种光的强度由对应的光照强度参数决定。
24 | let final_color = light_uniforms.color*(ambient + diffuse) + light_uniforms.specular_color * specular;
25 | return vec4(final_color.rgb, 1.0);
26 | }
--------------------------------------------------------------------------------
/vol4_oneCube_light_vp+m/src/shader/cubeVert.wgsl:
--------------------------------------------------------------------------------
1 | struct Uniforms {
2 | view_project_mat : mat4x4,
3 | model_mat : mat4x4,
4 | normal_mat : mat4x4,
5 | };
6 | @binding(0) @group(0) var uniforms : Uniforms;
7 |
8 | struct Output {
9 | @builtin(position) position : vec4,
10 | @location(0) v_position : vec4,
11 | @location(1) v_normal : vec4,
12 | };
13 |
14 | @vertex
15 | fn main(@location(0) pos: vec4, @location(1) normal: vec4) -> Output {
16 | var output: Output;
17 | let m_position:vec4 = uniforms.model_mat * pos;
18 | output.v_position = m_position;
19 | // 矩阵对向量进行变换
20 | // normal_mat是法线矩阵,它用来将法线从模型空间变换到世界空间。
21 | // 将顶点的法线(normal)从模型空间变换到世界空间。通过用法线矩阵乘以模型空间中的法线向量实现
22 | // 光照计算通常在世界空间中进行。在模型空间中,法线向量可能不正确地表示顶点相对于世界的方向
23 | output.v_normal = uniforms.normal_mat * normal;
24 | // view_project_mat是视图投影矩阵,它将顶点从世界空间变换到裁剪空间。裁剪空间中的顶点会经过裁剪操作,以删除位于视锥体以外的顶点,
25 | // 然后通过透视除法变换到归一化设备坐标(NDC)空间,并最终被光栅化为屏幕空间中的像素。
26 | // m_position是已经通过模型矩阵变换到世界空间的顶点位置,现在我们通过应用视图投影矩阵将其变换到裁剪空间。
27 | output.position = uniforms.view_project_mat * m_position;
28 | return output;
29 | }
--------------------------------------------------------------------------------
/vol4_oneCube_light_vp+m/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/vol4_oneCube_light_vp+m/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"],
21 | }
22 |
--------------------------------------------------------------------------------
/vol5_objects_light/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol5_objects_light/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.32",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol5_objects_light/src/helper/box.ts:
--------------------------------------------------------------------------------
1 | const vertex = new Float32Array([
2 | // float3 position, float3 normal, float2 uv
3 | 0.5,0.5,0.5, 1,0,0, 0,1,
4 | 0.5,0.5,-0.5, 1,0,0, 1,1,
5 | 0.5,-0.5,0.5, 1,0,0, 0,0,
6 | 0.5,-0.5,-0.5, 1,0,0, 1,0,
7 | -0.5,0.5,-0.5, -1,0,0, 0,1,
8 | -0.5,0.5,0.5, -1,0,0, 1,1,
9 | -0.5,-0.5,-0.5, -1,0,0, 0,0,
10 | -0.5,-0.5,0.5, -1,0,0, 1,0,
11 | -0.5,0.5,-0.5, 0,1,0, 0,1,
12 | 0.5,0.5,-0.5, 0,1,0, 1,1,
13 | -0.5,0.5,0.5, 0,1,0, 0,0,
14 | 0.5,0.5,0.5, 0,1,0, 1,0,
15 | -0.5,-0.5,0.5, 0,-1,0, 0,1,
16 | 0.5,-0.5,0.5, 0,-1,0, 1,1,
17 | -0.5,-0.5,-0.5, 0,-1,0, 0,0,
18 | 0.5,-0.5,-0.5, 0,-1,0, 1,0,
19 | -0.5,0.5,0.5, 0,0,1, 0,1,
20 | 0.5,0.5,0.5, 0,0,1, 1,1,
21 | -0.5,-0.5,0.5, 0,0,1, 0,0,
22 | 0.5,-0.5,0.5, 0,0,1, 1,0,
23 | 0.5,0.5,-0.5, 0,0,-1, 0,1,
24 | -0.5,0.5,-0.5, 0,0,-1, 1,1,
25 | 0.5,-0.5,-0.5, 0,0,-1, 0,0,
26 | -0.5,-0.5,-0.5, 0,0,-1, 1,0
27 | ])
28 |
29 | const index = new Uint16Array([
30 | 0,2,1,
31 | 2,3,1,
32 | 4,6,5,
33 | 6,7,5,
34 | 8,10,9,
35 | 10,11,9,
36 | 12,14,13,
37 | 14,15,13,
38 | 16,18,17,
39 | 18,19,17,
40 | 20,22,21,
41 | 22,23,21
42 | ])
43 | const vertexCount = 24
44 | const indexCount = 36
45 |
46 | export {vertex, index, vertexCount, indexCount}
--------------------------------------------------------------------------------
/vol5_objects_light/src/helper/gpuBuffer.ts:
--------------------------------------------------------------------------------
1 | // 创建顶点缓冲区 VBO
2 | // 获取一块状态为映射了的显存,以及一个对应的 arrayBuffer 对象来写数据
3 | /**
4 | * 应用程序可以请求映射一个 GPUBuffer,这样它们就可以通过代表 GPUBuffer 分配的部分的 arraybuffer 访问它的内容。
5 | * 映射一个 GPUBuffer 是通过 mapAsync() 异步请求的,这样用户代理可以确保 GPU 在应用程序访问它的内容之前完成了对 GPUBuffer 的使用。
6 | * 映射的 GPUBuffer 不能被 GPU 使用,必须使用 unmap() 解除映射,然后才能将使用它的工作提交到 Queue 时间轴。
7 | * 一旦映射了 GPUBuffer,应用程序就可以通过 getMappedRange 同步请求访问其内容的范围
8 | */
9 | export const CreateGPUBuffer = (
10 | device: GPUDevice,
11 | data: Float32Array,
12 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.VERTEX |
13 | GPUBufferUsage.COPY_DST
14 | ) => {
15 | const buffer = device.createBuffer({
16 | size: data.byteLength,
17 | usage: usageFlag,
18 | mappedAtCreation: true,
19 | });
20 | new Float32Array(buffer.getMappedRange()).set(data);
21 | buffer.unmap();
22 | return buffer;
23 | };
24 |
25 | export const CreateGPUBufferUint = (
26 | device: GPUDevice,
27 | data: Uint32Array,
28 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
29 | GPUBufferUsage.COPY_DST
30 | ) => {
31 | const buffer = device.createBuffer({
32 | size: data.byteLength,
33 | usage: usageFlag,
34 | mappedAtCreation: true,
35 | });
36 | new Uint32Array(buffer.getMappedRange()).set(data);
37 | buffer.unmap();
38 | return buffer;
39 | };
40 |
41 | export const CreateGPUBufferUint16 = (
42 | device: GPUDevice,
43 | data: Uint16Array,
44 | usageFlag: GPUBufferUsageFlags = GPUBufferUsage.INDEX |
45 | GPUBufferUsage.COPY_DST
46 | ) => {
47 | const buffer = device.createBuffer({
48 | size: data.byteLength,
49 | usage: usageFlag,
50 | mappedAtCreation: true,
51 | });
52 | new Uint16Array(buffer.getMappedRange()).set(data);
53 | buffer.unmap();
54 | return buffer;
55 | };
56 |
--------------------------------------------------------------------------------
/vol5_objects_light/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.querySelector("canvas") as HTMLCanvasElement;
10 | canvas.width = window.innerWidth;
11 | canvas.height = window.innerHeight;
12 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
13 | // 请求WebGPU适配器与GPU设备
14 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
15 | const device = await adapter.requestDevice();
16 | const format = navigator.gpu.getPreferredCanvasFormat();
17 | // 配置上下文
18 | context.configure({
19 | device: device,
20 | // 上下文格式
21 | format: format,
22 | // 不透明度
23 | alphaMode: "opaque",
24 | });
25 | return { device, canvas, format, context };
26 | };
27 |
--------------------------------------------------------------------------------
/vol5_objects_light/src/shader/vert.wgsl:
--------------------------------------------------------------------------------
1 | @group(0) @binding(0) var model : array>;
2 | @group(0) @binding(1) var viewProjection : mat4x4;
3 | @group(0) @binding(2) var colors : array>;
4 |
5 | struct VertexOutput {
6 | @builtin(position) Position : vec4,
7 | @location(0) fragPosition : vec3,
8 | @location(1) fragNormal : vec3,
9 | @location(2) fragUV: vec2,
10 | @location(3) fragColor: vec4
11 | };
12 |
13 | @vertex
14 | fn main(
15 | @builtin(instance_index) index : u32,
16 | @location(0) position : vec3,
17 | @location(1) normal : vec3,
18 | @location(2) uv : vec2,
19 | ) -> VertexOutput {
20 | let modelMatrix = model[index];
21 | let mvp = viewProjection * modelMatrix;
22 | let pos = vec4(position, 1.0);
23 |
24 | var output : VertexOutput;
25 | output.Position = mvp * pos;
26 | output.fragPosition = (modelMatrix * pos).xyz;
27 | // 如果你考虑到非均匀缩放,那么在变换法线时,你应该使用模型视图矩阵的逆矩阵的转置,而不是模型视图矩阵本身
28 | // 但在WGSL中,并没有提供直接计算矩阵逆的函数,因此注释建议在JavaScript或计算着色器(Compute Shader)中进行此操作。
29 | // 这里为了简化 直接使用模型视图矩阵
30 | output.fragNormal = (modelMatrix * vec4(normal, 0.0)).xyz;
31 | output.fragUV = uv;
32 | output.fragColor = colors[index];
33 | return output;
34 | }
--------------------------------------------------------------------------------
/vol5_objects_light/src/style.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | }
5 |
6 | canvas{
7 | width: 100vw;
8 | height: 100vh;
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | }
--------------------------------------------------------------------------------
/vol5_objects_light/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["vite/client", "@webgpu/types"]
19 | },
20 | "include": ["src"],
21 | }
22 |
--------------------------------------------------------------------------------
/vol5_objects_light_layout/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/vol5_objects_light_layout/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "helloworld",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@webgpu/types": "^0.1.34",
13 | "typescript": "^5.0.4",
14 | "vite": "^4.3.2"
15 | },
16 | "dependencies": {
17 | "wgpu-matrix": "^2.5.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vol5_objects_light_layout/src/helper/box.ts:
--------------------------------------------------------------------------------
1 | const vertex = new Float32Array([
2 | // float3 position, float3 normal, float2 uv
3 | 0.5,0.5,0.5, 1,0,0, 0,1,
4 | 0.5,0.5,-0.5, 1,0,0, 1,1,
5 | 0.5,-0.5,0.5, 1,0,0, 0,0,
6 | 0.5,-0.5,-0.5, 1,0,0, 1,0,
7 | -0.5,0.5,-0.5, -1,0,0, 0,1,
8 | -0.5,0.5,0.5, -1,0,0, 1,1,
9 | -0.5,-0.5,-0.5, -1,0,0, 0,0,
10 | -0.5,-0.5,0.5, -1,0,0, 1,0,
11 | -0.5,0.5,-0.5, 0,1,0, 0,1,
12 | 0.5,0.5,-0.5, 0,1,0, 1,1,
13 | -0.5,0.5,0.5, 0,1,0, 0,0,
14 | 0.5,0.5,0.5, 0,1,0, 1,0,
15 | -0.5,-0.5,0.5, 0,-1,0, 0,1,
16 | 0.5,-0.5,0.5, 0,-1,0, 1,1,
17 | -0.5,-0.5,-0.5, 0,-1,0, 0,0,
18 | 0.5,-0.5,-0.5, 0,-1,0, 1,0,
19 | -0.5,0.5,0.5, 0,0,1, 0,1,
20 | 0.5,0.5,0.5, 0,0,1, 1,1,
21 | -0.5,-0.5,0.5, 0,0,1, 0,0,
22 | 0.5,-0.5,0.5, 0,0,1, 1,0,
23 | 0.5,0.5,-0.5, 0,0,-1, 0,1,
24 | -0.5,0.5,-0.5, 0,0,-1, 1,1,
25 | 0.5,-0.5,-0.5, 0,0,-1, 0,0,
26 | -0.5,-0.5,-0.5, 0,0,-1, 1,0
27 | ])
28 |
29 | const index = new Uint16Array([
30 | 0,2,1,
31 | 2,3,1,
32 | 4,6,5,
33 | 6,7,5,
34 | 8,10,9,
35 | 10,11,9,
36 | 12,14,13,
37 | 14,15,13,
38 | 16,18,17,
39 | 18,19,17,
40 | 20,22,21,
41 | 22,23,21
42 | ])
43 | const vertexCount = 24
44 | const indexCount = 36
45 |
46 | export {vertex, index, vertexCount, indexCount}
--------------------------------------------------------------------------------
/vol5_objects_light_layout/src/helper/init.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | export const InitGPU = async () => {
4 | if (navigator.gpu === undefined) {
5 | alert("当前浏览器不支持WebGPU,确保chrome版本在113及以上。");
6 | throw new Error("当前浏览器不支持WebGPU");
7 | }
8 | // 创建canvas
9 | const canvas = document.querySelector("canvas") as HTMLCanvasElement;
10 | canvas.width = window.innerWidth;
11 | canvas.height = window.innerHeight;
12 | const context = canvas.getContext("webgpu") as GPUCanvasContext;
13 | // 请求WebGPU适配器与GPU设备
14 | const adapter = (await navigator.gpu.requestAdapter()) as GPUAdapter;
15 | const device = await adapter.requestDevice();
16 | const format = navigator.gpu.getPreferredCanvasFormat();
17 | // 配置上下文
18 | context.configure({
19 | device: device,
20 | // 上下文格式
21 | format: format,
22 | // 不透明度
23 | alphaMode: "opaque",
24 | });
25 | return { device, canvas, format, context };
26 | };
27 |
--------------------------------------------------------------------------------
/vol5_objects_light_layout/src/shader/vert.wgsl:
--------------------------------------------------------------------------------
1 | @group(0) @binding(0) var model : array>;
2 | @group(0) @binding(1) var viewProjection : mat4x4;
3 | @group(0) @binding(2) var colors : array>;
4 |
5 | struct VertexOutput {
6 | @builtin(position) Position : vec4,
7 | @location(0) fragPosition : vec3,
8 | @location(1) fragNormal : vec3,
9 | @location(2) fragUV: vec2,
10 | @location(3) fragColor: vec4
11 | };
12 |
13 | @vertex
14 | fn main(
15 | @builtin(instance_index) index : u32,
16 | @location(0) position : vec3