@@ -30,6 +30,8 @@ declare module "../scene" {
30
30
export interface Scene {
31
31
/** @internal */
32
32
_meshUVSpaceRendererShader : Nullable < ShaderMaterial > ;
33
+ /** @internal */
34
+ _meshUVSpaceRendererMaskShader : Nullable < ShaderMaterial > ;
33
35
}
34
36
}
35
37
@@ -74,27 +76,10 @@ export class MeshUVSpaceRenderer {
74
76
private _scene : Scene ;
75
77
private _options : Required < IMeshUVSpaceRendererOptions > ;
76
78
private _textureCreatedInternally = false ;
77
- /**
78
- * Mask Texture for the UV Edge Blending
79
- */
80
- _maskTexture : any ;
81
- /**
82
- * Final Texture for the UV Edge Blending
83
- */
84
- _finalTexture : any ;
85
-
86
- /**
87
- * The decal texture
88
- */
89
- decalTexture : Texture ;
90
- /**
91
- * The final material for the UV Edge Blending
92
- */
93
- public finalMaterial : ShaderMaterial ;
94
- /**
95
- * The final post process for the UV Edge Blending
96
- */
97
- _finalPostProcess : any ;
79
+ private _maskTexture : Texture ;
80
+ private _decalTexture : Texture ;
81
+ private _finalPostProcess : PostProcess ;
82
+ private _userCreatedTextureSetup : boolean = false ;
98
83
99
84
private static _GetShader ( scene : Scene ) : ShaderMaterial {
100
85
if ( ! scene . _meshUVSpaceRendererShader ) {
@@ -126,6 +111,33 @@ export class MeshUVSpaceRenderer {
126
111
return scene . _meshUVSpaceRendererShader ;
127
112
}
128
113
114
+ private static _GetMaskShader ( scene : Scene ) : ShaderMaterial {
115
+ if ( ! scene . _meshUVSpaceRendererMaskShader ) {
116
+ const shader = new ShaderMaterial (
117
+ "meshUVSpaceRendererMaskShader" ,
118
+ scene ,
119
+ {
120
+ vertex : "meshUVSpaceRendererMasker" ,
121
+ fragment : "meshUVSpaceRendererMasker" ,
122
+ } ,
123
+ {
124
+ attributes : [ "position" , "uv" ] ,
125
+ uniforms : [ "worldViewProjection" ] ,
126
+ }
127
+ ) ;
128
+ shader . backFaceCulling = false ;
129
+ shader . alphaMode = Constants . ALPHA_COMBINE ;
130
+
131
+ scene . onDisposeObservable . add ( ( ) => {
132
+ scene . _meshUVSpaceRendererShader ?. dispose ( ) ;
133
+ scene . _meshUVSpaceRendererShader = null ;
134
+ } ) ;
135
+
136
+ scene . _meshUVSpaceRendererMaskShader = shader ;
137
+ }
138
+ return scene . _meshUVSpaceRendererMaskShader ;
139
+ }
140
+
129
141
private static _IsRenderTargetTexture ( texture : ThinTexture | RenderTargetTexture ) : texture is RenderTargetTexture {
130
142
return ( texture as RenderTargetTexture ) . renderList !== undefined ;
131
143
}
@@ -167,11 +179,11 @@ export class MeshUVSpaceRenderer {
167
179
* @returns true if the texture is ready to be used
168
180
*/
169
181
public isReady ( ) : boolean {
170
- if ( ! this . decalTexture ) {
171
- this . _createDiffuseRTT ( ) ;
182
+ if ( ! this . texture ) {
183
+ this . _createDecalDiffuseRTT ( ) ;
172
184
}
173
185
174
- return MeshUVSpaceRenderer . _IsRenderTargetTexture ( this . decalTexture ) ? this . decalTexture . isReadyForRendering ( ) : this . decalTexture . isReady ( ) ;
186
+ return MeshUVSpaceRenderer . _IsRenderTargetTexture ( this . texture ) ? this . texture . isReadyForRendering ( ) : this . texture . isReady ( ) ;
175
187
}
176
188
177
189
/**
@@ -182,10 +194,16 @@ export class MeshUVSpaceRenderer {
182
194
* @param size The size of the projection
183
195
* @param angle The rotation angle around the direction of the projection
184
196
*/
185
- public async renderTexture ( texture : BaseTexture , position : Vector3 , normal : Vector3 , size : Vector3 , angle = 0 ) : Promise < void > {
197
+ public renderTexture ( texture : BaseTexture , position : Vector3 , normal : Vector3 , size : Vector3 , angle = 0 ) : void {
186
198
// Create the diffuse render target texture if it doesn't exist
187
- if ( ! this . decalTexture ) {
188
- this . _createDiffuseRTT ( ) ;
199
+ if ( ! this . texture && ! this . _options . uvEdgeBlending && ! this . _decalTexture ) {
200
+ this . _updateRTT ( ) ;
201
+ } else if ( this . texture && ! this . _userCreatedTextureSetup && ! this . _options . uvEdgeBlending && ! this . _decalTexture ) {
202
+ this . _updateRTT ( ) ;
203
+ } else if ( this . texture && ! this . _userCreatedTextureSetup && this . _options . uvEdgeBlending && ! this . _decalTexture ) {
204
+ this . _createDecalDiffuseRTT ( ) ;
205
+ } else if ( ! this . texture && this . _options . uvEdgeBlending && ! this . _decalTexture ) {
206
+ this . _createDecalDiffuseRTT ( ) ;
189
207
}
190
208
191
209
// // Prepare the shader with the decal texture, mask texture, and necessary uniforms
@@ -196,166 +214,134 @@ export class MeshUVSpaceRenderer {
196
214
const projectionMatrix = this . _createProjectionMatrix ( position , normal , size , angle ) ;
197
215
shader . setMatrix ( "projMatrix" , projectionMatrix ) ;
198
216
199
- if ( MeshUVSpaceRenderer . _IsRenderTargetTexture ( this . decalTexture ) ) {
200
- this . decalTexture . render ( ) ;
201
- if ( this . _options . uvEdgeBlending ) {
202
- await this . _createMaskTexture ( ) ;
203
- this . _createFinalTexture ( ) ;
204
- } else {
205
- this . texture = this . decalTexture ;
217
+
218
+ if ( ! this . _options . uvEdgeBlending ) {
219
+ if ( this . texture instanceof RenderTargetTexture ) {
220
+ this . texture . render ( ) ;
221
+ }
222
+ } else {
223
+ if ( MeshUVSpaceRenderer . _IsRenderTargetTexture ( this . _decalTexture ) ) {
224
+ if ( this . _options . uvEdgeBlending ) {
225
+ this . _decalTexture . render ( ) ;
226
+ this . _createMaskTexture ( ) ;
227
+ this . _createFinalTexture ( ) ;
228
+ }
206
229
}
207
230
}
208
231
}
232
+ /**
233
+ * Creates a texture RTT if one doesn't exist,
234
+ */
235
+ _updateRTT ( ) {
236
+ if ( ! this . texture ) {
237
+ this . texture = this . _createRenderTargetTexture ( this . _options . width , this . _options . height ) ;
238
+ } else {
239
+ this . _userCreatedTextureSetup = true ;
240
+ }
241
+ if ( this . texture instanceof RenderTargetTexture ) {
242
+ this . texture . renderList = [ this . _mesh ] ;
243
+ this . texture . setMaterialForRendering ( this . _mesh , MeshUVSpaceRenderer . _GetShader ( this . _scene ) ) ;
244
+ this . texture . onClearObservable . addOnce ( ( ) => {
245
+ this . _scene . getEngine ( ) . clear ( this . clearColor , true , true , true ) ;
246
+ if ( this . texture instanceof RenderTargetTexture ) {
247
+ this . texture . onClearObservable . add ( ( ) => { } ) ;
248
+ }
249
+ } ) ;
250
+ }
251
+ }
209
252
210
253
private _createMaskTexture ( ) : void {
211
254
if ( this . _maskTexture ) {
212
- Promise . resolve ( ) ;
213
255
return ;
214
256
}
215
- try {
216
- // Create a new render target texture for the mask
217
- this . _maskTexture = new RenderTargetTexture (
218
- "maskTexture" ,
219
- { width : this . _options . width , height : this . _options . height } ,
220
- this . _scene ,
221
- false , // No mipmaps for the mask texture
222
- true ,
223
- Constants . TEXTURETYPE_UNSIGNED_BYTE ,
224
- false ,
225
- undefined ,
226
- undefined ,
227
- undefined ,
228
- undefined ,
229
- Constants . TEXTUREFORMAT_R
230
- ) ;
231
-
232
- // Set up the mask material
233
- const maskMaterial = new ShaderMaterial (
234
- "meshUVSpaceRendererMaskerShader" ,
235
- this . _scene ,
236
- {
237
- vertex : "meshUVSpaceRendererMasker" ,
238
- fragment : "meshUVSpaceRendererMasker" ,
239
- } ,
240
- {
241
- attributes : [ "position" , "uv" ] ,
242
- uniforms : [ "worldViewProjection" ] ,
243
- }
244
- ) ;
245
-
246
- let texture = null ;
247
- if ( this . _mesh . material instanceof PBRMaterial ) {
248
- texture = ( this . _mesh . material as PBRMaterial ) . albedoTexture ;
249
- } else if ( this . _mesh . material instanceof StandardMaterial ) {
250
- texture = ( this . _mesh . material as StandardMaterial ) . diffuseTexture ;
251
- }
257
+ // Create a new render target texture for the mask
258
+ this . _maskTexture = new RenderTargetTexture (
259
+ "maskTexture" ,
260
+ { width : this . _options . width , height : this . _options . height } ,
261
+ this . _scene ,
262
+ false , // No mipmaps for the mask texture
263
+ true ,
264
+ Constants . TEXTURETYPE_UNSIGNED_BYTE ,
265
+ false ,
266
+ undefined ,
267
+ undefined ,
268
+ undefined ,
269
+ undefined ,
270
+ Constants . TEXTUREFORMAT_R
271
+ ) ;
272
+ const maskShader = MeshUVSpaceRenderer . _GetMaskShader ( this . _scene ) ;
273
+ let texture = null ;
274
+ if ( this . _mesh . material instanceof PBRMaterial ) {
275
+ texture = ( this . _mesh . material as PBRMaterial ) . albedoTexture ;
276
+ } else if ( this . _mesh . material instanceof StandardMaterial ) {
277
+ texture = ( this . _mesh . material as StandardMaterial ) . diffuseTexture ;
278
+ }
252
279
253
- if ( texture ) {
254
- maskMaterial . setTexture ( "textureSampler" , texture ) ;
255
- } else {
256
- console . error ( "Material does not have a valid texture property." ) ;
257
- }
280
+ if ( texture ) {
281
+ maskShader . setTexture ( "textureSampler" , texture ) ;
282
+ } else {
283
+ console . error ( "Material does not have a valid texture property." ) ;
284
+ }
258
285
259
- maskMaterial . backFaceCulling = false ;
286
+ maskShader . backFaceCulling = false ;
260
287
261
- this . _mesh . material = this . _mesh . material as PBRMaterial ;
262
- maskMaterial . backFaceCulling = false ;
288
+ this . _mesh . material = this . _mesh . material as PBRMaterial ;
289
+ maskShader . backFaceCulling = false ;
263
290
291
+ if ( MeshUVSpaceRenderer . _IsRenderTargetTexture ( this . _maskTexture ) ) {
264
292
// Render the mesh with the mask material to the mask texture
265
- this . _maskTexture . renderList . push ( this . _mesh ) ;
266
- this . _maskTexture . setMaterialForRendering ( this . _mesh , maskMaterial ) ;
267
-
293
+ this . _maskTexture . renderList ?. push ( this . _mesh ) ;
294
+ this . _maskTexture . setMaterialForRendering ( this . _mesh , maskShader ) ;
268
295
// Ensure the mask texture is updated
269
296
this . _maskTexture . refreshRate = RenderTargetTexture . REFRESHRATE_RENDER_ONCE ;
270
297
this . _scene . customRenderTargets . push ( this . _maskTexture ) ;
271
- Promise . resolve ( ) ;
272
- } catch ( error ) {
273
- console . error ( "Error creating mask texture:" , error ) ;
274
298
}
275
299
}
276
300
277
301
private _createFinalTexture ( ) : void {
278
- if ( ! this . texture ) {
279
- this . texture = new RenderTargetTexture (
280
- "finalTexture" ,
281
- { width : this . _options . width , height : this . _options . height } ,
282
- this . _scene ,
302
+ // Create the post-process only if it hasn't been created already
303
+ if ( ! this . _finalPostProcess ) {
304
+ this . _finalPostProcess = new PostProcess (
305
+ "finalTexturePostProcess" ,
306
+ "meshUVSpaceRendererFinaliser" ,
307
+ [ "textureSize" ] ,
308
+ [ "textureSampler" , "maskTextureSampler" ] ,
309
+ 1.0 ,
310
+ null ,
311
+ Texture . NEAREST_SAMPLINGMODE ,
312
+ this . _scene . getEngine ( ) ,
283
313
false ,
284
- true ,
314
+ null ,
285
315
this . _options . textureType
286
316
) ;
287
- }
288
-
289
- try {
290
- // Set up the shader material
291
- this . finalMaterial = new ShaderMaterial (
292
- "meshUVSpaceRendererFinaliserShader" ,
293
- this . _scene ,
294
- {
295
- vertex : "meshUVSpaceRendererFinaliser" ,
296
- fragment : "meshUVSpaceRendererFinaliser" ,
297
- } ,
298
- {
299
- attributes : [ "position" , "uv" ] ,
300
- uniforms : [ "worldViewProjection" , "textureSize" ] ,
301
- samplers : [ "textureSampler" , "maskTextureSampler" ] ,
302
- }
303
- ) ;
304
-
305
- this . finalMaterial . setTexture ( "textureSampler" , this . decalTexture ) ;
306
- this . finalMaterial . setTexture ( "maskTextureSampler" , this . _maskTexture ) ;
307
- this . finalMaterial . setVector2 ( "textureSize" , new Vector2 ( this . _options . width , this . _options . height ) ) ;
308
- this . finalMaterial . backFaceCulling = false ;
309
-
310
- // Create the post-process only if it hasn't been created already
311
- if ( ! this . _finalPostProcess ) {
312
- this . _finalPostProcess = new PostProcess (
313
- "finalTexturePostProcess" ,
314
- "meshUVSpaceRendererFinaliser" ,
315
- [ "textureSize" ] ,
316
- [ "textureSampler" , "maskTextureSampler" ] ,
317
- 1.0 ,
318
- null ,
319
- Texture . NEAREST_SAMPLINGMODE ,
320
- this . _scene . getEngine ( ) ,
321
- false ,
322
- null ,
323
- this . _options . textureType
324
- ) ;
325
-
326
- this . _finalPostProcess . onApply = ( effect : { setTexture : ( arg0 : string , arg1 : Texture ) => void ; setVector2 : ( arg0 : string , arg1 : Vector2 ) => void } ) => {
327
- effect . setTexture ( "textureSampler" , this . decalTexture ) ;
328
- effect . setTexture ( "maskTextureSampler" , this . _maskTexture ) ;
329
- effect . setVector2 ( "textureSize" , new Vector2 ( this . _options . width , this . _options . height ) ) ;
330
- } ;
331
- if ( MeshUVSpaceRenderer . _IsRenderTargetTexture ( this . texture ) ) {
332
- this . texture . addPostProcess ( this . _finalPostProcess ) ;
333
- }
334
- }
335
317
318
+ this . _finalPostProcess . onApply = ( effect : { setTexture : ( arg0 : string , arg1 : Texture ) => void ; setVector2 : ( arg0 : string , arg1 : Vector2 ) => void } ) => {
319
+ effect . setTexture ( "textureSampler" , this . _decalTexture ) ;
320
+ effect . setTexture ( "maskTextureSampler" , this . _maskTexture ) ;
321
+ effect . setVector2 ( "textureSize" , new Vector2 ( this . _options . width , this . _options . height ) ) ;
322
+ } ;
336
323
if ( MeshUVSpaceRenderer . _IsRenderTargetTexture ( this . texture ) ) {
337
- this . texture . render ( ) ;
324
+ this . texture . addPostProcess ( this . _finalPostProcess ) ;
338
325
}
339
- } catch ( error ) {
340
- console . error ( "Error creating final texture:" , error ) ;
341
326
}
342
- }
343
327
328
+ if ( MeshUVSpaceRenderer . _IsRenderTargetTexture ( this . texture ) ) {
329
+ this . texture . render ( ) ;
330
+ }
331
+ }
344
332
/**
345
333
* Clears the texture map
346
334
*/
347
335
public clear ( ) : void {
348
336
if ( MeshUVSpaceRenderer . _IsRenderTargetTexture ( this . texture ) && this . texture . renderTarget ) {
349
337
const engine = this . _scene . getEngine ( ) ;
350
-
351
338
engine . bindFramebuffer ( this . texture . renderTarget ) ;
352
339
engine . clear ( this . clearColor , true , true , true ) ;
353
340
engine . unBindFramebuffer ( this . texture . renderTarget ) ;
354
341
}
355
342
}
356
-
357
343
/**
358
- * Disposes of the ressources
344
+ * Disposes of the resources
359
345
*/
360
346
public dispose ( ) {
361
347
if ( this . _textureCreatedInternally ) {
@@ -364,18 +350,19 @@ export class MeshUVSpaceRenderer {
364
350
}
365
351
}
366
352
367
- private _createDiffuseRTT ( ) : void {
368
- this . _textureCreatedInternally = true ;
369
-
353
+ private _createDecalDiffuseRTT ( ) : void {
370
354
const texture = this . _createRenderTargetTexture ( this . _options . width , this . _options . height ) ;
371
355
372
356
texture . setMaterialForRendering ( this . _mesh , MeshUVSpaceRenderer . _GetShader ( this . _scene ) ) ;
373
357
374
- this . decalTexture = texture ;
375
-
376
- // Additional check after assignment
377
- if ( ! this . decalTexture . isReady ( ) ) {
378
- console . error ( "decalTexture is not ready after creation in _createDiffuseRTT." ) ;
358
+ this . _decalTexture = texture ;
359
+ if ( ! this . texture ) {
360
+ this . texture = new RenderTargetTexture (
361
+ this . _mesh . name + "_finalUVSpaceTexture" ,
362
+ { width : this . _options . width , height : this . _options . height } ,
363
+ this . _scene ,
364
+ ) ;
365
+ this . _textureCreatedInternally = true ;
379
366
}
380
367
}
381
368
0 commit comments