Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13917 from HypnosNova/afterimage-effect
add afterimage effect
- Loading branch information
Showing
4 changed files
with
265 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/** | ||
* @author HypnosNova / https://www.threejs.org.cn/gallery/ | ||
*/ | ||
|
||
THREE.AfterimagePass = function ( damp ) { | ||
|
||
THREE.Pass.call( this ); | ||
|
||
if ( THREE.AfterimageShader === undefined ) | ||
console.error( "THREE.AfterimagePass relies on THREE.AfterimageShader" ); | ||
|
||
this.shader = THREE.AfterimageShader; | ||
|
||
this.uniforms = THREE.UniformsUtils.clone( this.shader.uniforms ); | ||
|
||
this.uniforms[ "damp" ].value = damp !== undefined ? damp : 0.96; | ||
|
||
this.textureComp = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, { | ||
|
||
minFilter: THREE.LinearFilter, | ||
magFilter: THREE.NearestFilter, | ||
format: THREE.RGBAFormat | ||
|
||
} ); | ||
|
||
this.textureOld = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, { | ||
|
||
minFilter: THREE.LinearFilter, | ||
magFilter: THREE.NearestFilter, | ||
format: THREE.RGBAFormat | ||
|
||
} ); | ||
|
||
this.shaderMaterial = new THREE.ShaderMaterial( { | ||
|
||
uniforms: this.uniforms, | ||
vertexShader: this.shader.vertexShader, | ||
fragmentShader: this.shader.fragmentShader | ||
|
||
} ); | ||
|
||
this.sceneComp = new THREE.Scene(); | ||
this.scene = new THREE.Scene(); | ||
|
||
this.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 ); | ||
this.camera.position.z = 1; | ||
|
||
var geometry = new THREE.PlaneBufferGeometry( 2, 2 ); | ||
|
||
this.quadComp = new THREE.Mesh( geometry, this.shaderMaterial ); | ||
this.sceneComp.add( this.quadComp ); | ||
|
||
var material = new THREE.MeshBasicMaterial( { | ||
map: this.textureComp.texture | ||
} ); | ||
|
||
var quadScreen = new THREE.Mesh( geometry, material ); | ||
this.scene.add( quadScreen ); | ||
|
||
}; | ||
|
||
THREE.AfterimagePass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), { | ||
|
||
constructor: THREE.AfterimagePass, | ||
|
||
render: function ( renderer, writeBuffer, readBuffer ) { | ||
|
||
this.uniforms[ "tOld" ].value = this.textureOld.texture; | ||
this.uniforms[ "tNew" ].value = readBuffer.texture; | ||
|
||
this.quadComp.material = this.shaderMaterial; | ||
|
||
renderer.render( this.sceneComp, this.camera, this.textureComp ); | ||
renderer.render( this.scene, this.camera, this.textureOld ); | ||
|
||
if ( this.renderToScreen ) { | ||
|
||
renderer.render( this.scene, this.camera ); | ||
|
||
} else { | ||
|
||
renderer.render( this.scene, this.camera, writeBuffer, this.clear ); | ||
|
||
} | ||
|
||
} | ||
|
||
} ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/** | ||
* @author HypnosNova / https://www.threejs.org.cn/gallery/ | ||
* | ||
* Afterimage shader | ||
* I created this effect inspired by a demo on codepen: | ||
* https://codepen.io/brunoimbrizi/pen/MoRJaN?page=1& | ||
*/ | ||
|
||
THREE.AfterimageShader = { | ||
|
||
uniforms: { | ||
|
||
"damp": { value: 0.96 }, | ||
"tOld": { value: null }, | ||
"tNew": { value: null } | ||
|
||
}, | ||
|
||
vertexShader: [ | ||
|
||
"varying vec2 vUv;", | ||
|
||
"void main() {", | ||
|
||
"vUv = uv;", | ||
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", | ||
|
||
"}" | ||
|
||
].join( "\n" ), | ||
|
||
fragmentShader: [ | ||
|
||
"uniform float damp;", | ||
|
||
"uniform sampler2D tOld;", | ||
"uniform sampler2D tNew;", | ||
|
||
"varying vec2 vUv;", | ||
|
||
"vec4 when_gt( vec4 x, float y ) {", | ||
|
||
"return max( sign( x - y ), 0.0 );", | ||
|
||
"}", | ||
|
||
"void main() {", | ||
|
||
"vec4 texelOld = texture2D( tOld, vUv );", | ||
"vec4 texelNew = texture2D( tNew, vUv );", | ||
|
||
"texelOld *= damp * when_gt( texelOld, 0.1 );", | ||
|
||
"gl_FragColor = max(texelNew, texelOld);", | ||
|
||
"}" | ||
|
||
].join( "\n" ) | ||
|
||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>three.js webgl - postprocessing - afterimage</title> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> | ||
<style> | ||
body { | ||
margin: 0px; | ||
background-color: #000000; | ||
overflow: hidden; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
|
||
<script src="../build/three.js"></script> | ||
|
||
<script src="js/shaders/CopyShader.js"></script> | ||
<script src="js/shaders/AfterimageShader.js"></script> | ||
|
||
<script src="js/postprocessing/EffectComposer.js"></script> | ||
<script src="js/postprocessing/RenderPass.js"></script> | ||
<script src="js/postprocessing/MaskPass.js"></script> | ||
<script src="js/postprocessing/ShaderPass.js"></script> | ||
<script src="js/postprocessing/AfterimagePass.js"></script> | ||
|
||
<script src="js/libs/dat.gui.min.js" type="text/javascript" charset="utf-8"></script> | ||
|
||
<script> | ||
|
||
var camera, scene, renderer, composer; | ||
var mesh, light; | ||
|
||
var afterimagePass, enable = true; | ||
|
||
init(); | ||
createGUI(); | ||
animate(); | ||
|
||
function init() { | ||
|
||
renderer = new THREE.WebGLRenderer(); | ||
renderer.setPixelRatio( window.devicePixelRatio ); | ||
renderer.setSize( window.innerWidth, window.innerHeight ); | ||
document.body.appendChild( renderer.domElement ); | ||
|
||
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 ); | ||
camera.position.z = 400; | ||
|
||
scene = new THREE.Scene(); | ||
scene.fog = new THREE.Fog( 0x000000, 1, 1000 ); | ||
|
||
object = new THREE.Object3D(); | ||
scene.add( object ); | ||
|
||
var geometry = new THREE.BoxBufferGeometry( 150, 150, 150, 2, 2, 2); | ||
var material = new THREE.MeshNormalMaterial(); | ||
mesh = new THREE.Mesh( geometry, material ); | ||
scene.add( mesh ); | ||
|
||
// postprocessing | ||
|
||
composer = new THREE.EffectComposer( renderer ); | ||
composer.addPass( new THREE.RenderPass( scene, camera ) ); | ||
|
||
afterimagePass = new THREE.AfterimagePass(); | ||
afterimagePass.renderToScreen = true; | ||
composer.addPass( afterimagePass ); | ||
|
||
window.addEventListener( 'resize', onWindowResize, false ); | ||
|
||
} | ||
|
||
function createGUI(){ | ||
|
||
var gui = new dat.GUI( { name: 'Damp setting' } ); | ||
gui.add( afterimagePass.uniforms[ "damp" ], 'value', 0, 1 ).step( 0.001 ); | ||
gui.add( this, 'enable' ); | ||
|
||
} | ||
|
||
function onWindowResize() { | ||
|
||
camera.aspect = window.innerWidth / window.innerHeight; | ||
camera.updateProjectionMatrix(); | ||
|
||
renderer.setSize( window.innerWidth, window.innerHeight ); | ||
composer.setSize( window.innerWidth, window.innerHeight ); | ||
|
||
} | ||
|
||
function animate() { | ||
|
||
requestAnimationFrame( animate ); | ||
|
||
var time = Date.now(); | ||
|
||
mesh.rotation.x += 0.005; | ||
mesh.rotation.y += 0.01; | ||
|
||
if( enable ){ | ||
|
||
composer.render(); | ||
|
||
} else { | ||
|
||
renderer.render( scene, camera ); | ||
|
||
} | ||
|
||
} | ||
|
||
</script> | ||
</body> | ||
</html> |