You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
3.7 KiB

import {
HalfFloatType,
ShaderMaterial,
WebGLRenderTarget
} from 'three';
import { FullScreenQuad, Pass } from './Pass.js';
class RenderTransitionPass extends Pass {
constructor( sceneA, cameraA, sceneB, cameraB ) {
super();
this.material = this.createMaterial();
this.fsQuad = new FullScreenQuad( this.material );
this.sceneA = sceneA;
this.cameraA = cameraA;
this.sceneB = sceneB;
this.cameraB = cameraB;
this.renderTargetA = new WebGLRenderTarget();
this.renderTargetA.texture.type = HalfFloatType;
this.renderTargetB = new WebGLRenderTarget();
this.renderTargetB.texture.type = HalfFloatType;
}
setTransition( value ) {
this.material.uniforms.mixRatio.value = value;
}
useTexture( value ) {
this.material.uniforms.useTexture.value = value ? 1 : 0;
}
setTexture( value ) {
this.material.uniforms.tMixTexture.value = value;
}
setTextureThreshold( value ) {
this.material.uniforms.threshold.value = value;
}
setSize( width, height ) {
this.renderTargetA.setSize( width, height );
this.renderTargetB.setSize( width, height );
}
render( renderer, writeBuffer ) {
const uniforms = this.fsQuad.material.uniforms;
const transition = uniforms.mixRatio.value;
// Prevent render both scenes when it's not necessary
if ( transition === 0 ) {
renderer.setRenderTarget( writeBuffer );
if ( this.clear ) renderer.clear();
renderer.render( this.sceneB, this.cameraB );
} else if ( transition === 1 ) {
renderer.setRenderTarget( writeBuffer );
if ( this.clear ) renderer.clear();
renderer.render( this.sceneA, this.cameraA );
} else {
// When 0 < transition < 1 render transition between two scenes
renderer.setRenderTarget( this.renderTargetA );
renderer.render( this.sceneA, this.cameraA );
renderer.setRenderTarget( this.renderTargetB );
renderer.render( this.sceneB, this.cameraB );
uniforms.tDiffuse1.value = this.renderTargetA.texture;
uniforms.tDiffuse2.value = this.renderTargetB.texture;
if ( this.renderToScreen ) {
renderer.setRenderTarget( null );
renderer.clear();
} else {
renderer.setRenderTarget( writeBuffer );
if ( this.clear ) renderer.clear();
}
this.fsQuad.render( renderer );
}
}
dispose() {
this.renderTargetA.dispose();
this.renderTargetB.dispose();
this.material.dispose();
this.fsQuad.dispose();
}
createMaterial() {
return new ShaderMaterial( {
uniforms: {
tDiffuse1: {
value: null
},
tDiffuse2: {
value: null
},
mixRatio: {
value: 0.0
},
threshold: {
value: 0.1
},
useTexture: {
value: 1
},
tMixTexture: {
value: null
}
},
vertexShader: /* glsl */`
varying vec2 vUv;
void main() {
vUv = vec2( uv.x, uv.y );
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`,
fragmentShader: /* glsl */`
uniform float mixRatio;
uniform sampler2D tDiffuse1;
uniform sampler2D tDiffuse2;
uniform sampler2D tMixTexture;
uniform int useTexture;
uniform float threshold;
varying vec2 vUv;
void main() {
vec4 texel1 = texture2D( tDiffuse1, vUv );
vec4 texel2 = texture2D( tDiffuse2, vUv );
if (useTexture == 1) {
vec4 transitionTexel = texture2D( tMixTexture, vUv );
float r = mixRatio * ( 1.0 + threshold * 2.0 ) - threshold;
float mixf = clamp( ( transitionTexel.r - r ) * ( 1.0 / threshold ), 0.0, 1.0 );
gl_FragColor = mix( texel1, texel2, mixf );
} else {
gl_FragColor = mix( texel2, texel1, mixRatio );
}
#include <tonemapping_fragment>
#include <colorspace_fragment>
}
`
} );
}
}
export { RenderTransitionPass };