wgsl-renderer 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +8 -8
- package/README.md +236 -150
- package/dist/cjs/index.js +122 -125
- package/dist/esm/index.js +122 -125
- package/dist/types/index.d.ts +19 -74
- package/dist/types/index.js +122 -125
- package/package.json +1 -1
package/LICENSE.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 taiyuuki
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sub license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
-
|
|
7
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
-
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 taiyuuki
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sub license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
9
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
## ✨ 特性
|
|
6
6
|
|
|
7
|
-
- 🔗
|
|
8
|
-
- 🖼️ **多Pass渲染** -
|
|
7
|
+
- 🔗 **灵活的Pass链** - Pass 2开始自动绑定上一个pass的输出
|
|
8
|
+
- 🖼️ **多Pass渲染** - 支持纹理渲染、后处理效果等多通道
|
|
9
9
|
- ⚡ **高性能渲染循环** - 支持单帧渲染和循环渲染模式
|
|
10
10
|
- 🛠️ **TypeScript支持** - 完整的类型定义和清晰的API分离
|
|
11
11
|
- 🎮 **Uniform系统** - 内置uniform buffer管理,支持动态参数
|
|
12
|
+
- 🔄 **自动Resize** - 内置ResizeObserver自动处理canvas大小变化
|
|
12
13
|
|
|
13
14
|
## 🚀 快速开始
|
|
14
15
|
|
|
@@ -21,47 +22,116 @@ npm i wgls-renderer
|
|
|
21
22
|
### 基础使用
|
|
22
23
|
|
|
23
24
|
```typescript
|
|
24
|
-
import { createWGSLRenderer } from 'wgls-renderer'
|
|
25
|
+
import { createWGSLRenderer } from 'wgls-renderer'
|
|
25
26
|
|
|
26
|
-
const canvas = document.getElementById('canvas')
|
|
27
|
-
const renderer = await createWGSLRenderer(canvas
|
|
28
|
-
backgroundColor: 0x66CCFF // 支持多种格式:0xRRGGBB, "#RRGGBB", {r, g, b}
|
|
29
|
-
});
|
|
27
|
+
const canvas = document.getElementById('canvas')
|
|
28
|
+
const renderer = await createWGSLRenderer(canvas)
|
|
30
29
|
|
|
31
30
|
// 创建采样器
|
|
32
|
-
const sampler = renderer.createSampler()
|
|
31
|
+
const sampler = renderer.createSampler()
|
|
33
32
|
|
|
34
|
-
//
|
|
35
|
-
const { texture } = await renderer.
|
|
33
|
+
// 加载图片纹理
|
|
34
|
+
const { texture } = await renderer.loadImageTexture('image.jpg')
|
|
36
35
|
|
|
37
36
|
// 添加Pass 1: 渲染纹理
|
|
38
37
|
renderer.addPass({
|
|
39
38
|
name: 'texture_pass',
|
|
40
39
|
shaderCode: textureShader,
|
|
41
40
|
blendMode: 'alpha',
|
|
42
|
-
resources: [texture
|
|
43
|
-
})
|
|
41
|
+
resources: [texture, sampler], // binding 0, 1
|
|
42
|
+
})
|
|
44
43
|
|
|
45
|
-
// 添加Pass 2: 后处理效果
|
|
46
|
-
const uniforms = renderer.createUniforms(
|
|
44
|
+
// 添加Pass 2: 后处理效果 (自动绑定Pass 1的输出到binding 0)
|
|
45
|
+
const uniforms = renderer.createUniforms(16) // 支持复杂的uniform结构
|
|
47
46
|
renderer.addPass({
|
|
48
47
|
name: 'post_process',
|
|
49
48
|
shaderCode: postProcessShader,
|
|
50
49
|
blendMode: 'alpha',
|
|
51
|
-
resources: [sampler, uniforms.getBuffer()]
|
|
52
|
-
})
|
|
50
|
+
resources: [sampler, uniforms.getBuffer()], // 对应binding 1, 2 (binding 0自动绑定到Pass 1的输出)
|
|
51
|
+
})
|
|
53
52
|
|
|
54
|
-
//
|
|
53
|
+
// 启动循环渲染,可以在回调函数中更新uniforms
|
|
55
54
|
renderer.loopRender(() => {
|
|
56
|
-
|
|
57
|
-
uniforms
|
|
58
|
-
uniforms.values[
|
|
59
|
-
uniforms.values[
|
|
60
|
-
uniforms.
|
|
61
|
-
|
|
55
|
+
|
|
56
|
+
// 更新uniforms (注意WebGPU的内存对齐规则)
|
|
57
|
+
uniforms.values[0] = canvas.width // resolution.x
|
|
58
|
+
uniforms.values[1] = canvas.height // resolution.y
|
|
59
|
+
uniforms.values[2] = performance.now() // time
|
|
60
|
+
uniforms.values[3] = 0 // padding (vec3对齐)
|
|
61
|
+
uniforms.values[4] = 1024 // textureResolution.x
|
|
62
|
+
uniforms.values[5] = 1024 // textureResolution.y
|
|
63
|
+
uniforms.apply()
|
|
64
|
+
})
|
|
62
65
|
|
|
63
66
|
// 或者单帧渲染
|
|
64
|
-
renderer.renderFrame()
|
|
67
|
+
renderer.renderFrame()
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
## 🎨 着色器示例
|
|
72
|
+
|
|
73
|
+
### Pass 1: 纹理渲染
|
|
74
|
+
|
|
75
|
+
```wgsl
|
|
76
|
+
// textureShader
|
|
77
|
+
struct VSOut {
|
|
78
|
+
@builtin(position) pos: vec4<f32>,
|
|
79
|
+
@location(0) uv: vec2<f32>,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
@vertex
|
|
83
|
+
fn vs_main(@location(0) p: vec3<f32>) -> VSOut {
|
|
84
|
+
var o: VSOut;
|
|
85
|
+
o.pos = vec4<f32>(p, 1.0);
|
|
86
|
+
o.uv = p.xy * 0.5 + vec2<f32>(0.5, 0.5);
|
|
87
|
+
o.uv.y = 1.0 - o.uv.y;
|
|
88
|
+
return o;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@group(0) @binding(0) var myTexture: texture_2d<f32>;
|
|
92
|
+
@group(0) @binding(1) var mySampler: sampler;
|
|
93
|
+
|
|
94
|
+
@fragment
|
|
95
|
+
fn fs_main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
|
|
96
|
+
return textureSample(myTexture, mySampler, uv);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Pass 2: 动态后处理效果
|
|
101
|
+
|
|
102
|
+
```wgsl
|
|
103
|
+
// postProcessShader
|
|
104
|
+
struct Uniforms {
|
|
105
|
+
resolution: vec2<f32>, // offset 0-7
|
|
106
|
+
time: f32, // offset 8
|
|
107
|
+
// 4 bytes padding for vec3 alignment
|
|
108
|
+
texResolution: vec2<f32>, // offset 16-23
|
|
109
|
+
speed: f32, // offset 24
|
|
110
|
+
// 8 bytes padding for next vec3
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@group(0) @binding(0) var prevTexture: texture_2d<f32>; // 自动绑定到Pass 1的输出纹理
|
|
114
|
+
@group(0) @binding(1) var mySampler: sampler;
|
|
115
|
+
@group(0) @binding(2) var<uniform> uniforms: Uniforms;
|
|
116
|
+
|
|
117
|
+
@fragment
|
|
118
|
+
fn fs_main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
|
|
119
|
+
var color = textureSample(prevTexture, mySampler, uv);
|
|
120
|
+
|
|
121
|
+
// 动态扫描线效果
|
|
122
|
+
let scanline = 0.8 + 0.2 * sin(uv.y * 600.0 + uniforms.time * 5.0);
|
|
123
|
+
color = vec4<f32>(color.r * scanline, color.g * scanline, color.b * scanline, color.a);
|
|
124
|
+
|
|
125
|
+
// 动态波纹效果
|
|
126
|
+
let waveAmplitude = 0.05 + 0.02 * sin(uniforms.time * 2.0);
|
|
127
|
+
let waveX = sin(uv.x * 10.0 + uniforms.time * 3.0) * cos(uv.y * 8.0 + uniforms.time * 2.0) * waveAmplitude;
|
|
128
|
+
|
|
129
|
+
let finalR = clamp(color.r + waveX, 0.0, 1.0);
|
|
130
|
+
let finalG = clamp(color.g - waveX * 0.5, 0.0, 1.0);
|
|
131
|
+
let finalB = clamp(color.b + waveX * 0.3, 0.0, 1.0);
|
|
132
|
+
|
|
133
|
+
return vec4<f32>(finalR, finalG, finalB, color.a);
|
|
134
|
+
}
|
|
65
135
|
```
|
|
66
136
|
|
|
67
137
|
## 📋 API
|
|
@@ -71,15 +141,32 @@ renderer.renderFrame();
|
|
|
71
141
|
创建WGSL渲染器实例。
|
|
72
142
|
|
|
73
143
|
```typescript
|
|
74
|
-
const renderer = await createWGSLRenderer(canvas
|
|
75
|
-
|
|
76
|
-
|
|
144
|
+
const renderer = await createWGSLRenderer(canvas)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### createUniforms(length)
|
|
148
|
+
|
|
149
|
+
创建uniform变量,length单位为float数量。
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
const myUniforms = renderer.createUniforms(8) // 8个float
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### getContext()
|
|
156
|
+
|
|
157
|
+
获取WebGPU画布上下文。
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const context = renderer.getContext()
|
|
77
161
|
```
|
|
78
162
|
|
|
163
|
+
### getDevice()
|
|
79
164
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
165
|
+
获取WebGPU设备对象。
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
const device = renderer.getDevice()
|
|
169
|
+
```
|
|
83
170
|
|
|
84
171
|
### 渲染控制
|
|
85
172
|
|
|
@@ -87,7 +174,7 @@ const renderer = await createWGSLRenderer(canvas, {
|
|
|
87
174
|
单帧渲染,不循环。
|
|
88
175
|
|
|
89
176
|
```typescript
|
|
90
|
-
renderer.renderFrame()
|
|
177
|
+
renderer.renderFrame()
|
|
91
178
|
```
|
|
92
179
|
|
|
93
180
|
#### loopRender(callback?)
|
|
@@ -95,17 +182,18 @@ renderer.renderFrame();
|
|
|
95
182
|
|
|
96
183
|
```typescript
|
|
97
184
|
renderer.loopRender(() => {
|
|
185
|
+
|
|
98
186
|
// 每帧更新uniforms
|
|
99
|
-
myUniforms.values[0] = performance.now() / 1000.0
|
|
100
|
-
myUniforms.apply()
|
|
101
|
-
})
|
|
187
|
+
myUniforms.values[0] = performance.now() / 1000.0
|
|
188
|
+
myUniforms.apply()
|
|
189
|
+
})
|
|
102
190
|
```
|
|
103
191
|
|
|
104
192
|
#### stopLoop()
|
|
105
193
|
停止循环渲染。
|
|
106
194
|
|
|
107
195
|
```typescript
|
|
108
|
-
renderer.stopLoop()
|
|
196
|
+
renderer.stopLoop()
|
|
109
197
|
```
|
|
110
198
|
|
|
111
199
|
### addPass(descriptor)
|
|
@@ -117,19 +205,32 @@ renderer.addPass({
|
|
|
117
205
|
name: 'my_pass',
|
|
118
206
|
shaderCode: wgslShaderCode,
|
|
119
207
|
blendMode: 'alpha',
|
|
120
|
-
resources: [textureView, sampler]
|
|
121
|
-
})
|
|
208
|
+
resources: [textureView, sampler], // 资源数组
|
|
209
|
+
})
|
|
122
210
|
```
|
|
123
211
|
|
|
124
212
|
**资源数组绑定规则:**
|
|
125
|
-
|
|
126
|
-
- **
|
|
127
|
-
- **Binding
|
|
128
|
-
-
|
|
213
|
+
|
|
214
|
+
- **Pass 1**: 无自动绑定,完全自由
|
|
215
|
+
- **Binding 0**: `resources[0]`
|
|
216
|
+
- **Binding 1**: `resources[1]`
|
|
217
|
+
- 以此类推...
|
|
218
|
+
|
|
219
|
+
- **Pass 2及以上**: 自动绑定上一个pass的输出
|
|
220
|
+
- **Binding 0**: 上一个pass的输出纹理(自动)
|
|
221
|
+
- **Binding 1**: `resources[0]`
|
|
222
|
+
- **Binding 2**: `resources[1]`
|
|
223
|
+
- 以此类推...
|
|
129
224
|
|
|
130
225
|
**对应的WGSL绑定:**
|
|
226
|
+
|
|
131
227
|
```wgsl
|
|
132
|
-
|
|
228
|
+
// Pass 1:
|
|
229
|
+
@group(0) @binding(0) var myTexture: texture_2d<f32>; // resources[0]
|
|
230
|
+
@group(0) @binding(1) var mySampler: sampler; // resources[1]
|
|
231
|
+
|
|
232
|
+
// Pass 2+:
|
|
233
|
+
@group(0) @binding(0) var prevTexture: texture_2d<f32>; // 自动绑定
|
|
133
234
|
@group(0) @binding(1) var myTexture: texture_2d<f32>; // resources[0]
|
|
134
235
|
@group(0) @binding(2) var mySampler: sampler; // resources[1]
|
|
135
236
|
```
|
|
@@ -140,163 +241,148 @@ renderer.addPass({
|
|
|
140
241
|
创建uniform buffer管理对象。
|
|
141
242
|
|
|
142
243
|
```typescript
|
|
143
|
-
const uniforms = renderer.createUniforms(4)
|
|
144
|
-
uniforms.values[0] = 1.0
|
|
145
|
-
uniforms.apply()
|
|
146
|
-
const buffer = uniforms.getBuffer()
|
|
244
|
+
const uniforms = renderer.createUniforms(4) // 4个float
|
|
245
|
+
uniforms.values[0] = 1.0 // 设置值
|
|
246
|
+
uniforms.apply() // 应用到GPU
|
|
247
|
+
const buffer = uniforms.getBuffer() // 获取GPUBuffer
|
|
147
248
|
```
|
|
148
249
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
250
|
+
**JavaScript Uniforms设置 (注意内存对齐):**
|
|
251
|
+
|
|
252
|
+
```javascript
|
|
253
|
+
const uniforms = renderer.createUniforms(16) // 64字节
|
|
254
|
+
uniforms.values[0] = canvas.width // resolution.x
|
|
255
|
+
uniforms.values[1] = canvas.height // resolution.y
|
|
256
|
+
uniforms.values[2] = performance.now() // time
|
|
257
|
+
uniforms.values[3] = 0 // padding (vec3对齐)
|
|
258
|
+
uniforms.values[4] = 1024 // texResolution.x
|
|
259
|
+
uniforms.values[5] = 1024 // texResolution.y
|
|
260
|
+
uniforms.values[6] = 1.0 // speed
|
|
261
|
+
uniforms.values[7] = 0 // padding
|
|
262
|
+
uniforms.values[8] = 0 // padding
|
|
263
|
+
uniforms.apply()
|
|
154
264
|
```
|
|
155
265
|
|
|
156
|
-
##
|
|
157
|
-
|
|
158
|
-
### Pass 1: 纹理渲染
|
|
266
|
+
## 🔧 内置方法
|
|
159
267
|
|
|
160
|
-
|
|
161
|
-
struct VSOut {
|
|
162
|
-
@builtin(position) pos: vec4<f32>,
|
|
163
|
-
@location(0) uv: vec2<f32>,
|
|
164
|
-
};
|
|
268
|
+
### 纹理相关
|
|
165
269
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
o.pos = vec4<f32>(p, 1.0);
|
|
170
|
-
o.uv = p.xy * 0.5 + vec2<f32>(0.5, 0.5);
|
|
171
|
-
o.uv.y = 1.0 - o.uv.y;
|
|
172
|
-
return o;
|
|
173
|
-
}
|
|
270
|
+
```typescript
|
|
271
|
+
// 从url加载图片纹理
|
|
272
|
+
const { texture, width, height } = await renderer.loadImageTexture('image.png')
|
|
174
273
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
@group(0) @binding(2) var mySampler: sampler;
|
|
274
|
+
// 创建采样器
|
|
275
|
+
const sampler = renderer.createSampler()
|
|
178
276
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
1.0
|
|
190
|
-
);
|
|
191
|
-
}
|
|
277
|
+
// 绑定到Pass
|
|
278
|
+
const textureView = texture.createView()
|
|
279
|
+
renderer.addPass({
|
|
280
|
+
name: 'texture-pass',
|
|
281
|
+
shaderCode: shaderCode,
|
|
282
|
+
resources: [
|
|
283
|
+
textureView,
|
|
284
|
+
sampler,
|
|
285
|
+
],
|
|
286
|
+
})
|
|
192
287
|
```
|
|
193
288
|
|
|
194
|
-
### Pass 2: 动态后处理效果
|
|
195
|
-
|
|
196
289
|
```wgsl
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
resolution: vec2<f32>,
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
@group(0) @binding(0) var prevTexture: texture_2d<f32>; // Pass 1的输出纹理
|
|
290
|
+
// 如果是Pass 1:
|
|
291
|
+
@group(0) @binding(0) var myTexture: texture_2d<f32>;
|
|
203
292
|
@group(0) @binding(1) var mySampler: sampler;
|
|
204
|
-
@group(0) @binding(2) var<uniform> uniforms: Uniforms;
|
|
205
|
-
|
|
206
|
-
@fragment
|
|
207
|
-
fn fs_main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
|
|
208
|
-
var color = textureSample(prevTexture, mySampler, uv);
|
|
209
|
-
|
|
210
|
-
// 动态扫描线效果
|
|
211
|
-
let scanline = 0.8 + 0.2 * sin(uv.y * 600.0 + uniforms.time * 5.0);
|
|
212
|
-
color = vec4<f32>(color.r * scanline, color.g * scanline, color.b * scanline, color.a);
|
|
213
293
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
294
|
+
// 如果是Pass 2及以后:
|
|
295
|
+
@group(0) @binding(0) var prevTexture: texture_2d<f32>; // 自动绑定,上一个Pass的输出纹理
|
|
296
|
+
@group(0) @binding(1) var myTexture: texture_2d<f32>;
|
|
297
|
+
@group(0) @binding(2) var mySampler: sampler;
|
|
298
|
+
```
|
|
217
299
|
|
|
218
|
-
|
|
219
|
-
let finalG = clamp(color.g - waveX * 0.5, 0.0, 1.0);
|
|
220
|
-
let finalB = clamp(color.b + waveX * 0.3, 0.0, 1.0);
|
|
300
|
+
### Uniform变量
|
|
221
301
|
|
|
222
|
-
|
|
223
|
-
|
|
302
|
+
```typescript
|
|
303
|
+
// 创建uniform buffer,length单位为float数量
|
|
304
|
+
const uniforms = renderer.createUniforms(8) // 8个float (32字节)
|
|
305
|
+
uniforms.values[0] = 1.0 // 设置第一个float值
|
|
306
|
+
uniforms.values[1] = 0.5 // 设置第二个float值
|
|
307
|
+
uniforms.values[2] = 0.25 // 设置第三个float值
|
|
308
|
+
// 向量值需要内存对齐,这里的offset必须是4的倍数,因此跳过uniforms.values[3]
|
|
309
|
+
uniforms.values[4] = 1.0 // texResolution.x
|
|
310
|
+
uniforms.values[5] = 1024.0 // texResolution.y
|
|
311
|
+
|
|
312
|
+
uniforms.apply() // 应用到GPU
|
|
313
|
+
const uniformBuffer = uniforms.getBuffer() // 获取GPUBuffer
|
|
314
|
+
|
|
315
|
+
// 绑定到Pass
|
|
316
|
+
renderer.addPass({
|
|
317
|
+
name: 'uniform-pass',
|
|
318
|
+
shaderCode: shaderCode,
|
|
319
|
+
resources: [
|
|
320
|
+
|
|
321
|
+
// 数组第0项,Pass 1着色器中对应@group(0) @binding(0),Pass2及以后的着色器中是@group(0) @binding(1)
|
|
322
|
+
uniformBuffer,
|
|
323
|
+
],
|
|
324
|
+
})
|
|
224
325
|
```
|
|
225
326
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
327
|
+
```wgsl
|
|
328
|
+
struct Uniforms {
|
|
329
|
+
value1: f32, // 对应 uniforms.values[0]
|
|
330
|
+
value2: f32, // 对应 uniforms.values[1]
|
|
331
|
+
value3: f32, // 对应 uniforms.values[2]
|
|
332
|
+
textureResolution: vec2<f32>, // x, y分别对应 uniforms.values[4], uniforms.values[5]
|
|
333
|
+
// ...
|
|
334
|
+
}
|
|
229
335
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const { texture, width, height } = await renderer.loadTexture('image.png');
|
|
336
|
+
// 如果是Pass 1:
|
|
337
|
+
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
|
233
338
|
|
|
234
|
-
//
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
minFilter: 'linear',
|
|
238
|
-
addressModeU: 'clamp-to-edge',
|
|
239
|
-
addressModeV: 'clamp-to-edge',
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
// 创建纹理绑定
|
|
243
|
-
const textureView = renderer.createTextureBinding(texture);
|
|
339
|
+
// 如果是Pass 2及以后:
|
|
340
|
+
@group(0) @binding(0) var prevTexture: texture_2d<f32>; // 自动绑定,上一个Pass的输出纹理
|
|
341
|
+
@group(0) @binding(1) var<uniform> uniforms: Uniforms;
|
|
244
342
|
```
|
|
245
343
|
|
|
246
344
|
### 控制相关
|
|
247
345
|
|
|
248
346
|
```typescript
|
|
249
347
|
// 调整画布大小
|
|
250
|
-
renderer.resize(800, 600)
|
|
348
|
+
renderer.resize(800, 600)
|
|
251
349
|
|
|
252
350
|
// 停止渲染
|
|
253
|
-
renderer.stopLoop()
|
|
351
|
+
renderer.stopLoop()
|
|
254
352
|
```
|
|
255
353
|
|
|
256
354
|
## 🎯 Pass流程
|
|
257
355
|
|
|
258
356
|
渲染器自动管理以下pass流程:
|
|
259
357
|
|
|
260
|
-
1. **
|
|
261
|
-
-
|
|
358
|
+
1. **User Pass 1**
|
|
359
|
+
- 无自动绑定,完全自由
|
|
360
|
+
- Binding 0+: 用户资源
|
|
262
361
|
- 输出到 `pass_0_output`
|
|
263
362
|
|
|
264
|
-
2. **User Pass
|
|
265
|
-
- Binding 0:
|
|
363
|
+
2. **User Pass 2**
|
|
364
|
+
- Binding 0: Pass 1输出纹理(自动)
|
|
266
365
|
- Binding 1+: 用户资源
|
|
267
366
|
- 输出到 `pass_1_output`
|
|
268
367
|
|
|
269
|
-
3. **User Pass
|
|
270
|
-
- Binding 0:
|
|
368
|
+
3. **User Pass 3+**
|
|
369
|
+
- Binding 0: 上一个pass输出纹理(自动)
|
|
271
370
|
- Binding 1+: 用户资源
|
|
272
|
-
- 输出到 `
|
|
371
|
+
- 输出到 `pass_N-1_output`
|
|
273
372
|
|
|
274
373
|
4. **Final Pass**
|
|
275
|
-
- Binding 0: 上一个pass
|
|
374
|
+
- Binding 0: 上一个pass输出纹理(自动)
|
|
375
|
+
- Binding 1+: 用户资源
|
|
276
376
|
- 渲染到canvas
|
|
277
377
|
|
|
278
|
-
## 📁 项目结构
|
|
279
|
-
|
|
280
|
-
```
|
|
281
|
-
src/
|
|
282
|
-
├── index.ts # 主渲染器类,包含完整的API
|
|
283
|
-
├── RenderPass.ts # Pass渲染逻辑和类型定义
|
|
284
|
-
├── TextureManager.ts # 纹理管理
|
|
285
|
-
examples/
|
|
286
|
-
└── multi-pass-demo.html # 完整示例,包含纹理、动态uniforms效果
|
|
287
|
-
```
|
|
288
|
-
|
|
289
378
|
## 🛠️ 开发
|
|
290
379
|
|
|
291
380
|
```bash
|
|
292
381
|
# 开发模式
|
|
293
|
-
|
|
382
|
+
pnpm dev
|
|
294
383
|
|
|
295
384
|
# 构建
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
# 类型检查
|
|
299
|
-
npm run type-check
|
|
385
|
+
pnpm build
|
|
300
386
|
```
|
|
301
387
|
|
|
302
388
|
## 📝 许可证
|