1
1
/* eslint-disable prettier/prettier */
2
2
import { mat4 , mat3 } from 'wgpu-matrix' ;
3
+ import { GUI } from 'dat.gui' ;
3
4
import { modelData } from './models' ;
5
+ import { randElement , randColor } from './utils' ;
4
6
import solidColorLitWGSL from './solidColorLit.wgsl' ;
5
7
import wireframeWGSL from './wireframe.wgsl' ;
6
8
@@ -9,11 +11,11 @@ type TypedArrayView = Float32Array | Uint32Array;
9
11
function createBufferWithData (
10
12
device : GPUDevice ,
11
13
data : TypedArrayView ,
12
- usage : number
14
+ usage : GPUBufferUsageFlags ,
13
15
) {
14
16
const buffer = device . createBuffer ( {
15
17
size : data . byteLength ,
16
- usage : usage ,
18
+ usage,
17
19
} ) ;
18
20
device . queue . writeBuffer ( buffer , 0 , data ) ;
19
21
return buffer ;
@@ -66,25 +68,6 @@ const depthFormat = 'depth24plus';
66
68
67
69
const models = Object . values ( modelData ) . map ( data => createVertexAndIndexBuffer ( device , data ) ) ;
68
70
69
- function rand ( min ?: number , max ?: number ) {
70
- if ( min === undefined ) {
71
- max = 1 ;
72
- min = 0 ;
73
- } else if ( max === undefined ) {
74
- max = min ;
75
- min = 0 ;
76
- }
77
- return Math . random ( ) * ( max - min ) + min ;
78
- }
79
-
80
- function randInt ( min : number , max ?: number ) {
81
- return Math . floor ( rand ( min , max ) ) ;
82
- }
83
-
84
- function randColor ( ) {
85
- return [ rand ( ) , rand ( ) , rand ( ) , 1 ] ;
86
- }
87
-
88
71
const litModule = device . createShaderModule ( {
89
72
code : solidColorLitWGSL ,
90
73
} ) ;
@@ -141,6 +124,7 @@ const wireframePipeline = device.createRenderPipeline({
141
124
} ,
142
125
fragment : {
143
126
module : wireframeModule ,
127
+ entryPoint : 'fs' ,
144
128
targets : [ { format : presentationFormat } ] ,
145
129
} ,
146
130
primitive : {
@@ -153,13 +137,51 @@ const wireframePipeline = device.createRenderPipeline({
153
137
} ,
154
138
} ) ;
155
139
140
+ const barycentricCoordinatesBasedWireframePipeline = device . createRenderPipeline ( {
141
+ label : 'barycentric coordinates based wireframe pipeline' ,
142
+ layout : 'auto' ,
143
+ vertex : {
144
+ module : wireframeModule ,
145
+ entryPoint : 'vsIndexedU32BarycentricCoordinateBasedLines' ,
146
+ } ,
147
+ fragment : {
148
+ module : wireframeModule ,
149
+ entryPoint : 'fsBarycentricCoordinateBasedLines' ,
150
+ targets : [
151
+ {
152
+ format : presentationFormat ,
153
+ blend : {
154
+ color : {
155
+ srcFactor : 'one' ,
156
+ dstFactor : 'one-minus-src-alpha' ,
157
+ } ,
158
+ alpha : {
159
+ srcFactor : 'one' ,
160
+ dstFactor : 'one-minus-src-alpha' ,
161
+ } ,
162
+ } ,
163
+ } ,
164
+ ] ,
165
+ } ,
166
+ primitive : {
167
+ topology : 'triangle-list' ,
168
+ } ,
169
+ depthStencil : {
170
+ depthWriteEnabled : true ,
171
+ depthCompare : 'less-equal' ,
172
+ format : depthFormat ,
173
+ } ,
174
+ } ) ;
175
+
156
176
type ObjectInfo = {
157
177
worldViewProjectionMatrixValue : Float32Array ;
158
178
worldMatrixValue : Float32Array ;
159
179
uniformValues : Float32Array ;
160
180
uniformBuffer : GPUBuffer ;
181
+ lineUniformValues : Float32Array ;
182
+ lineUniformBuffer : GPUBuffer ;
161
183
litBindGroup : GPUBindGroup ;
162
- wireframeBindGroup : GPUBindGroup ;
184
+ wireframeBindGroups : GPUBindGroup [ ] ;
163
185
model : Model ;
164
186
} ;
165
187
@@ -187,29 +209,47 @@ for (let i = 0; i < numObjects; ++i) {
187
209
const colorValue = uniformValues . subarray ( kColorOffset , kColorOffset + 4 ) ;
188
210
colorValue . set ( randColor ( ) ) ;
189
211
190
- const model = models [ randInt ( models . length ) ] ;
212
+ const model = randElement ( models ) ;
191
213
192
214
// Make a bind group for this uniform
193
215
const litBindGroup = device . createBindGroup ( {
194
216
layout : litPipeline . getBindGroupLayout ( 0 ) ,
195
217
entries : [ { binding : 0 , resource : { buffer : uniformBuffer } } ] ,
196
218
} ) ;
197
219
198
- const strideValues = new Uint32Array ( 1 + 3 ) ;
199
- const strideBuffer = device . createBuffer ( {
200
- size : strideValues . byteLength ,
220
+ // Note: We're making one lineUniformBuffer per object.
221
+ // This is only because stride might be different per object.
222
+ // In this sample stride is the same across all objects so
223
+ // we could have made just a single shared uniform buffer for
224
+ // these settings.
225
+ const lineUniformValues = new Float32Array ( 3 + 1 ) ;
226
+ const lineUniformValuesAsU32 = new Uint32Array ( lineUniformValues . buffer ) ;
227
+ const lineUniformBuffer = device . createBuffer ( {
228
+ size : lineUniformValues . byteLength ,
201
229
usage : GPUBufferUsage . UNIFORM | GPUBufferUsage . COPY_DST ,
202
230
} ) ;
203
- strideValues [ 0 ] = 6 ;
204
- device . queue . writeBuffer ( strideBuffer , 0 , strideValues ) ;
231
+ lineUniformValuesAsU32 [ 0 ] = 6 ; // the array stride for positions for this model.
205
232
233
+ // We're creating 2 bindGroups, one for each pipeline.
234
+ // We could create just one since they are identical. To do
235
+ // so we'd have to manually create a bindGroupLayout.
206
236
const wireframeBindGroup = device . createBindGroup ( {
207
237
layout : wireframePipeline . getBindGroupLayout ( 0 ) ,
208
238
entries : [
209
239
{ binding : 0 , resource : { buffer : uniformBuffer } } ,
210
240
{ binding : 1 , resource : { buffer : model . vertexBuffer } } ,
211
241
{ binding : 2 , resource : { buffer : model . indexBuffer } } ,
212
- { binding : 3 , resource : { buffer : strideBuffer } } ,
242
+ { binding : 3 , resource : { buffer : lineUniformBuffer } } ,
243
+ ] ,
244
+ } ) ;
245
+
246
+ const barycentricCoordinatesBasedWireframeBindGroup = device . createBindGroup ( {
247
+ layout : barycentricCoordinatesBasedWireframePipeline . getBindGroupLayout ( 0 ) ,
248
+ entries : [
249
+ { binding : 0 , resource : { buffer : uniformBuffer } } ,
250
+ { binding : 1 , resource : { buffer : model . vertexBuffer } } ,
251
+ { binding : 2 , resource : { buffer : model . indexBuffer } } ,
252
+ { binding : 3 , resource : { buffer : lineUniformBuffer } } ,
213
253
] ,
214
254
} ) ;
215
255
@@ -218,8 +258,13 @@ for (let i = 0; i < numObjects; ++i) {
218
258
worldMatrixValue,
219
259
uniformValues,
220
260
uniformBuffer,
261
+ lineUniformValues,
262
+ lineUniformBuffer,
221
263
litBindGroup,
222
- wireframeBindGroup,
264
+ wireframeBindGroups : [
265
+ wireframeBindGroup ,
266
+ barycentricCoordinatesBasedWireframeBindGroup ,
267
+ ] ,
223
268
model,
224
269
} ) ;
225
270
}
@@ -242,7 +287,45 @@ const renderPassDescriptor: GPURenderPassDescriptor = {
242
287
} ,
243
288
} ;
244
289
245
- let depthTexture ;
290
+ const settings = {
291
+ barycentricCoordinatesBased : false ,
292
+ thickness : 2 ,
293
+ alphaThreshold : 0.5 ,
294
+ lines : true ,
295
+ models : true ,
296
+ } ;
297
+
298
+ const gui = new GUI ( ) ;
299
+ gui . add ( settings , 'barycentricCoordinatesBased' ) . onChange ( addRemoveGUI ) ;
300
+ gui . add ( settings , 'lines' ) ;
301
+ gui . add ( settings , 'models' ) ;
302
+
303
+ const guis = [ ] ;
304
+ function addRemoveGUI ( ) {
305
+ if ( settings . barycentricCoordinatesBased ) {
306
+ guis . push (
307
+ gui . add ( settings , 'thickness' , 0.0 , 10 ) . onChange ( updateThickness ) ,
308
+ gui . add ( settings , 'alphaThreshold' , 0 , 1 ) . onChange ( updateThickness ) ,
309
+ ) ;
310
+ } else {
311
+ guis . forEach ( g => g . remove ( ) ) ;
312
+ guis . length = 0 ;
313
+ }
314
+ }
315
+
316
+ function updateThickness ( ) {
317
+ objectInfos . forEach ( ( {
318
+ lineUniformBuffer,
319
+ lineUniformValues,
320
+ } ) => {
321
+ lineUniformValues [ 1 ] = settings . thickness ;
322
+ lineUniformValues [ 2 ] = settings . alphaThreshold ;
323
+ device . queue . writeBuffer ( lineUniformBuffer , 0 , lineUniformValues ) ;
324
+ } ) ;
325
+ }
326
+ updateThickness ( ) ;
327
+
328
+ let depthTexture : GPUTexture | undefined ;
246
329
247
330
function render ( time : number ) {
248
331
time *= 0.001 ; // convert to seconds;
@@ -311,20 +394,27 @@ function render(time: number) {
311
394
// Upload our uniform values.
312
395
device . queue . writeBuffer ( uniformBuffer , 0 , uniformValues ) ;
313
396
314
- pass . setVertexBuffer ( 0 , vertexBuffer ) ;
315
- pass . setIndexBuffer ( indexBuffer , indexFormat ) ;
316
- pass . setBindGroup ( 0 , litBindGroup ) ;
317
- pass . drawIndexed ( vertexCount ) ;
397
+ if ( settings . models ) {
398
+ pass . setVertexBuffer ( 0 , vertexBuffer ) ;
399
+ pass . setIndexBuffer ( indexBuffer , indexFormat ) ;
400
+ pass . setBindGroup ( 0 , litBindGroup ) ;
401
+ pass . drawIndexed ( vertexCount ) ;
402
+ }
318
403
} ) ;
319
404
320
- objectInfos . forEach ( ( {
321
- wireframeBindGroup,
322
- model : { vertexCount } ,
323
- } ) => {
324
- pass . setPipeline ( wireframePipeline ) ;
325
- pass . setBindGroup ( 0 , wireframeBindGroup )
326
- pass . draw ( vertexCount * 2 ) ;
327
- } ) ;
405
+ if ( settings . lines ) {
406
+ // Note: If we're using the line-list based pipeline then we need to
407
+ // multiply the vertex count by 2 since we need to emit 6 vertices
408
+ // for each triangle (3 edges).
409
+ const [ bindGroupNdx , countMult , pipeline ] = settings . barycentricCoordinatesBased
410
+ ? [ 1 , 1 , barycentricCoordinatesBasedWireframePipeline ]
411
+ : [ 0 , 2 , wireframePipeline ] ;
412
+ pass . setPipeline ( pipeline ) ;
413
+ objectInfos . forEach ( ( { wireframeBindGroups, model : { vertexCount } } ) => {
414
+ pass . setBindGroup ( 0 , wireframeBindGroups [ bindGroupNdx ] ) ;
415
+ pass . draw ( vertexCount * countMult ) ;
416
+ } ) ;
417
+ }
328
418
329
419
pass . end ( ) ;
330
420
0 commit comments