|
|
@@ -9,14 +9,16 @@
|
|
|
|
|
|
<body>
|
|
|
<div id="info">
|
|
|
- <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - webgl god-rays example - tree by <a href="http://www.turbosquid.com/3d-models/free-tree-3d-model/592617" target="_blank" rel="noopener">stanloshka</a>
|
|
|
+ <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - webgl god-rays example - <a href="https://github.com/Ameobea/three-good-godrays" target="_blank" rel="noopener">three-good-godrays extension</a>
|
|
|
</div>
|
|
|
|
|
|
<script type="importmap">
|
|
|
{
|
|
|
"imports": {
|
|
|
"three": "../build/three.module.js",
|
|
|
- "three/addons/": "./jsm/"
|
|
|
+ "three/addons/": "./jsm/",
|
|
|
+ "postprocessing": "https://unpkg.com/postprocessing@6.38.2/build/index.js",
|
|
|
+ "goodrays": "https://unpkg.com/three-good-godrays@0.8.1/build/three-good-godrays.esm.js"
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
@@ -27,92 +29,130 @@
|
|
|
|
|
|
import Stats from 'three/addons/libs/stats.module.js';
|
|
|
|
|
|
- import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
|
|
|
+ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
|
|
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
|
- import { GodRaysFakeSunShader, GodRaysDepthMaskShader, GodRaysCombineShader, GodRaysGenerateShader } from 'three/addons/shaders/GodRaysShader.js';
|
|
|
|
|
|
- let container, stats;
|
|
|
- let camera, scene, renderer, materialDepth;
|
|
|
+ import { EffectComposer, RenderPass } from 'postprocessing';
|
|
|
+ import { GodraysPass } from 'goodrays';
|
|
|
|
|
|
- let sphereMesh;
|
|
|
+ let camera, scene, renderer, composer;
|
|
|
+ let controls, stats;
|
|
|
|
|
|
- const sunPosition = new THREE.Vector3( 0, 1000, - 1000 );
|
|
|
- const clipPosition = new THREE.Vector4();
|
|
|
- const screenSpacePosition = new THREE.Vector3();
|
|
|
+ init();
|
|
|
|
|
|
- const postprocessing = { enabled: true };
|
|
|
+ async function init() {
|
|
|
|
|
|
- const orbitRadius = 200;
|
|
|
+ camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 1000 );
|
|
|
+ camera.position.set( - 175, 50, 0 );
|
|
|
|
|
|
- const bgColor = 0x000511;
|
|
|
- const sunColor = 0xffee00;
|
|
|
+ scene = new THREE.Scene();
|
|
|
+ scene.background = new THREE.Color( 0x000000 );
|
|
|
|
|
|
- // Use a smaller size for some of the god-ray render targets for better performance.
|
|
|
- const godrayRenderTargetResolutionMultiplier = 1.0 / 4.0;
|
|
|
+ // asset
|
|
|
|
|
|
- init();
|
|
|
+ const loader = new GLTFLoader();
|
|
|
+ const gltf = await loader.loadAsync( 'models/gltf/godrays_demo.glb' );
|
|
|
+ scene.add( gltf.scene );
|
|
|
|
|
|
- function init() {
|
|
|
+ const pillars = gltf.scene.getObjectByName( 'concrete' );
|
|
|
+ pillars.material = new THREE.MeshStandardMaterial( {
|
|
|
+ color: 0x333333,
|
|
|
+ } );
|
|
|
|
|
|
- container = document.createElement( 'div' );
|
|
|
- document.body.appendChild( container );
|
|
|
+ const base = gltf.scene.getObjectByName( 'base' );
|
|
|
+ base.material = new THREE.MeshStandardMaterial( {
|
|
|
+ color: 0x333333,
|
|
|
+ side: THREE.DoubleSide,
|
|
|
+ } );
|
|
|
|
|
|
- //
|
|
|
+ setupBackdrop();
|
|
|
|
|
|
- camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 3000 );
|
|
|
- camera.position.z = 200;
|
|
|
+ // lights
|
|
|
|
|
|
- scene = new THREE.Scene();
|
|
|
+ const lightPos = new THREE.Vector3( 0, 50, 0 );
|
|
|
+ const lightSphereMaterial = new THREE.MeshBasicMaterial( {
|
|
|
+ color: 0xffffff,
|
|
|
+ } );
|
|
|
+ const lightSphere = new THREE.Mesh( new THREE.SphereGeometry( 0.5, 16, 16 ), lightSphereMaterial );
|
|
|
+ lightSphere.position.copy( lightPos );
|
|
|
+ scene.add( lightSphere );
|
|
|
|
|
|
- //
|
|
|
+ scene.add( new THREE.AmbientLight( 0xcccccc, 0.4 ) );
|
|
|
|
|
|
- materialDepth = new THREE.MeshDepthMaterial();
|
|
|
+ const pointLight = new THREE.PointLight( 0xf6287d, 10000 );
|
|
|
+ pointLight.castShadow = true;
|
|
|
+ pointLight.shadow.bias = - 0.001;
|
|
|
+ pointLight.shadow.mapSize.width = 1024;
|
|
|
+ pointLight.shadow.mapSize.height = 1024;
|
|
|
+ pointLight.position.copy( lightPos );
|
|
|
+ scene.add( pointLight );
|
|
|
|
|
|
- // tree
|
|
|
+ // shadow setup
|
|
|
|
|
|
- const loader = new OBJLoader();
|
|
|
- loader.load( 'models/obj/tree.obj', function ( object ) {
|
|
|
+ scene.traverse( obj => {
|
|
|
|
|
|
- object.position.set( 0, - 150, - 150 );
|
|
|
- object.scale.multiplyScalar( 400 );
|
|
|
- scene.add( object );
|
|
|
+ if ( obj.isMesh === true ) {
|
|
|
|
|
|
- } );
|
|
|
+ obj.castShadow = true;
|
|
|
+ obj.receiveShadow = true;
|
|
|
|
|
|
- // sphere
|
|
|
+ }
|
|
|
|
|
|
- const geo = new THREE.SphereGeometry( 1, 20, 10 );
|
|
|
- sphereMesh = new THREE.Mesh( geo, new THREE.MeshBasicMaterial( { color: 0x000000 } ) );
|
|
|
- sphereMesh.scale.multiplyScalar( 20 );
|
|
|
- scene.add( sphereMesh );
|
|
|
+ } );
|
|
|
+
|
|
|
+ lightSphere.castShadow = false;
|
|
|
+ lightSphere.receiveShadow = false;
|
|
|
|
|
|
//
|
|
|
|
|
|
renderer = new THREE.WebGLRenderer();
|
|
|
- renderer.setClearColor( 0xffffff );
|
|
|
renderer.setPixelRatio( window.devicePixelRatio );
|
|
|
renderer.setSize( window.innerWidth, window.innerHeight );
|
|
|
renderer.setAnimationLoop( animate );
|
|
|
- container.appendChild( renderer.domElement );
|
|
|
+ renderer.shadowMap.enabled = true;
|
|
|
+ document.body.appendChild( renderer.domElement );
|
|
|
+
|
|
|
+ //
|
|
|
|
|
|
- renderer.autoClear = false;
|
|
|
+ composer = new EffectComposer( renderer, { frameBufferType: THREE.HalfFloatType } );
|
|
|
|
|
|
- const controls = new OrbitControls( camera, renderer.domElement );
|
|
|
- controls.minDistance = 50;
|
|
|
- controls.maxDistance = 500;
|
|
|
+ const renderPass = new RenderPass( scene, camera );
|
|
|
+ composer.addPass( renderPass );
|
|
|
+
|
|
|
+ const params = {
|
|
|
+ density: 1 / 128,
|
|
|
+ maxDensity: 0.5,
|
|
|
+ edgeStrength: 2,
|
|
|
+ edgeRadius: 2,
|
|
|
+ distanceAttenuation: 2,
|
|
|
+ color: new THREE.Color( 0xf6287d ),
|
|
|
+ raymarchSteps: 60,
|
|
|
+ blur: true,
|
|
|
+ gammaCorrection: true,
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ const godraysPass = new GodraysPass( pointLight, camera, params );
|
|
|
+ godraysPass.renderToScreen = true;
|
|
|
+ composer.addPass( godraysPass );
|
|
|
|
|
|
//
|
|
|
|
|
|
- stats = new Stats();
|
|
|
- container.appendChild( stats.dom );
|
|
|
+ controls = new OrbitControls( camera, renderer.domElement );
|
|
|
+ controls.target.set( 0, 0.5, 0 );
|
|
|
+ controls.enableDamping = true;
|
|
|
+ controls.maxDistance = 200;
|
|
|
+ controls.update();
|
|
|
|
|
|
//
|
|
|
|
|
|
- window.addEventListener( 'resize', onWindowResize );
|
|
|
+ stats = new Stats();
|
|
|
+ document.body.appendChild( stats.dom );
|
|
|
|
|
|
//
|
|
|
|
|
|
- initPostprocessing( window.innerWidth, window.innerHeight );
|
|
|
+ window.addEventListener( 'resize', onWindowResize );
|
|
|
+
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -120,254 +160,59 @@
|
|
|
|
|
|
function onWindowResize() {
|
|
|
|
|
|
- const renderTargetWidth = window.innerWidth;
|
|
|
- const renderTargetHeight = window.innerHeight;
|
|
|
-
|
|
|
- camera.aspect = renderTargetWidth / renderTargetHeight;
|
|
|
+ camera.aspect = window.innerWidth / window.innerHeight;
|
|
|
camera.updateProjectionMatrix();
|
|
|
|
|
|
- renderer.setSize( renderTargetWidth, renderTargetHeight );
|
|
|
- postprocessing.rtTextureColors.setSize( renderTargetWidth, renderTargetHeight );
|
|
|
- postprocessing.rtTextureDepth.setSize( renderTargetWidth, renderTargetHeight );
|
|
|
- postprocessing.rtTextureDepthMask.setSize( renderTargetWidth, renderTargetHeight );
|
|
|
-
|
|
|
- const adjustedWidth = renderTargetWidth * godrayRenderTargetResolutionMultiplier;
|
|
|
- const adjustedHeight = renderTargetHeight * godrayRenderTargetResolutionMultiplier;
|
|
|
- postprocessing.rtTextureGodRays1.setSize( adjustedWidth, adjustedHeight );
|
|
|
- postprocessing.rtTextureGodRays2.setSize( adjustedWidth, adjustedHeight );
|
|
|
+ renderer.setSize( window.innerWidth, window.innerHeight );
|
|
|
|
|
|
}
|
|
|
|
|
|
- function initPostprocessing( renderTargetWidth, renderTargetHeight ) {
|
|
|
-
|
|
|
- postprocessing.scene = new THREE.Scene();
|
|
|
-
|
|
|
- postprocessing.camera = new THREE.OrthographicCamera( - 0.5, 0.5, 0.5, - 0.5, - 10000, 10000 );
|
|
|
- postprocessing.camera.position.z = 100;
|
|
|
-
|
|
|
- postprocessing.scene.add( postprocessing.camera );
|
|
|
-
|
|
|
- postprocessing.rtTextureColors = new THREE.WebGLRenderTarget( renderTargetWidth, renderTargetHeight, { type: THREE.HalfFloatType } );
|
|
|
-
|
|
|
- // I would have this quarter size and use it as one of the ping-pong render
|
|
|
- // targets but the aliasing causes some temporal flickering
|
|
|
-
|
|
|
- postprocessing.rtTextureDepth = new THREE.WebGLRenderTarget( renderTargetWidth, renderTargetHeight, { type: THREE.HalfFloatType } );
|
|
|
- postprocessing.rtTextureDepthMask = new THREE.WebGLRenderTarget( renderTargetWidth, renderTargetHeight, { type: THREE.HalfFloatType } );
|
|
|
-
|
|
|
- // The ping-pong render targets can use an adjusted resolution to minimize cost
|
|
|
-
|
|
|
- const adjustedWidth = renderTargetWidth * godrayRenderTargetResolutionMultiplier;
|
|
|
- const adjustedHeight = renderTargetHeight * godrayRenderTargetResolutionMultiplier;
|
|
|
- postprocessing.rtTextureGodRays1 = new THREE.WebGLRenderTarget( adjustedWidth, adjustedHeight, { type: THREE.HalfFloatType } );
|
|
|
- postprocessing.rtTextureGodRays2 = new THREE.WebGLRenderTarget( adjustedWidth, adjustedHeight, { type: THREE.HalfFloatType } );
|
|
|
-
|
|
|
- // god-ray shaders
|
|
|
-
|
|
|
- const godraysMaskShader = GodRaysDepthMaskShader;
|
|
|
- postprocessing.godrayMaskUniforms = THREE.UniformsUtils.clone( godraysMaskShader.uniforms );
|
|
|
- postprocessing.materialGodraysDepthMask = new THREE.ShaderMaterial( {
|
|
|
-
|
|
|
- uniforms: postprocessing.godrayMaskUniforms,
|
|
|
- vertexShader: godraysMaskShader.vertexShader,
|
|
|
- fragmentShader: godraysMaskShader.fragmentShader
|
|
|
+ function setupBackdrop() {
|
|
|
|
|
|
+ const backdropDistance = 200;
|
|
|
+ // Add backdrop walls `backdropDistance` units away from the origin
|
|
|
+ const backdropGeometry = new THREE.PlaneGeometry( 400, 200 );
|
|
|
+ const backdropMaterial = new THREE.MeshBasicMaterial( {
|
|
|
+ color: 0x200808,
|
|
|
+ side: THREE.DoubleSide,
|
|
|
} );
|
|
|
-
|
|
|
- const godraysGenShader = GodRaysGenerateShader;
|
|
|
- postprocessing.godrayGenUniforms = THREE.UniformsUtils.clone( godraysGenShader.uniforms );
|
|
|
- postprocessing.materialGodraysGenerate = new THREE.ShaderMaterial( {
|
|
|
-
|
|
|
- uniforms: postprocessing.godrayGenUniforms,
|
|
|
- vertexShader: godraysGenShader.vertexShader,
|
|
|
- fragmentShader: godraysGenShader.fragmentShader
|
|
|
-
|
|
|
- } );
|
|
|
-
|
|
|
- const godraysCombineShader = GodRaysCombineShader;
|
|
|
- postprocessing.godrayCombineUniforms = THREE.UniformsUtils.clone( godraysCombineShader.uniforms );
|
|
|
- postprocessing.materialGodraysCombine = new THREE.ShaderMaterial( {
|
|
|
-
|
|
|
- uniforms: postprocessing.godrayCombineUniforms,
|
|
|
- vertexShader: godraysCombineShader.vertexShader,
|
|
|
- fragmentShader: godraysCombineShader.fragmentShader
|
|
|
-
|
|
|
- } );
|
|
|
-
|
|
|
- const godraysFakeSunShader = GodRaysFakeSunShader;
|
|
|
- postprocessing.godraysFakeSunUniforms = THREE.UniformsUtils.clone( godraysFakeSunShader.uniforms );
|
|
|
- postprocessing.materialGodraysFakeSun = new THREE.ShaderMaterial( {
|
|
|
-
|
|
|
- uniforms: postprocessing.godraysFakeSunUniforms,
|
|
|
- vertexShader: godraysFakeSunShader.vertexShader,
|
|
|
- fragmentShader: godraysFakeSunShader.fragmentShader
|
|
|
-
|
|
|
- } );
|
|
|
-
|
|
|
- postprocessing.godraysFakeSunUniforms.bgColor.value.setHex( bgColor );
|
|
|
- postprocessing.godraysFakeSunUniforms.sunColor.value.setHex( sunColor );
|
|
|
-
|
|
|
- postprocessing.godrayCombineUniforms.fGodRayIntensity.value = 0.75;
|
|
|
-
|
|
|
- postprocessing.quad = new THREE.Mesh(
|
|
|
- new THREE.PlaneGeometry( 1.0, 1.0 ),
|
|
|
- postprocessing.materialGodraysGenerate
|
|
|
- );
|
|
|
- postprocessing.quad.position.z = - 9900;
|
|
|
- postprocessing.scene.add( postprocessing.quad );
|
|
|
+ const backdropLeft = new THREE.Mesh( backdropGeometry, backdropMaterial );
|
|
|
+ backdropLeft.position.set( - backdropDistance, 100, 0 );
|
|
|
+ backdropLeft.rotateY( Math.PI / 2 );
|
|
|
+ scene.add( backdropLeft );
|
|
|
+
|
|
|
+ const backdropRight = new THREE.Mesh( backdropGeometry, backdropMaterial );
|
|
|
+ backdropRight.position.set( backdropDistance, 100, 0 );
|
|
|
+ backdropRight.rotateY( Math.PI / 2 );
|
|
|
+ scene.add( backdropRight );
|
|
|
+
|
|
|
+ const backdropFront = new THREE.Mesh( backdropGeometry, backdropMaterial );
|
|
|
+ backdropFront.position.set( 0, 100, - backdropDistance );
|
|
|
+ scene.add( backdropFront );
|
|
|
+
|
|
|
+ const backdropBack = new THREE.Mesh( backdropGeometry, backdropMaterial );
|
|
|
+ backdropBack.position.set( 0, 100, backdropDistance );
|
|
|
+ scene.add( backdropBack );
|
|
|
+
|
|
|
+ const backdropTop = new THREE.Mesh( backdropGeometry, backdropMaterial );
|
|
|
+ backdropTop.position.set( 0, 200, 0 );
|
|
|
+ backdropTop.rotateX( Math.PI / 2 );
|
|
|
+ backdropTop.scale.set( 3, 6, 1 );
|
|
|
+ scene.add( backdropTop );
|
|
|
|
|
|
}
|
|
|
|
|
|
function animate() {
|
|
|
|
|
|
- stats.begin();
|
|
|
- render();
|
|
|
- stats.end();
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- function getStepSize( filterLen, tapsPerPass, pass ) {
|
|
|
-
|
|
|
- return filterLen * Math.pow( tapsPerPass, - pass );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- function filterGodRays( inputTex, renderTarget, stepSize ) {
|
|
|
-
|
|
|
- postprocessing.scene.overrideMaterial = postprocessing.materialGodraysGenerate;
|
|
|
-
|
|
|
- postprocessing.godrayGenUniforms[ 'fStepSize' ].value = stepSize;
|
|
|
- postprocessing.godrayGenUniforms[ 'tInput' ].value = inputTex;
|
|
|
-
|
|
|
- renderer.setRenderTarget( renderTarget );
|
|
|
- renderer.render( postprocessing.scene, postprocessing.camera );
|
|
|
- postprocessing.scene.overrideMaterial = null;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- function render() {
|
|
|
-
|
|
|
- const time = Date.now() / 4000;
|
|
|
-
|
|
|
- sphereMesh.position.x = orbitRadius * Math.cos( time );
|
|
|
- sphereMesh.position.z = orbitRadius * Math.sin( time ) - 100;
|
|
|
-
|
|
|
- if ( postprocessing.enabled ) {
|
|
|
-
|
|
|
- clipPosition.x = sunPosition.x;
|
|
|
- clipPosition.y = sunPosition.y;
|
|
|
- clipPosition.z = sunPosition.z;
|
|
|
- clipPosition.w = 1;
|
|
|
-
|
|
|
- clipPosition.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );
|
|
|
-
|
|
|
- // perspective divide (produce NDC space)
|
|
|
-
|
|
|
- clipPosition.x /= clipPosition.w;
|
|
|
- clipPosition.y /= clipPosition.w;
|
|
|
-
|
|
|
- screenSpacePosition.x = ( clipPosition.x + 1 ) / 2; // transform from [-1,1] to [0,1]
|
|
|
- screenSpacePosition.y = ( clipPosition.y + 1 ) / 2; // transform from [-1,1] to [0,1]
|
|
|
- screenSpacePosition.z = clipPosition.z; // needs to stay in clip space for visibility checks
|
|
|
-
|
|
|
- // Give it to the god-ray and sun shaders
|
|
|
-
|
|
|
- postprocessing.godrayGenUniforms[ 'vSunPositionScreenSpace' ].value.copy( screenSpacePosition );
|
|
|
- postprocessing.godraysFakeSunUniforms[ 'vSunPositionScreenSpace' ].value.copy( screenSpacePosition );
|
|
|
-
|
|
|
- // -- Draw sky and sun --
|
|
|
-
|
|
|
- // Clear colors and depths, will clear to sky color
|
|
|
-
|
|
|
- renderer.setRenderTarget( postprocessing.rtTextureColors );
|
|
|
- renderer.clear( true, true, false );
|
|
|
-
|
|
|
- // Sun render. Runs a shader that gives a brightness based on the screen
|
|
|
- // space distance to the sun. Not very efficient, so i make a scissor
|
|
|
- // rectangle around the suns position to avoid rendering surrounding pixels.
|
|
|
-
|
|
|
- const sunsqH = 0.74 * window.innerHeight; // 0.74 depends on extent of sun from shader
|
|
|
- const sunsqW = 0.74 * window.innerHeight; // both depend on height because sun is aspect-corrected
|
|
|
-
|
|
|
- screenSpacePosition.x *= window.innerWidth;
|
|
|
- screenSpacePosition.y *= window.innerHeight;
|
|
|
-
|
|
|
- renderer.setScissor( screenSpacePosition.x - sunsqW / 2, screenSpacePosition.y - sunsqH / 2, sunsqW, sunsqH );
|
|
|
- renderer.setScissorTest( true );
|
|
|
+ controls.update();
|
|
|
|
|
|
- postprocessing.godraysFakeSunUniforms[ 'fAspect' ].value = window.innerWidth / window.innerHeight;
|
|
|
-
|
|
|
- postprocessing.scene.overrideMaterial = postprocessing.materialGodraysFakeSun;
|
|
|
- renderer.setRenderTarget( postprocessing.rtTextureColors );
|
|
|
- renderer.render( postprocessing.scene, postprocessing.camera );
|
|
|
-
|
|
|
- renderer.setScissorTest( false );
|
|
|
-
|
|
|
- // -- Draw scene objects --
|
|
|
-
|
|
|
- // Colors
|
|
|
-
|
|
|
- scene.overrideMaterial = null;
|
|
|
- renderer.setRenderTarget( postprocessing.rtTextureColors );
|
|
|
- renderer.render( scene, camera );
|
|
|
-
|
|
|
- // Depth
|
|
|
-
|
|
|
- scene.overrideMaterial = materialDepth;
|
|
|
- renderer.setRenderTarget( postprocessing.rtTextureDepth );
|
|
|
- renderer.clear();
|
|
|
- renderer.render( scene, camera );
|
|
|
-
|
|
|
- //
|
|
|
-
|
|
|
- postprocessing.godrayMaskUniforms[ 'tInput' ].value = postprocessing.rtTextureDepth.texture;
|
|
|
-
|
|
|
- postprocessing.scene.overrideMaterial = postprocessing.materialGodraysDepthMask;
|
|
|
- renderer.setRenderTarget( postprocessing.rtTextureDepthMask );
|
|
|
- renderer.render( postprocessing.scene, postprocessing.camera );
|
|
|
-
|
|
|
- // -- Render god-rays --
|
|
|
-
|
|
|
- // Maximum length of god-rays (in texture space [0,1]X[0,1])
|
|
|
-
|
|
|
- const filterLen = 1.0;
|
|
|
-
|
|
|
- // Samples taken by filter
|
|
|
-
|
|
|
- const TAPS_PER_PASS = 6.0;
|
|
|
-
|
|
|
- // Pass order could equivalently be 3,2,1 (instead of 1,2,3), which
|
|
|
- // would start with a small filter support and grow to large. however
|
|
|
- // the large-to-small order produces less objectionable aliasing artifacts that
|
|
|
- // appear as a glimmer along the length of the beams
|
|
|
-
|
|
|
- // pass 1 - render into first ping-pong target
|
|
|
- filterGodRays( postprocessing.rtTextureDepthMask.texture, postprocessing.rtTextureGodRays2, getStepSize( filterLen, TAPS_PER_PASS, 1.0 ) );
|
|
|
-
|
|
|
- // pass 2 - render into second ping-pong target
|
|
|
- filterGodRays( postprocessing.rtTextureGodRays2.texture, postprocessing.rtTextureGodRays1, getStepSize( filterLen, TAPS_PER_PASS, 2.0 ) );
|
|
|
-
|
|
|
- // pass 3 - 1st RT
|
|
|
- filterGodRays( postprocessing.rtTextureGodRays1.texture, postprocessing.rtTextureGodRays2, getStepSize( filterLen, TAPS_PER_PASS, 3.0 ) );
|
|
|
-
|
|
|
- // final pass - composite god-rays onto colors
|
|
|
-
|
|
|
- postprocessing.godrayCombineUniforms[ 'tColors' ].value = postprocessing.rtTextureColors.texture;
|
|
|
- postprocessing.godrayCombineUniforms[ 'tGodRays' ].value = postprocessing.rtTextureGodRays2.texture;
|
|
|
-
|
|
|
- postprocessing.scene.overrideMaterial = postprocessing.materialGodraysCombine;
|
|
|
-
|
|
|
- renderer.setRenderTarget( null );
|
|
|
- renderer.render( postprocessing.scene, postprocessing.camera );
|
|
|
- postprocessing.scene.overrideMaterial = null;
|
|
|
-
|
|
|
- } else {
|
|
|
+ stats.begin();
|
|
|
|
|
|
- renderer.setRenderTarget( null );
|
|
|
- renderer.clear();
|
|
|
- renderer.render( scene, camera );
|
|
|
+ composer.render();
|
|
|
|
|
|
- }
|
|
|
+ //renderer.render( scene, camera );
|
|
|
+
|
|
|
+ stats.end();
|
|
|
|
|
|
}
|
|
|
|