@@ -2,10 +2,11 @@ import * as THREE from 'three'
2
2
import { shaderMaterial } from './shaderMaterial'
3
3
import { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass'
4
4
import { useFBO } from './useFBO'
5
+ import { PlaneGeometry } from 'three'
5
6
6
7
const isVector3 = ( object : any ) : object is THREE . Vector3 => object ?. isVector3
7
8
8
- type CausticsProjectionMaterialType = THREE . MeshNormalMaterial & {
9
+ export type CausticsProjectionMaterialType = THREE . MeshNormalMaterial & {
9
10
viewMatrix : { value ?: THREE . Matrix4 }
10
11
color ?: THREE . Color
11
12
causticsTexture ?: THREE . Texture
@@ -14,7 +15,7 @@ type CausticsProjectionMaterialType = THREE.MeshNormalMaterial & {
14
15
lightViewMatrix ?: THREE . Matrix4
15
16
}
16
17
17
- type CausticsProps = {
18
+ export type CausticsProps = {
18
19
/** How many frames it will render, set it to Infinity for runtime, default: 1 */
19
20
frames ?: number
20
21
/** Will display caustics only and skip the models, default: false */
@@ -60,15 +61,15 @@ function createNormalMaterial(side: THREE.Side = THREE.FrontSide) {
60
61
} )
61
62
}
62
63
63
- type CausticsProjectionShaderType = {
64
+ export type CausticsProjectionShaderType = {
64
65
causticsTexture ?: THREE . Texture | null
65
66
causticsTextureB ?: THREE . Texture | null
66
67
color ?: THREE . Color
67
68
lightProjMatrix ?: THREE . Matrix4
68
69
lightViewMatrix ?: THREE . Matrix4
69
70
}
70
71
71
- const CausticsProjectionMaterial = shaderMaterial < CausticsProjectionShaderType > (
72
+ export const CausticsProjectionMaterial = shaderMaterial < CausticsProjectionShaderType > (
72
73
{
73
74
causticsTexture : null ,
74
75
causticsTextureB : null ,
@@ -101,7 +102,7 @@ const CausticsProjectionMaterial = shaderMaterial<CausticsProjectionShaderType>(
101
102
}`
102
103
)
103
104
104
- type CausticsMaterialType = {
105
+ export type CausticsMaterialType = {
105
106
cameraMatrixWorld : THREE . Matrix4
106
107
cameraProjectionMatrixInv : THREE . Matrix4
107
108
normalTexture : THREE . Texture | null
@@ -120,7 +121,7 @@ type CausticsMaterialType = {
120
121
intensity : number
121
122
}
122
123
123
- const CausticsMaterial = shaderMaterial < CausticsMaterialType > (
124
+ export const CausticsMaterial = shaderMaterial < CausticsMaterialType > (
124
125
{
125
126
cameraMatrixWorld : new THREE . Matrix4 ( ) ,
126
127
cameraProjectionMatrixInv : new THREE . Matrix4 ( ) ,
@@ -277,86 +278,27 @@ export type CausticsType = {
277
278
causticsTargetB : THREE . WebGLRenderTarget
278
279
}
279
280
280
- export const Caustics = (
281
- renderer : THREE . WebGLRenderer ,
282
- {
283
- frames = 1 ,
284
- causticsOnly = false ,
285
- ior = 1.1 ,
286
- backside = false ,
287
- backsideIOR = 1.1 ,
288
- worldRadius = 0.3125 ,
289
- color = new THREE . Color ( 'white' ) ,
290
- intensity = 0.05 ,
291
- resolution = 2024 ,
292
- lightSource = new THREE . Vector3 ( 1 , 1 , 1 ) ,
293
- near = 0.1 ,
294
- far = 0 , // auto calculates if zero
295
- } : CausticsProps = { }
296
- ) : CausticsType => {
297
- const params = {
298
- frames,
299
- ior,
300
- color,
301
- causticsOnly,
302
- backside,
303
- backsideIOR,
304
- worldRadius,
305
- intensity,
306
- resolution,
307
- lightSource,
308
- near,
309
- far,
281
+ export function createCausticsUpdate (
282
+ updateParameters : ( ) => {
283
+ params : Omit < CausticsProps , 'color' >
284
+ scene : THREE . Scene
285
+ group : THREE . Group
286
+ camera : THREE . OrthographicCamera
287
+ plane : THREE . Mesh < PlaneGeometry , InstanceType < typeof CausticsProjectionMaterial > >
288
+ normalTarget : THREE . WebGLRenderTarget
289
+ normalTargetB : THREE . WebGLRenderTarget
290
+ causticsTarget : THREE . WebGLRenderTarget
291
+ causticsTargetB : THREE . WebGLRenderTarget
292
+ helper ?: THREE . CameraHelper | null
310
293
}
311
- const group = new THREE . Group ( )
312
- group . name = 'caustics_group'
313
- const ref = group
314
-
315
- const camera = new THREE . OrthographicCamera ( )
316
-
317
- const scene = new THREE . Scene ( )
318
- scene . name = 'caustics_scene'
319
-
320
- const gl = renderer
321
-
322
- const helper = new THREE . CameraHelper ( camera )
323
- helper . name = 'caustics_helper'
324
-
325
- // Buffers for front and back faces
326
- const res = params . resolution
327
- const normalTarget = useFBO ( res , res , NORMALPROPS )
328
- const normalTargetB = useFBO ( res , res , NORMALPROPS )
329
- const causticsTarget = useFBO ( res , res , CAUSTICPROPS )
330
- const causticsTargetB = useFBO ( res , res , CAUSTICPROPS )
294
+ ) {
331
295
// Normal materials for front and back faces
332
296
const normalMat = createNormalMaterial ( )
333
297
const normalMatB = createNormalMaterial ( THREE . BackSide )
334
298
// The quad that catches the caustics
335
299
const causticsMaterial = new CausticsMaterial ( )
336
300
const causticsQuad = new FullScreenQuad ( causticsMaterial )
337
301
338
- const plane = new THREE . Mesh (
339
- new THREE . PlaneGeometry ( 1 , 1 ) ,
340
- new CausticsProjectionMaterial ( {
341
- transparent : true ,
342
- color : params . color ,
343
- causticsTexture : causticsTarget . texture ,
344
- causticsTextureB : causticsTargetB . texture ,
345
- blending : THREE . CustomBlending ,
346
- blendSrc : THREE . OneFactor ,
347
- blendDst : THREE . SrcAlphaFactor ,
348
- depthWrite : false ,
349
- } )
350
- )
351
-
352
- plane . name = 'caustics_plane'
353
- plane . rotation . x = - Math . PI / 2
354
- plane . renderOrder = 2
355
- group . add ( scene , plane )
356
- // scene.add(activeModel) //add glb to caustics scene
357
- // mainObjects.add(group, helper) // add entire group to scene
358
- group . updateWorldMatrix ( false , true )
359
-
360
302
let count = 0
361
303
362
304
const v = new THREE . Vector3 ( )
@@ -383,10 +325,26 @@ export const Caustics = (
383
325
lightDirs . push ( new THREE . Vector3 ( ) )
384
326
}
385
327
386
- const update = ( ) => {
387
- if ( params . frames === Infinity || count ++ < params . frames ) {
388
- if ( isVector3 ( lightSource ) ) lightDir . copy ( lightSource ) . normalize ( )
389
- else lightDir . copy ( ref . worldToLocal ( lightSource . getWorldPosition ( v ) ) . normalize ( ) )
328
+ return function update ( gl : THREE . WebGLRenderer ) {
329
+ const {
330
+ params,
331
+ helper,
332
+ camera,
333
+ plane,
334
+ normalTarget,
335
+ normalTargetB,
336
+ causticsTarget,
337
+ causticsTargetB,
338
+ scene,
339
+ group,
340
+ } = updateParameters ( )
341
+
342
+ if ( params . frames === Infinity || ( params . frames && count ++ < params . frames ) ) {
343
+ if ( isVector3 ( params . lightSource ) ) {
344
+ lightDir . copy ( params . lightSource ) . normalize ( )
345
+ } else if ( params . lightSource ) {
346
+ lightDir . copy ( group . worldToLocal ( params . lightSource . getWorldPosition ( v ) ) . normalize ( ) )
347
+ }
390
348
391
349
lightDirInv . copy ( lightDir ) . multiplyScalar ( - 1 )
392
350
@@ -422,7 +380,7 @@ export const Caustics = (
422
380
camera . right = radius
423
381
camera . top = radius
424
382
camera . bottom = - radius
425
- camera . near = params . near
383
+ if ( params . near ) camera . near = params . near
426
384
if ( params . far ) {
427
385
camera . far = params . far
428
386
} else {
@@ -449,7 +407,7 @@ export const Caustics = (
449
407
plane . scale . setScalar ( maxSize )
450
408
plane . position . copy ( centerPos )
451
409
452
- if ( helper . parent ) helper . update ( )
410
+ if ( helper ? .parent ) helper . update ( )
453
411
454
412
// Inject uniforms
455
413
normalMatB . viewMatrix . value = normalMat . viewMatrix . value = camera . matrixWorldInverse
@@ -467,10 +425,11 @@ export const Caustics = (
467
425
468
426
causticsMaterial . near = camera . near
469
427
causticsMaterial . far = camera . far
470
- causticsMaterial . resolution = params . resolution
428
+ if ( params . resolution ) causticsMaterial . resolution = params . resolution
471
429
causticsMaterial . size = radius
472
- causticsMaterial . intensity = params . intensity
473
- causticsMaterial . worldRadius = params . worldRadius
430
+
431
+ if ( params . intensity ) causticsMaterial . intensity = params . intensity
432
+ if ( params . worldRadius ) causticsMaterial . worldRadius = params . worldRadius
474
433
475
434
// Switch the scene on
476
435
scene . visible = true
@@ -492,7 +451,7 @@ export const Caustics = (
492
451
// Remove the override material
493
452
scene . overrideMaterial = null
494
453
// Render front face caustics
495
- causticsMaterial . ior = params . ior
454
+ if ( params . ior ) causticsMaterial . ior = params . ior
496
455
plane . material . lightProjMatrix = camera . projectionMatrix
497
456
plane . material . lightViewMatrix = camera . matrixWorldInverse
498
457
causticsMaterial . normalTexture = normalTarget . texture
@@ -502,7 +461,7 @@ export const Caustics = (
502
461
causticsQuad . render ( gl )
503
462
504
463
// Render back face caustics, if enabled
505
- causticsMaterial . ior = params . backsideIOR
464
+ if ( params . backsideIOR ) causticsMaterial . ior = params . backsideIOR
506
465
causticsMaterial . normalTexture = normalTargetB . texture
507
466
causticsMaterial . depthTexture = normalTargetB . depthTexture
508
467
gl . setRenderTarget ( causticsTargetB )
@@ -516,13 +475,100 @@ export const Caustics = (
516
475
if ( params . causticsOnly ) scene . visible = false
517
476
}
518
477
}
478
+ }
479
+
480
+ export const Caustics = (
481
+ renderer : THREE . WebGLRenderer ,
482
+ {
483
+ frames = 1 ,
484
+ causticsOnly = false ,
485
+ ior = 1.1 ,
486
+ backside = false ,
487
+ backsideIOR = 1.1 ,
488
+ worldRadius = 0.3125 ,
489
+ color = new THREE . Color ( 'white' ) ,
490
+ intensity = 0.05 ,
491
+ resolution = 2024 ,
492
+ lightSource = new THREE . Vector3 ( 1 , 1 , 1 ) ,
493
+ near = 0.1 ,
494
+ far = 0 , // auto calculates if zero
495
+ } : CausticsProps = { }
496
+ ) : CausticsType => {
497
+ const params = {
498
+ frames,
499
+ ior,
500
+ color,
501
+ causticsOnly,
502
+ backside,
503
+ backsideIOR,
504
+ worldRadius,
505
+ intensity,
506
+ resolution,
507
+ lightSource,
508
+ near,
509
+ far,
510
+ }
511
+ const group = new THREE . Group ( )
512
+ group . name = 'caustics_group'
513
+
514
+ const camera = new THREE . OrthographicCamera ( )
515
+
516
+ const scene = new THREE . Scene ( )
517
+ scene . name = 'caustics_scene'
518
+
519
+ const gl = renderer
520
+
521
+ const helper = new THREE . CameraHelper ( camera )
522
+ helper . name = 'caustics_helper'
523
+
524
+ // Buffers for front and back faces
525
+ const res = params . resolution
526
+ const normalTarget = useFBO ( res , res , NORMALPROPS )
527
+ const normalTargetB = useFBO ( res , res , NORMALPROPS )
528
+ const causticsTarget = useFBO ( res , res , CAUSTICPROPS )
529
+ const causticsTargetB = useFBO ( res , res , CAUSTICPROPS )
530
+
531
+ const plane = new THREE . Mesh (
532
+ new THREE . PlaneGeometry ( 1 , 1 ) ,
533
+ new CausticsProjectionMaterial ( {
534
+ transparent : true ,
535
+ color : params . color ,
536
+ causticsTexture : causticsTarget . texture ,
537
+ causticsTextureB : causticsTargetB . texture ,
538
+ blending : THREE . CustomBlending ,
539
+ blendSrc : THREE . OneFactor ,
540
+ blendDst : THREE . SrcAlphaFactor ,
541
+ depthWrite : false ,
542
+ } )
543
+ )
544
+
545
+ plane . name = 'caustics_plane'
546
+ plane . rotation . x = - Math . PI / 2
547
+ plane . renderOrder = 2
548
+ group . add ( scene , plane )
549
+ // scene.add(activeModel) //add glb to caustics scene
550
+ // mainObjects.add(group, helper) // add entire group to scene
551
+ group . updateWorldMatrix ( false , true )
552
+
553
+ const update = createCausticsUpdate ( ( ) => ( {
554
+ params,
555
+ scene,
556
+ group,
557
+ camera,
558
+ plane,
559
+ normalTarget,
560
+ normalTargetB,
561
+ causticsTarget,
562
+ causticsTargetB,
563
+ helper,
564
+ } ) )
519
565
520
566
return {
521
567
scene,
522
568
group,
523
569
helper,
524
570
params,
525
- update,
571
+ update : update . bind ( { } , gl ) ,
526
572
527
573
normalTarget,
528
574
normalTargetB,
0 commit comments