@@ -30,24 +30,34 @@ import { ShaderLanguage } from "core/Materials/shaderLanguage";
3030export class _IblShadowsVoxelRenderer {
3131 private _scene : Scene ;
3232 private _engine : Engine ;
33- private _voxelGridRT : ProceduralTexture ;
33+
34+ // WebGPU, single-pass voxelization.
35+ // See https://playground.babylonjs.com/#XSNYAU#133
36+ private _voxelGrid : RenderTargetTexture ;
37+ private _voxelGridRT : RenderTargetTexture ;
38+
39+ // WebGL voxelization, including tri-planar voxelization.
40+ private _combinedVoxelGridPT : ProceduralTexture ;
3441 private _voxelGridXaxis : RenderTargetTexture ;
3542 private _voxelGridYaxis : RenderTargetTexture ;
3643 private _voxelGridZaxis : RenderTargetTexture ;
3744 private _voxelMrtsXaxis : MultiRenderTarget [ ] = [ ] ;
3845 private _voxelMrtsYaxis : MultiRenderTarget [ ] = [ ] ;
3946 private _voxelMrtsZaxis : MultiRenderTarget [ ] = [ ] ;
40- private _isVoxelGrid3D : boolean = true ;
47+
4148 private _voxelMaterial : ShaderMaterial ;
4249 private _voxelSlabDebugMaterial : ShaderMaterial ;
50+ private _voxelClearColor : Color4 = new Color4 ( 0 , 0 , 0 , 1 ) ;
4351
4452 /**
4553 * Return the voxel grid texture.
4654 * @returns The voxel grid texture.
4755 */
4856 public getVoxelGrid ( ) : ProceduralTexture | RenderTargetTexture {
49- if ( this . _triPlanarVoxelization ) {
50- return this . _voxelGridRT ;
57+ if ( this . _engine . isWebGPU ) {
58+ return this . _voxelGrid ;
59+ } else if ( this . _triPlanarVoxelization ) {
60+ return this . _combinedVoxelGridPT ;
5161 } else {
5262 return this . _voxelGridZaxis ;
5363 }
@@ -85,6 +95,11 @@ export class _IblShadowsVoxelRenderer {
8595 * Whether to use tri-planar voxelization. More expensive, but can help with artifacts.
8696 */
8797 public set triPlanarVoxelization ( enabled : boolean ) {
98+ if ( this . _engine . isWebGPU ) {
99+ // WebGPU only supports tri-planar voxelization.
100+ this . _triPlanarVoxelization = true ;
101+ return ;
102+ }
88103 if ( this . _triPlanarVoxelization === enabled ) {
89104 return ;
90105 }
@@ -238,22 +253,14 @@ export class _IblShadowsVoxelRenderer {
238253 reusable : false ,
239254 shaderLanguage : isWebGPU ? ShaderLanguage . WGSL : ShaderLanguage . GLSL ,
240255 extraInitializations : ( useWebGPU : boolean , list : Promise < any > [ ] ) => {
241- if ( this . _isVoxelGrid3D ) {
242- if ( useWebGPU ) {
243- list . push ( import ( "../../ShadersWGSL/iblVoxelGrid3dDebug.fragment" ) ) ;
244- } else {
245- list . push ( import ( "../../Shaders/iblVoxelGrid3dDebug.fragment" ) ) ;
246- }
247- return ;
248- }
249256 if ( useWebGPU ) {
250- list . push ( import ( "../../ShadersWGSL/iblVoxelGrid2dArrayDebug .fragment" ) ) ;
257+ list . push ( import ( "../../ShadersWGSL/iblVoxelGrid3dDebug .fragment" ) ) ;
251258 } else {
252- list . push ( import ( "../../Shaders/iblVoxelGrid2dArrayDebug .fragment" ) ) ;
259+ list . push ( import ( "../../Shaders/iblVoxelGrid3dDebug .fragment" ) ) ;
253260 }
254261 } ,
255262 } ;
256- this . _voxelDebugPass = new PostProcess ( this . debugPassName , this . _isVoxelGrid3D ? "iblVoxelGrid3dDebug" : "iblVoxelGrid2dArrayDebug ", debugOptions ) ;
263+ this . _voxelDebugPass = new PostProcess ( this . debugPassName , "iblVoxelGrid3dDebug" , debugOptions ) ;
257264 this . _voxelDebugPass . onApplyObservable . add ( ( effect ) => {
258265 if ( this . _voxelDebugAxis === 0 ) {
259266 effect . setTexture ( "voxelTexture" , this . _voxelGridXaxis ) ;
@@ -276,13 +283,13 @@ export class _IblShadowsVoxelRenderer {
276283 * @param scene Scene to attach to
277284 * @param iblShadowsRenderPipeline The render pipeline this pass is associated with
278285 * @param resolutionExp Resolution of the voxel grid. The final resolution will be 2^resolutionExp.
279- * @param triPlanarVoxelization Whether to use tri-planar voxelization. More expensive, but can help with artifacts .
286+ * @param triPlanarVoxelization Whether to use tri-planar voxelization. Only applies to WebGL. Voxelization will take longer but will reduce missing geometry .
280287 * @returns The voxel renderer
281288 */
282289 constructor ( scene : Scene , iblShadowsRenderPipeline : IblShadowsRenderPipeline , resolutionExp : number = 6 , triPlanarVoxelization : boolean = true ) {
283290 this . _scene = scene ;
284291 this . _engine = scene . getEngine ( ) as Engine ;
285- this . _triPlanarVoxelization = triPlanarVoxelization ;
292+ this . _triPlanarVoxelization = this . _engine . isWebGPU || triPlanarVoxelization ;
286293 if ( ! this . _engine . getCaps ( ) . drawBuffersExtension ) {
287294 Logger . Error ( "Can't do voxel rendering without the draw buffers extension." ) ;
288295 }
@@ -374,14 +381,13 @@ export class _IblShadowsVoxelRenderer {
374381 const size : TextureSize = {
375382 width : this . _voxelResolution ,
376383 height : this . _voxelResolution ,
377- layers : this . _isVoxelGrid3D ? undefined : this . _voxelResolution ,
378- depth : this . _isVoxelGrid3D ? this . _voxelResolution : undefined ,
384+ depth : this . _voxelResolution ,
379385 } ;
380386 const voxelAxisOptions : RenderTargetTextureOptions = {
381387 generateDepthBuffer : false ,
382388 generateMipMaps : false ,
383389 type : Constants . TEXTURETYPE_UNSIGNED_BYTE ,
384- format : Constants . TEXTUREFORMAT_R ,
390+ format : Constants . TEXTUREFORMAT_RGBA ,
385391 samplingMode : Constants . TEXTURE_NEAREST_SAMPLINGMODE ,
386392 } ;
387393
@@ -403,24 +409,36 @@ export class _IblShadowsVoxelRenderer {
403409 }
404410 } ,
405411 } ;
406- if ( this . _triPlanarVoxelization ) {
412+ if ( this . _engine . isWebGPU ) {
413+ this . _voxelGrid = new RenderTargetTexture ( "voxelGrid" , size , this . _scene , {
414+ ...voxelCombinedOptions ,
415+ format : Constants . TEXTUREFORMAT_RGBA ,
416+ creationFlags : Constants . TEXTURE_CREATIONFLAG_STORAGE ,
417+ } ) ;
418+ this . _voxelGridRT = new RenderTargetTexture (
419+ "voxelGridRT" ,
420+ { width : Math . min ( size . width * 2.0 , 2048 ) , height : Math . min ( size . height * 2.0 , 2048 ) } ,
421+ this . _scene ,
422+ voxelAxisOptions
423+ ) ;
424+ } else if ( this . _triPlanarVoxelization ) {
407425 this . _voxelGridXaxis = new RenderTargetTexture ( "voxelGridXaxis" , size , this . _scene , voxelAxisOptions ) ;
408426 this . _voxelGridYaxis = new RenderTargetTexture ( "voxelGridYaxis" , size , this . _scene , voxelAxisOptions ) ;
409427 this . _voxelGridZaxis = new RenderTargetTexture ( "voxelGridZaxis" , size , this . _scene , voxelAxisOptions ) ;
410428 this . _voxelMrtsXaxis = this . _createVoxelMRTs ( "x_axis_" , this . _voxelGridXaxis , numSlabs ) ;
411429 this . _voxelMrtsYaxis = this . _createVoxelMRTs ( "y_axis_" , this . _voxelGridYaxis , numSlabs ) ;
412430 this . _voxelMrtsZaxis = this . _createVoxelMRTs ( "z_axis_" , this . _voxelGridZaxis , numSlabs ) ;
413431
414- this . _voxelGridRT = new ProceduralTexture ( "combinedVoxelGrid" , size , "iblCombineVoxelGrids" , this . _scene , voxelCombinedOptions , false ) ;
415- this . _scene . proceduralTextures . splice ( this . _scene . proceduralTextures . indexOf ( this . _voxelGridRT ) , 1 ) ;
416- this . _voxelGridRT . setFloat ( "layer" , 0.0 ) ;
417- this . _voxelGridRT . setTexture ( "voxelXaxisSampler" , this . _voxelGridXaxis ) ;
418- this . _voxelGridRT . setTexture ( "voxelYaxisSampler" , this . _voxelGridYaxis ) ;
419- this . _voxelGridRT . setTexture ( "voxelZaxisSampler" , this . _voxelGridZaxis ) ;
432+ this . _combinedVoxelGridPT = new ProceduralTexture ( "combinedVoxelGrid" , size , "iblCombineVoxelGrids" , this . _scene , voxelCombinedOptions , false ) ;
433+ this . _scene . proceduralTextures . splice ( this . _scene . proceduralTextures . indexOf ( this . _combinedVoxelGridPT ) , 1 ) ;
434+ this . _combinedVoxelGridPT . setFloat ( "layer" , 0.0 ) ;
435+ this . _combinedVoxelGridPT . setTexture ( "voxelXaxisSampler" , this . _voxelGridXaxis ) ;
436+ this . _combinedVoxelGridPT . setTexture ( "voxelYaxisSampler" , this . _voxelGridYaxis ) ;
437+ this . _combinedVoxelGridPT . setTexture ( "voxelZaxisSampler" , this . _voxelGridZaxis ) ;
420438 // We will render this only after voxelization is completed for the 3 axes.
421- this . _voxelGridRT . autoClear = false ;
422- this . _voxelGridRT . wrapU = Texture . CLAMP_ADDRESSMODE ;
423- this . _voxelGridRT . wrapV = Texture . CLAMP_ADDRESSMODE ;
439+ this . _combinedVoxelGridPT . autoClear = false ;
440+ this . _combinedVoxelGridPT . wrapU = Texture . CLAMP_ADDRESSMODE ;
441+ this . _combinedVoxelGridPT . wrapV = Texture . CLAMP_ADDRESSMODE ;
424442 } else {
425443 this . _voxelGridZaxis = new RenderTargetTexture ( "voxelGridZaxis" , size , this . _scene , voxelCombinedOptions ) ;
426444 this . _voxelMrtsZaxis = this . _createVoxelMRTs ( "z_axis_" , this . _voxelGridZaxis , numSlabs ) ;
@@ -464,7 +482,7 @@ export class _IblShadowsVoxelRenderer {
464482 voxelRT . wrapV = Texture . CLAMP_ADDRESSMODE ;
465483 voxelRT . noPrePassRenderer = true ;
466484 const mrtArray : MultiRenderTarget [ ] = [ ] ;
467- const targetTypes = new Array ( this . _maxDrawBuffers ) . fill ( this . _isVoxelGrid3D ? Constants . TEXTURE_3D : Constants . TEXTURE_2D_ARRAY ) ;
485+ const targetTypes = new Array ( this . _maxDrawBuffers ) . fill ( Constants . TEXTURE_3D ) ;
468486
469487 for ( let mrtIndex = 0 ; mrtIndex < numSlabs ; mrtIndex ++ ) {
470488 let layerIndices = new Array ( this . _maxDrawBuffers ) . fill ( 0 ) ;
@@ -475,7 +493,7 @@ export class _IblShadowsVoxelRenderer {
475493
476494 const mrt = new MultiRenderTarget (
477495 "mrt_" + name + mrtIndex ,
478- { width : this . _voxelResolution , height : this . _voxelResolution , depth : this . _isVoxelGrid3D ? this . _voxelResolution : undefined } ,
496+ { width : this . _voxelResolution , height : this . _voxelResolution , depth : this . _voxelResolution } ,
479497 this . _maxDrawBuffers , // number of draw buffers
480498 this . _scene ,
481499 {
@@ -516,7 +534,7 @@ export class _IblShadowsVoxelRenderer {
516534 if ( this . _triPlanarVoxelization ) {
517535 this . _voxelGridXaxis ?. dispose ( ) ;
518536 this . _voxelGridYaxis ?. dispose ( ) ;
519- this . _voxelGridRT ?. dispose ( ) ;
537+ this . _combinedVoxelGridPT ?. dispose ( ) ;
520538 }
521539 this . _voxelGridZaxis ?. dispose ( ) ;
522540 for ( const mip of this . _mipArray ) {
@@ -533,7 +551,7 @@ export class _IblShadowsVoxelRenderer {
533551 private _createVoxelMaterials ( ) : void {
534552 const isWebGPU = this . _engine . isWebGPU ;
535553 this . _voxelMaterial = new ShaderMaterial ( "voxelization" , this . _scene , "iblVoxelGrid" , {
536- uniforms : [ "world" , "viewMatrix" , "invWorldScale" , "nearPlane" , "farPlane" , "stepSize" ] ,
554+ uniforms : [ "world" , "viewMatrix" , "invTransWorld" , " invWorldScale", "nearPlane" , "farPlane" , "stepSize" ] ,
537555 defines : [ "MAX_DRAW_BUFFERS " + this . _maxDrawBuffers ] ,
538556 shaderLanguage : isWebGPU ? ShaderLanguage . WGSL : ShaderLanguage . GLSL ,
539557 extraInitializationsAsync : async ( ) => {
@@ -594,6 +612,7 @@ export class _IblShadowsVoxelRenderer {
594612 this . _removeVoxelRTs ( this . _voxelMrtsXaxis ) ;
595613 this . _removeVoxelRTs ( this . _voxelMrtsYaxis ) ;
596614 this . _removeVoxelRTs ( this . _voxelMrtsZaxis ) ;
615+ this . _removeVoxelRTs ( [ this . _voxelGridRT ] ) ;
597616 }
598617
599618 private _removeVoxelRTs ( rts : RenderTargetTexture [ ] ) {
@@ -628,7 +647,10 @@ export class _IblShadowsVoxelRenderer {
628647 this . _includedMeshes = includedMeshes ;
629648 this . _voxelizationInProgress = true ;
630649
631- if ( this . _triPlanarVoxelization ) {
650+ if ( this . _engine . isWebGPU ) {
651+ this . _voxelGridRT . renderList = includedMeshes ;
652+ this . _addRTsForRender ( [ this . _voxelGridRT ] , includedMeshes , 0 ) ;
653+ } else if ( this . _triPlanarVoxelization ) {
632654 this . _addRTsForRender ( this . _voxelMrtsXaxis , includedMeshes , 0 ) ;
633655 this . _addRTsForRender ( this . _voxelMrtsYaxis , includedMeshes , 1 ) ;
634656 this . _addRTsForRender ( this . _voxelMrtsZaxis , includedMeshes , 2 ) ;
@@ -656,13 +678,25 @@ export class _IblShadowsVoxelRenderer {
656678 allReady &&= rttReady ;
657679 }
658680 if ( allReady ) {
681+ if ( this . _engine . isWebGPU ) {
682+ // Clear the voxel grid storage texture.
683+ // Need to clear each layer individually.
684+ // Would a compute shader be faster here to clear all layers in one go?
685+ if ( this . _voxelGrid && this . _voxelGrid . renderTarget ) {
686+ for ( let layer = 0 ; layer < this . _voxelResolution ; layer ++ ) {
687+ this . _engine . bindFramebuffer ( this . _voxelGrid . renderTarget , 0 , undefined , undefined , true , 0 , layer ) ;
688+ this . _engine . clear ( this . _voxelClearColor , true , false , false ) ;
689+ this . _engine . unBindFramebuffer ( this . _voxelGrid . renderTarget , true ) ;
690+ }
691+ }
692+ }
659693 for ( const rt of this . _renderTargets ) {
660694 rt . render ( ) ;
661695 }
662696 this . _stopVoxelization ( ) ;
663697
664- if ( this . _triPlanarVoxelization ) {
665- this . _voxelGridRT . render ( ) ;
698+ if ( this . _triPlanarVoxelization && ! this . _engine . isWebGPU ) {
699+ this . _combinedVoxelGridPT . render ( ) ;
666700 }
667701 this . _generateMipMaps ( ) ;
668702 // eslint-disable-next-line @typescript-eslint/no-floating-promises, github/no-then
@@ -710,6 +744,10 @@ export class _IblShadowsVoxelRenderer {
710744 voxelMaterial . setFloat ( "nearPlane" , nearPlane ) ;
711745 voxelMaterial . setFloat ( "farPlane" , farPlane ) ;
712746 voxelMaterial . setFloat ( "stepSize" , stepSize ) ;
747+ if ( this . _engine . isWebGPU ) {
748+ this . _voxelMaterial . useVertexPulling = true ;
749+ this . _voxelMaterial . setTexture ( "voxel_storage" , this . getVoxelGrid ( ) ) ;
750+ }
713751 } ) ;
714752
715753 // Set this material on every mesh in the scene (for this RT)
0 commit comments