11/* eslint-disable prettier/prettier */
22import { mat4 , mat3 } from 'wgpu-matrix' ;
3+ import { GUI } from 'dat.gui' ;
34import { modelData } from './models' ;
5+ import { randElement , randColor } from './utils' ;
46import solidColorLitWGSL from './solidColorLit.wgsl' ;
57import wireframeWGSL from './wireframe.wgsl' ;
68
@@ -9,11 +11,11 @@ type TypedArrayView = Float32Array | Uint32Array;
911function createBufferWithData (
1012 device : GPUDevice ,
1113 data : TypedArrayView ,
12- usage : number
14+ usage : GPUBufferUsageFlags ,
1315) {
1416 const buffer = device . createBuffer ( {
1517 size : data . byteLength ,
16- usage : usage ,
18+ usage,
1719 } ) ;
1820 device . queue . writeBuffer ( buffer , 0 , data ) ;
1921 return buffer ;
@@ -66,25 +68,6 @@ const depthFormat = 'depth24plus';
6668
6769const models = Object . values ( modelData ) . map ( data => createVertexAndIndexBuffer ( device , data ) ) ;
6870
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-
8871const litModule = device . createShaderModule ( {
8972 code : solidColorLitWGSL ,
9073} ) ;
@@ -141,6 +124,7 @@ const wireframePipeline = device.createRenderPipeline({
141124 } ,
142125 fragment : {
143126 module : wireframeModule ,
127+ entryPoint : 'fs' ,
144128 targets : [ { format : presentationFormat } ] ,
145129 } ,
146130 primitive : {
@@ -153,13 +137,51 @@ const wireframePipeline = device.createRenderPipeline({
153137 } ,
154138} ) ;
155139
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+
156176type ObjectInfo = {
157177 worldViewProjectionMatrixValue : Float32Array ;
158178 worldMatrixValue : Float32Array ;
159179 uniformValues : Float32Array ;
160180 uniformBuffer : GPUBuffer ;
181+ lineUniformValues : Float32Array ;
182+ lineUniformBuffer : GPUBuffer ;
161183 litBindGroup : GPUBindGroup ;
162- wireframeBindGroup : GPUBindGroup ;
184+ wireframeBindGroups : GPUBindGroup [ ] ;
163185 model : Model ;
164186} ;
165187
@@ -187,29 +209,47 @@ for (let i = 0; i < numObjects; ++i) {
187209 const colorValue = uniformValues . subarray ( kColorOffset , kColorOffset + 4 ) ;
188210 colorValue . set ( randColor ( ) ) ;
189211
190- const model = models [ randInt ( models . length ) ] ;
212+ const model = randElement ( models ) ;
191213
192214 // Make a bind group for this uniform
193215 const litBindGroup = device . createBindGroup ( {
194216 layout : litPipeline . getBindGroupLayout ( 0 ) ,
195217 entries : [ { binding : 0 , resource : { buffer : uniformBuffer } } ] ,
196218 } ) ;
197219
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 ,
201229 usage : GPUBufferUsage . UNIFORM | GPUBufferUsage . COPY_DST ,
202230 } ) ;
203- strideValues [ 0 ] = 6 ;
204- device . queue . writeBuffer ( strideBuffer , 0 , strideValues ) ;
231+ lineUniformValuesAsU32 [ 0 ] = 6 ; // the array stride for positions for this model.
205232
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.
206236 const wireframeBindGroup = device . createBindGroup ( {
207237 layout : wireframePipeline . getBindGroupLayout ( 0 ) ,
208238 entries : [
209239 { binding : 0 , resource : { buffer : uniformBuffer } } ,
210240 { binding : 1 , resource : { buffer : model . vertexBuffer } } ,
211241 { 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 } } ,
213253 ] ,
214254 } ) ;
215255
@@ -218,8 +258,13 @@ for (let i = 0; i < numObjects; ++i) {
218258 worldMatrixValue,
219259 uniformValues,
220260 uniformBuffer,
261+ lineUniformValues,
262+ lineUniformBuffer,
221263 litBindGroup,
222- wireframeBindGroup,
264+ wireframeBindGroups : [
265+ wireframeBindGroup ,
266+ barycentricCoordinatesBasedWireframeBindGroup ,
267+ ] ,
223268 model,
224269 } ) ;
225270}
@@ -242,7 +287,45 @@ const renderPassDescriptor: GPURenderPassDescriptor = {
242287 } ,
243288} ;
244289
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 ;
246329
247330function render ( time : number ) {
248331 time *= 0.001 ; // convert to seconds;
@@ -311,20 +394,27 @@ function render(time: number) {
311394 // Upload our uniform values.
312395 device . queue . writeBuffer ( uniformBuffer , 0 , uniformValues ) ;
313396
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+ }
318403 } ) ;
319404
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+ }
328418
329419 pass . end ( ) ;
330420
0 commit comments