Skip to content

Commit

Permalink
Separate material fade with fade tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
gkjohnson committed Dec 24, 2024
1 parent 94300a9 commit bc734d5
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 4 deletions.
4 changes: 2 additions & 2 deletions src/plugins/three/fade/FadeManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ export class FadeManager {

forEachObject( cb ) {

this._fadeState.forEach( ( info, scene ) => {
this._fadeState.forEach( ( info, object ) => {

cb( scene );
cb( object, info );

} );

Expand Down
169 changes: 169 additions & 0 deletions src/plugins/three/fade/FadeMaterialManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
export class FadeMaterialManager {

constructor() {

this._fadeParams = new WeakMap();
this.fading = 0;

}

// Set the fade parameters for the given scene
setFade( scene, fadeIn, fadeOut ) {

if ( ! scene ) {

return;

}

const fadeParams = this._fadeParams;
scene.traverse( child => {

const material = child.material;
if ( material ) {

const params = fadeParams.get( material );
params.fadeIn.value = fadeIn;
params.fadeOut.value = fadeOut;

const fadeInComplete = fadeIn === 0 || fadeIn === 1;
const fadeOutComplete = fadeOut === 0 || fadeOut === 1;
const value = Number( ! fadeInComplete || ! fadeOutComplete );
if ( material.defines.FEATURE_FADE !== value ) {

this.fading += value === 1 ? 1 : - 1;
material.defines.FEATURE_FADE = value;
material.needsUpdate = true;

}

}

} );

}

// initialize materials in the object
prepareScene( scene ) {

scene.traverse( child => {

if ( child.material ) {

this.prepareMaterial( child.material );

}

} );

}

// delete the object from the fade, reset the material data
deleteScene( scene ) {

if ( ! scene ) {

return;

}

const fadeParams = this._fadeParams;
scene.traverse( child => {

const material = child.material;
if ( material ) {

fadeParams.delete( material );
material.onBeforeCompile = () => {};
material.needsUpdate = true;

}

} );

}

// initialize the material
prepareMaterial( material ) {

const fadeParams = this._fadeParams;
if ( fadeParams.has( material ) ) {

return;

}

const params = {
fadeIn: { value: 0 },
fadeOut: { value: 0 },
};

material.defines = {
FEATURE_FADE: 0,
};

material.onBeforeCompile = shader => {

shader.uniforms = {
...shader.uniforms,
...params,
};

shader.fragmentShader = shader.fragmentShader
.replace( /void main\(/, value => /* glsl */`
#if FEATURE_FADE
// adapted from https://www.shadertoy.com/view/Mlt3z8
float bayerDither2x2( vec2 v ) {
return mod( 3.0 * v.y + 2.0 * v.x, 4.0 );
}
float bayerDither4x4( vec2 v ) {
vec2 P1 = mod( v, 2.0 );
vec2 P2 = floor( 0.5 * mod( v, 4.0 ) );
return 4.0 * bayerDither2x2( P1 ) + bayerDither2x2( P2 );
}
uniform float fadeIn;
uniform float fadeOut;
#endif
${ value }
` )
.replace( /#include <dithering_fragment>/, value => /* glsl */`
${ value }
#if FEATURE_FADE
float bayerValue = bayerDither4x4( floor( mod( gl_FragCoord.xy, 4.0 ) ) );
float bayerBins = 16.0;
float dither = ( 0.5 + bayerValue ) / bayerBins;
if ( dither >= fadeIn ) {
discard;
}
if ( dither < fadeOut ) {
discard;
}
#endif
` );


};

fadeParams.set( material, params );

}

}
14 changes: 12 additions & 2 deletions src/plugins/three/fade/TilesFadePlugin.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Matrix4, Vector3, Quaternion } from 'three';
import { FadeManager } from './FadeManager.js';
import { FadeMaterialManager } from './FadeMaterialManager.js';

const HAS_POPPED_IN = Symbol( 'HAS_POPPED_IN' );
const _fromPos = new Vector3();
Expand Down Expand Up @@ -59,16 +60,22 @@ function onTileVisibilityChange( tile, visible ) {

function onLoadModel( scene, tile ) {

this._fadeMaterialManager.prepareScene( scene );

}

function onDisposeModel( scene, tile ) {

this._fadeManager.deleteObject( tile );
this._fadeMaterialManager.deleteScene( scene );

}

function onFadeComplete( tile, visible ) {

// mark the fade as finished
this._fadeMaterialManager.setFade( tile.cached.scene, 0, 0 );

if ( ! visible ) {

// now that the tile is hidden we can run the built-in setTileVisible function for the tile
Expand Down Expand Up @@ -111,6 +118,7 @@ function onUpdateBefore() {
function onUpdateAfter() {

const fadeManager = this._fadeManager;
const fadeMaterialManager = this._fadeMaterialManager;
const displayActiveTiles = this._displayActiveTiles;
const fadingBefore = this._fadingBefore;
const tiles = this.tiles;
Expand Down Expand Up @@ -210,10 +218,11 @@ function onUpdateAfter() {

} );

// prevent faded tiles from being unloaded
fadeManager.forEachObject( tile => {
fadeManager.forEachObject( ( tile, { fadeIn, fadeOut } ) => {

// prevent faded tiles from being unloaded
lruCache.markUsed( tile );
fadeMaterialManager.setFade( tile.cached.scene, fadeIn, fadeOut );

} );

Expand Down Expand Up @@ -255,6 +264,7 @@ export class TilesFadePlugin {

this.tiles = null;
this._fadeManager = new FadeManager();
this._fadeMaterialManager = new FadeMaterialManager();
this._prevCameraTransforms = null;
this._tileMap = null; // TODO
this._fadingOutCount = 0;
Expand Down

0 comments on commit bc734d5

Please sign in to comment.