diff --git a/examples/jsm/Addons.js b/examples/jsm/Addons.js index d901f4de1746e5..58350ce6d9bed9 100644 --- a/examples/jsm/Addons.js +++ b/examples/jsm/Addons.js @@ -223,7 +223,6 @@ export * from './shaders/FilmShader.js'; export * from './shaders/FocusShader.js'; export * from './shaders/FreiChenShader.js'; export * from './shaders/GammaCorrectionShader.js'; -export * from './shaders/GodRaysShader.js'; export * from './shaders/GTAOShader.js'; export * from './shaders/HalftoneShader.js'; export * from './shaders/HorizontalBlurShader.js'; diff --git a/examples/jsm/shaders/GodRaysShader.js b/examples/jsm/shaders/GodRaysShader.js deleted file mode 100644 index 6fe9629adee004..00000000000000 --- a/examples/jsm/shaders/GodRaysShader.js +++ /dev/null @@ -1,333 +0,0 @@ -import { - Color, - Vector3 -} from 'three'; - -/** - * @module GodRaysShader - * @three_import import * as GodRaysShader from 'three/addons/shaders/GodRaysShader.js'; - */ - -/** - * God-rays (crepuscular rays) - * - * Similar implementation to the one used by Crytek for CryEngine 2 [Sousa2008]. - * Blurs a mask generated from the depth map along radial lines emanating from the light - * source. The blur repeatedly applies a blur filter of increasing support but constant - * sample count to produce a blur filter with large support. - * - * My implementation performs 3 passes, similar to the implementation from Sousa. I found - * just 6 samples per pass produced acceptable results. The blur is applied three times, - * with decreasing filter support. The result is equivalent to a single pass with - * 6*6*6 = 216 samples. - * - * References: - * - [Sousa2008, Crysis Next Gen Effects, GDC2008](http://www.crytek.com/sites/default/files/GDC08_SousaT_CrysisEffects.ppt). - * - * @constant - * @type {ShaderMaterial~Shader} - */ -const GodRaysDepthMaskShader = { - - name: 'GodRaysDepthMaskShader', - - uniforms: { - - tInput: { - value: null - } - - }, - - vertexShader: /* glsl */` - - varying vec2 vUv; - - void main() { - - vUv = uv; - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); - - }`, - - fragmentShader: /* glsl */` - - varying vec2 vUv; - - uniform sampler2D tInput; - - void main() { - - gl_FragColor = vec4( 1.0 ) - texture2D( tInput, vUv ); - - }` - -}; - - -/** - * The god-ray generation shader. - * - * First pass: - * - * The depth map is blurred along radial lines towards the "sun". The - * output is written to a temporary render target (I used a 1/4 sized - * target). - * - * Pass two & three: - * - * The results of the previous pass are re-blurred, each time with a - * decreased distance between samples. - * - * @constant - * @type {ShaderMaterial~Shader} - */ -const GodRaysGenerateShader = { - - name: 'GodRaysGenerateShader', - - uniforms: { - - tInput: { - value: null - }, - fStepSize: { - value: 1.0 - }, - vSunPositionScreenSpace: { - value: new Vector3() - } - - }, - - vertexShader: /* glsl */` - - varying vec2 vUv; - - void main() { - - vUv = uv; - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); - - }`, - - fragmentShader: /* glsl */` - - #define TAPS_PER_PASS 6.0 - - varying vec2 vUv; - - uniform sampler2D tInput; - - uniform vec3 vSunPositionScreenSpace; - uniform float fStepSize; // filter step size - - void main() { - - // delta from current pixel to "sun" position - - vec2 delta = vSunPositionScreenSpace.xy - vUv; - float dist = length( delta ); - - // Step vector (uv space) - - vec2 stepv = fStepSize * delta / dist; - - // Number of iterations between pixel and sun - - float iters = dist/fStepSize; - - vec2 uv = vUv.xy; - float col = 0.0; - - // This breaks ANGLE in Chrome 22 - // - see http://code.google.com/p/chromium/issues/detail?id=153105 - - /* - // Unrolling didn't do much on my hardware (ATI Mobility Radeon 3450), - // so i've just left the loop - - "for ( float i = 0.0; i < TAPS_PER_PASS; i += 1.0 ) {", - - // Accumulate samples, making sure we don't walk past the light source. - - // The check for uv.y < 1 would not be necessary with "border" UV wrap - // mode, with a black border color. I don't think this is currently - // exposed by three.js. As a result there might be artifacts when the - // sun is to the left, right or bottom of screen as these cases are - // not specifically handled. - - " col += ( i <= iters && uv.y < 1.0 ? texture2D( tInput, uv ).r : 0.0 );", - " uv += stepv;", - - "}", - */ - - // Unrolling loop manually makes it work in ANGLE - - float f = min( 1.0, max( vSunPositionScreenSpace.z / 1000.0, 0.0 ) ); // used to fade out godrays - - if ( 0.0 <= iters && uv.y < 1.0 ) col += texture2D( tInput, uv ).r * f; - uv += stepv; - - if ( 1.0 <= iters && uv.y < 1.0 ) col += texture2D( tInput, uv ).r * f; - uv += stepv; - - if ( 2.0 <= iters && uv.y < 1.0 ) col += texture2D( tInput, uv ).r * f; - uv += stepv; - - if ( 3.0 <= iters && uv.y < 1.0 ) col += texture2D( tInput, uv ).r * f; - uv += stepv; - - if ( 4.0 <= iters && uv.y < 1.0 ) col += texture2D( tInput, uv ).r * f; - uv += stepv; - - if ( 5.0 <= iters && uv.y < 1.0 ) col += texture2D( tInput, uv ).r * f; - uv += stepv; - - // Should technically be dividing by 'iters but 'TAPS_PER_PASS' smooths out - // objectionable artifacts, in particular near the sun position. The side - // effect is that the result is darker than it should be around the sun, as - // TAPS_PER_PASS is greater than the number of samples actually accumulated. - // When the result is inverted (in the shader 'godrays_combine this produces - // a slight bright spot at the position of the sun, even when it is occluded. - - gl_FragColor = vec4( col/TAPS_PER_PASS ); - gl_FragColor.a = 1.0; - - }` - -}; - -/** - * Additively applies god rays from texture tGodRays to a background (tColors). - * fGodRayIntensity attenuates the god rays. - * - * @constant - * @type {ShaderMaterial~Shader} - */ -const GodRaysCombineShader = { - - name: 'GodRaysCombineShader', - - uniforms: { - - tColors: { - value: null - }, - - tGodRays: { - value: null - }, - - fGodRayIntensity: { - value: 0.69 - } - - }, - - vertexShader: /* glsl */` - - varying vec2 vUv; - - void main() { - - vUv = uv; - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); - - }`, - - fragmentShader: /* glsl */` - - varying vec2 vUv; - - uniform sampler2D tColors; - uniform sampler2D tGodRays; - - uniform float fGodRayIntensity; - - void main() { - - // Since THREE.MeshDepthMaterial renders foreground objects white and background - // objects black, the god-rays will be white streaks. Therefore value is inverted - // before being combined with tColors - - gl_FragColor = texture2D( tColors, vUv ) + fGodRayIntensity * vec4( 1.0 - texture2D( tGodRays, vUv ).r ); - gl_FragColor.a = 1.0; - - }` - -}; - - -/** - * A dodgy sun/sky shader. Makes a bright spot at the sun location. Would be - * cheaper/faster/simpler to implement this as a simple sun sprite. - * - * @constant - * @type {Object} - */ -const GodRaysFakeSunShader = { - - name: 'GodRaysFakeSunShader', - - uniforms: { - - vSunPositionScreenSpace: { - value: new Vector3() - }, - - fAspect: { - value: 1.0 - }, - - sunColor: { - value: new Color( 0xffee00 ) - }, - - bgColor: { - value: new Color( 0x000000 ) - } - - }, - - vertexShader: /* glsl */` - - varying vec2 vUv; - - void main() { - - vUv = uv; - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); - - }`, - - fragmentShader: /* glsl */` - - varying vec2 vUv; - - uniform vec3 vSunPositionScreenSpace; - uniform float fAspect; - - uniform vec3 sunColor; - uniform vec3 bgColor; - - void main() { - - vec2 diff = vUv - vSunPositionScreenSpace.xy; - - // Correct for aspect ratio - - diff.x *= fAspect; - - float prop = clamp( length( diff ) / 0.5, 0.0, 1.0 ); - prop = 0.35 * pow( 1.0 - prop, 3.0 ); - - gl_FragColor.xyz = ( vSunPositionScreenSpace.z > 0.0 ) ? mix( sunColor, bgColor, 1.0 - prop ) : bgColor; - gl_FragColor.w = 1.0; - - }` - -}; - -export { GodRaysDepthMaskShader, GodRaysGenerateShader, GodRaysCombineShader, GodRaysFakeSunShader }; diff --git a/examples/models/gltf/godrays_demo.glb b/examples/models/gltf/godrays_demo.glb new file mode 100644 index 00000000000000..4e63ff9131dfdb Binary files /dev/null and b/examples/models/gltf/godrays_demo.glb differ diff --git a/examples/screenshots/webgl_postprocessing_godrays.jpg b/examples/screenshots/webgl_postprocessing_godrays.jpg index 60ddccdd51a986..0a8a358541c7bd 100644 Binary files a/examples/screenshots/webgl_postprocessing_godrays.jpg and b/examples/screenshots/webgl_postprocessing_godrays.jpg differ diff --git a/examples/tags.json b/examples/tags.json index 16dd0c5053e6c2..edee62010f7d63 100644 --- a/examples/tags.json +++ b/examples/tags.json @@ -102,7 +102,7 @@ "webgl_postprocessing_dof": [ "bokeh" ], "webgl_postprocessing_dof2": [ "bokeh" ], "webgl_postprocessing_fxaa": [ "msaa", "multisampled" ], - "webgl_postprocessing_godrays": [ "light scattering" ], + "webgl_postprocessing_godrays": [ "community" ], "webgl_postprocessing_gtao": [ "ambient occlusion" ], "webgl_shadowmap_progressive": [ "shadow", "soft", "lightmap", "onBeforeCompile" ], "webgl_postprocessing_ssaa": [ "msaa", "multisampled" ], diff --git a/examples/webgl_postprocessing_godrays.html b/examples/webgl_postprocessing_godrays.html index 605ffab5d308dd..e6efed53c1f35d 100644 --- a/examples/webgl_postprocessing_godrays.html +++ b/examples/webgl_postprocessing_godrays.html @@ -9,14 +9,16 @@
- three.js - webgl god-rays example - tree by stanloshka + three.js - webgl god-rays example - three-good-godrays extension
@@ -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(); }