瀏覽代碼

Examples: More sRGB and color management fixes. (#26092)

* Examples: More sRGB and color management fixes.

* Examples: Update screenshots.
Michael Herzog 2 年之前
父節點
當前提交
d5835f3b1a

+ 0 - 1
examples/files.json

@@ -309,7 +309,6 @@
 		"webgl_shadowmap_pcss",
 		"webgl_shadowmap_pcss",
 		"webgl_shadowmap_progressive",
 		"webgl_shadowmap_progressive",
 		"webgl_simple_gi",
 		"webgl_simple_gi",
-		"webgl_tiled_forward",
 		"webgl_worker_offscreencanvas"
 		"webgl_worker_offscreencanvas"
 	],
 	],
 	"webgl2": [
 	"webgl2": [

+ 6 - 20
examples/jsm/effects/AnaglyphEffect.js

@@ -75,38 +75,24 @@ class AnaglyphEffect {
 				'uniform mat3 colorMatrixLeft;',
 				'uniform mat3 colorMatrixLeft;',
 				'uniform mat3 colorMatrixRight;',
 				'uniform mat3 colorMatrixRight;',
 
 
-				// These functions implement sRGB linearization and gamma correction
-
-				'float lin( float c ) {',
-				'	return c <= 0.04045 ? c * 0.0773993808 :',
-				'			pow( c * 0.9478672986 + 0.0521327014, 2.4 );',
-				'}',
-
-				'vec4 lin( vec4 c ) {',
-				'	return vec4( lin( c.r ), lin( c.g ), lin( c.b ), c.a );',
-				'}',
-
-				'float dev( float c ) {',
-				'	return c <= 0.0031308 ? c * 12.92',
-				'			: pow( c, 0.41666 ) * 1.055 - 0.055;',
-				'}',
-
-
 				'void main() {',
 				'void main() {',
 
 
 				'	vec2 uv = vUv;',
 				'	vec2 uv = vUv;',
 
 
-				'	vec4 colorL = lin( texture2D( mapLeft, uv ) );',
-				'	vec4 colorR = lin( texture2D( mapRight, uv ) );',
+				'	vec4 colorL = texture2D( mapLeft, uv );',
+				'	vec4 colorR = texture2D( mapRight, uv );',
 
 
 				'	vec3 color = clamp(',
 				'	vec3 color = clamp(',
 				'			colorMatrixLeft * colorL.rgb +',
 				'			colorMatrixLeft * colorL.rgb +',
 				'			colorMatrixRight * colorR.rgb, 0., 1. );',
 				'			colorMatrixRight * colorR.rgb, 0., 1. );',
 
 
 				'	gl_FragColor = vec4(',
 				'	gl_FragColor = vec4(',
-				'			dev( color.r ), dev( color.g ), dev( color.b ),',
+				'			color.r, color.g, color.b,',
 				'			max( colorL.a, colorR.a ) );',
 				'			max( colorL.a, colorR.a ) );',
 
 
+				'	#include <tonemapping_fragment>',
+				'	#include <encodings_fragment>',
+
 				'}'
 				'}'
 
 
 			].join( '\n' )
 			].join( '\n' )

+ 3 - 0
examples/jsm/effects/ParallaxBarrierEffect.js

@@ -68,6 +68,9 @@ class ParallaxBarrierEffect {
 
 
 				'	}',
 				'	}',
 
 
+				'	#include <tonemapping_fragment>',
+				'	#include <encodings_fragment>',
+
 				'}'
 				'}'
 
 
 			].join( '\n' )
 			].join( '\n' )

二進制
examples/screenshots/webgl2_multiple_rendertargets.jpg


二進制
examples/screenshots/webgl2_multisampled_renderbuffers.jpg


二進制
examples/screenshots/webgl2_ubo.jpg


二進制
examples/screenshots/webgl_effects_anaglyph.jpg


二進制
examples/screenshots/webgl_effects_parallaxbarrier.jpg


二進制
examples/screenshots/webgl_effects_peppersghost.jpg


二進制
examples/screenshots/webgl_tiled_forward.jpg


+ 0 - 1
examples/tags.json

@@ -95,7 +95,6 @@
 	"webgl_shadowmap_csm": [ "cascade" ],
 	"webgl_shadowmap_csm": [ "cascade" ],
 	"webgl_shadowmap_pcss": [ "soft" ],
 	"webgl_shadowmap_pcss": [ "soft" ],
 	"webgl_simple_gi": [ "global illumination" ],
 	"webgl_simple_gi": [ "global illumination" ],
-	"webgl_tiled_forward": [ "derivatives" ],
 	"webgl2_multiple_rendertargets": [ "mrt" ],
 	"webgl2_multiple_rendertargets": [ "mrt" ],
 	"webgl2_multisampled_renderbuffers": [ "msaa" ],
 	"webgl2_multisampled_renderbuffers": [ "msaa" ],
 	"physics_ammo_cloth": [ "integration" ],
 	"physics_ammo_cloth": [ "integration" ],

+ 10 - 5
examples/webgl2_multiple_rendertargets.html

@@ -78,6 +78,10 @@
 			precision highp float;
 			precision highp float;
 			precision highp int;
 			precision highp int;
 
 
+			vec4 LinearTosRGB( in vec4 value ) {
+				return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );
+			}	
+
 			layout(location = 0) out vec4 pc_FragColor;
 			layout(location = 0) out vec4 pc_FragColor;
 
 
 			in vec2 vUv;
 			in vec2 vUv;
@@ -87,12 +91,14 @@
 
 
 			void main() {
 			void main() {
 
 
-				vec3 diffuse = texture( tDiffuse, vUv ).rgb;
-				vec3 normal = texture( tNormal, vUv ).rgb;
+				vec4 diffuse = texture( tDiffuse, vUv );
+				vec4 normal = texture( tNormal, vUv );
 
 
-				pc_FragColor.rgb = mix( diffuse, normal, step( 0.5, vUv.x ) );
+				pc_FragColor = mix( diffuse, normal, step( 0.5, vUv.x ) );
 				pc_FragColor.a = 1.0;
 				pc_FragColor.a = 1.0;
 
 
+				pc_FragColor = LinearTosRGB( pc_FragColor );
+
 			}
 			}
 		</script>
 		</script>
 
 
@@ -123,8 +129,6 @@
 			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
 			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 
-			THREE.ColorManagement.enabled = false; // TODO: Consider enabling color management.
-
 			let camera, scene, renderer, controls;
 			let camera, scene, renderer, controls;
 			let renderTarget;
 			let renderTarget;
 			let postScene, postCamera;
 			let postScene, postCamera;
@@ -188,6 +192,7 @@
 				const diffuse = loader.load( 'textures/hardwood2_diffuse.jpg', render );
 				const diffuse = loader.load( 'textures/hardwood2_diffuse.jpg', render );
 				diffuse.wrapS = THREE.RepeatWrapping;
 				diffuse.wrapS = THREE.RepeatWrapping;
 				diffuse.wrapT = THREE.RepeatWrapping;
 				diffuse.wrapT = THREE.RepeatWrapping;
+				diffuse.colorSpace = THREE.SRGBColorSpace;
 
 
 				scene.add( new THREE.Mesh(
 				scene.add( new THREE.Mesh(
 					new THREE.TorusKnotGeometry( 1, 0.3, 128, 32 ),
 					new THREE.TorusKnotGeometry( 1, 0.3, 128, 32 ),

+ 5 - 7
examples/webgl2_multisampled_renderbuffers.html

@@ -53,12 +53,10 @@
 			import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
 			import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
 			import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
 			import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
 			import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
 			import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js';
-			import { CopyShader } from 'three/addons/shaders/CopyShader.js';
+			import { GammaCorrectionShader } from 'three/addons/shaders/GammaCorrectionShader.js';
 			import WebGL from 'three/addons/capabilities/WebGL.js';
 			import WebGL from 'three/addons/capabilities/WebGL.js';
 			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
 
 
-			THREE.ColorManagement.enabled = false; // TODO: Consider enabling color management.
-
 			let camera, renderer, group, container;
 			let camera, renderer, group, container;
 
 
 			let composer1, composer2;
 			let composer1, composer2;
@@ -67,7 +65,7 @@
 
 
 				animate: true,
 				animate: true,
 
 
-			}
+			};
 
 
 			init();
 			init();
 
 
@@ -144,19 +142,19 @@
 				const renderTarget = new THREE.WebGLRenderTarget( size.width, size.height, { samples: 4 } );
 				const renderTarget = new THREE.WebGLRenderTarget( size.width, size.height, { samples: 4 } );
 
 
 				const renderPass = new RenderPass( scene, camera );
 				const renderPass = new RenderPass( scene, camera );
-				const copyPass = new ShaderPass( CopyShader );
+				const outputPass = new ShaderPass( GammaCorrectionShader );
 
 
 				//
 				//
 
 
 				composer1 = new EffectComposer( renderer );
 				composer1 = new EffectComposer( renderer );
 				composer1.addPass( renderPass );
 				composer1.addPass( renderPass );
-				composer1.addPass( copyPass );
+				composer1.addPass( outputPass );
 
 
 				//
 				//
 
 
 				composer2 = new EffectComposer( renderer, renderTarget );
 				composer2 = new EffectComposer( renderer, renderTarget );
 				composer2.addPass( renderPass );
 				composer2.addPass( renderPass );
-				composer2.addPass( copyPass );
+				composer2.addPass( outputPass );
 
 
 				//
 				//
 
 

+ 16 - 5
examples/webgl2_ubo.html

@@ -47,6 +47,10 @@
 
 
 			precision highp float;
 			precision highp float;
 
 
+			vec4 LinearTosRGB( in vec4 value ) {
+				return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );
+			}	
+
 			uniform LightingData {
 			uniform LightingData {
 				vec3 position;
 				vec3 position;
 				vec3 ambientColor;
 				vec3 ambientColor;
@@ -82,6 +86,8 @@
 
 
 				fragColor = vec4( color.rgb * lightWeighting.rgb, 1.0 );
 				fragColor = vec4( color.rgb * lightWeighting.rgb, 1.0 );
 
 
+				fragColor = LinearTosRGB( fragColor );
+
 			}
 			}
 
 
 		</script>
 		</script>
@@ -121,6 +127,10 @@
 
 
 			precision highp float;
 			precision highp float;
 
 
+			vec4 LinearTosRGB( in vec4 value ) {
+				return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );
+			}			
+
 			uniform sampler2D diffuseMap;
 			uniform sampler2D diffuseMap;
 
 
 			in vec2 vUv;
 			in vec2 vUv;
@@ -157,6 +167,8 @@
 
 
 				fragColor = vec4( texture( diffuseMap, vUv ).rgb * lightWeighting.rgb, 1.0 );
 				fragColor = vec4( texture( diffuseMap, vUv ).rgb * lightWeighting.rgb, 1.0 );
 
 
+				fragColor = LinearTosRGB( fragColor );
+
 			}
 			}
 
 
 		</script>
 		</script>
@@ -182,8 +194,6 @@
 
 
 			import WebGL from 'three/addons/capabilities/WebGL.js';
 			import WebGL from 'three/addons/capabilities/WebGL.js';
 
 
-			THREE.ColorManagement.enabled = false; // TODO: Consider enabling color management.
-
 			let camera, scene, renderer, clock;
 			let camera, scene, renderer, clock;
 
 
 			init();
 			init();
@@ -216,6 +226,7 @@
 				// texture
 				// texture
 
 
 				const texture = new THREE.TextureLoader().load( 'textures/crate.gif' );
 				const texture = new THREE.TextureLoader().load( 'textures/crate.gif' );
+				texture.colorSpace = THREE.SRGBColorSpace;
 
 
 				// uniforms groups
 				// uniforms groups
 
 
@@ -230,9 +241,9 @@
 				const lightingUniformsGroup = new THREE.UniformsGroup();
 				const lightingUniformsGroup = new THREE.UniformsGroup();
 				lightingUniformsGroup.setName( 'LightingData' );
 				lightingUniformsGroup.setName( 'LightingData' );
 				lightingUniformsGroup.add( new THREE.Uniform( new THREE.Vector3( 0, 0, 10 ) ) ); // light position
 				lightingUniformsGroup.add( new THREE.Uniform( new THREE.Vector3( 0, 0, 10 ) ) ); // light position
-				lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0x333333 ) ) ); // ambient color
-				lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0xaaaaaa ) ) ); // diffuse color
-				lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0xcccccc ) ) ); // specular color
+				lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0x7c7c7c ) ) ); // ambient color
+				lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0xd5d5d5 ) ) ); // diffuse color
+				lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0xe7e7e7 ) ) ); // specular color
 				lightingUniformsGroup.add( new THREE.Uniform( 64 ) ); // shininess
 				lightingUniformsGroup.add( new THREE.Uniform( 64 ) ); // shininess
 
 
 				// materials
 				// materials

+ 1 - 0
examples/webgl_effects_anaglyph.html

@@ -64,6 +64,7 @@
 				];
 				];
 
 
 				const textureCube = new THREE.CubeTextureLoader().load( urls );
 				const textureCube = new THREE.CubeTextureLoader().load( urls );
+				textureCube.colorSpace = THREE.SRGBColorSpace;
 
 
 				scene = new THREE.Scene();
 				scene = new THREE.Scene();
 				scene.background = textureCube;
 				scene.background = textureCube;

+ 1 - 0
examples/webgl_effects_parallaxbarrier.html

@@ -65,6 +65,7 @@
 				];
 				];
 
 
 				const textureCube = new THREE.CubeTextureLoader().load( urls );
 				const textureCube = new THREE.CubeTextureLoader().load( urls );
+				textureCube.colorSpace = THREE.SRGBColorSpace;
 
 
 				scene = new THREE.Scene();
 				scene = new THREE.Scene();
 				scene.background = textureCube;
 				scene.background = textureCube;

+ 0 - 2
examples/webgl_effects_peppersghost.html

@@ -32,8 +32,6 @@
 
 
 			import { PeppersGhostEffect } from 'three/addons/effects/PeppersGhostEffect.js';
 			import { PeppersGhostEffect } from 'three/addons/effects/PeppersGhostEffect.js';
 
 
-			THREE.ColorManagement.enabled = false; // TODO: Consider enabling color management.
-
 			let container;
 			let container;
 
 
 			let camera, scene, renderer, effect;
 			let camera, scene, renderer, effect;

+ 0 - 396
examples/webgl_tiled_forward.html

@@ -1,396 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
-		<title>three.js webgl - tiled forward lighting</title>
-		<meta charset="utf-8">
-		<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
-		<link type="text/css" rel="stylesheet" href="main.css">
-	</head>
-	<body>
-		<div id="info">
-			<a href="https://threejs.org" target="_blank" rel="noopener">threejs</a> - Tiled forward lighting<br/>
-			Created by <a href="https://github.com/wizgrav" target="_blank" rel="noopener">wizgrav</a>.
-		</div>
-
-		<!-- Import maps polyfill -->
-		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
-
-		<script type="importmap">
-			{
-				"imports": {
-					"three": "../build/three.module.js",
-					"three/addons/": "./jsm/"
-				}
-			}
-		</script>
-
-		<script type="module">
-
-			import * as THREE from 'three';
-
-			import Stats from 'three/addons/libs/stats.module.js';
-
-			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
-			import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
-
-			import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
-
-			THREE.ColorManagement.enabled = false; // TODO: Confirm correct color management.
-
-			// Simple form of tiled forward lighting
-			// using texels as bitmasks of 32 lights
-
-			const RADIUS = 75;
-
-			THREE.ShaderChunk[ 'lights_pars_begin' ] += [
-				'',
-				'#if defined TILED_FORWARD',
-				'uniform vec4 tileData;',
-				'uniform sampler2D tileTexture;',
-				'uniform sampler2D lightTexture;',
-				'#endif'
-			].join( '\n' );
-
-			THREE.ShaderChunk[ 'lights_fragment_end' ] += [
-				'',
-				'#if defined TILED_FORWARD',
-				'vec2 tUv = floor(gl_FragCoord.xy / tileData.xy * 32.) / 32. + tileData.zw;',
-				'vec4 tile = texture2D(tileTexture, tUv);',
-				'for (int i=0; i < 4; i++) {',
-				'	float tileVal = tile.x * 255.;',
-				'  	tile.xyzw = tile.yzwx;',
-				'	if(tileVal == 0.){ continue; }',
-				'  	float tileDiv = 128.;',
-				'	for (int j=0; j < 8; j++) {',
-				'  		if (tileVal < tileDiv) {  tileDiv *= 0.5; continue; }',
-				'		tileVal -= tileDiv;',
-				'		tileDiv *= 0.5;',
-				'  		PointLight pointlight;',
-				'		float uvx = (float(8 * i + j) + 0.5) / 32.;',
-				'  		vec4 lightData = texture2D(lightTexture, vec2(uvx, 0.));',
-				'  		vec4 lightColor = texture2D(lightTexture, vec2(uvx, 1.));',
-				'  		pointlight.position = lightData.xyz;',
-				'  		pointlight.distance = lightData.w;',
-				'  		pointlight.color = lightColor.rgb;',
-				'  		pointlight.decay = lightColor.a;',
-				'  		getPointLightInfo( pointlight, geometry, directLight );',
-				'		RE_Direct( directLight, geometry, material, reflectedLight );',
-				'	}',
-				'}',
-				'#endif'
-			].join( '\n' );
-
-			const lights = [];
-
-			const State = {
-				rows: 0,
-				cols: 0,
-				width: 0,
-				height: 0,
-				tileData: { value: null },
-				tileTexture: { value: null },
-				lightTexture: {
-					value: new THREE.DataTexture( new Float32Array( 32 * 2 * 4 ), 32, 2, THREE.RGBAFormat, THREE.FloatType )
-				},
-			};
-
-			function resizeTiles() {
-
-				const width = window.innerWidth;
-				const height = window.innerHeight;
-
-				State.width = width;
-				State.height = height;
-				State.cols = Math.ceil( width / 32 );
-				State.rows = Math.ceil( height / 32 );
-				State.tileData.value = [ width, height, 0.5 / Math.ceil( width / 32 ), 0.5 / Math.ceil( height / 32 ) ];
-				State.tileTexture.value = new THREE.DataTexture( new Uint8Array( State.cols * State.rows * 4 ), State.cols, State.rows );
-
-			}
-
-			// Generate the light bitmasks and store them in the tile texture
-			function tileLights( renderer, scene, camera ) {
-
-				if ( ! camera.projectionMatrix ) return;
-
-				const d = State.tileTexture.value.image.data;
-				const ld = State.lightTexture.value.image.data;
-
-				const viewMatrix = camera.matrixWorldInverse;
-
-				d.fill( 0 );
-
-				const vector = new THREE.Vector3();
-
-				lights.forEach( function ( light, index ) {
-
-					vector.setFromMatrixPosition( light.matrixWorld );
-
-					const bs = lightBounds( camera, vector, light._light.radius );
-
-					vector.applyMatrix4( viewMatrix );
-					vector.toArray( ld, 4 * index );
-					ld[ 4 * index + 3 ] = light._light.radius;
-					light._light.color.toArray( ld, 32 * 4 + 4 * index );
-					ld[ 32 * 4 + 4 * index + 3 ] = light._light.decay;
-
-					if ( bs[ 1 ] < 0 || bs[ 0 ] > State.width || bs[ 3 ] < 0 || bs[ 2 ] > State.height ) return;
-					if ( bs[ 0 ] < 0 ) bs[ 0 ] = 0;
-					if ( bs[ 1 ] > State.width ) bs[ 1 ] = State.width;
-					if ( bs[ 2 ] < 0 ) bs[ 2 ] = 0;
-					if ( bs[ 3 ] > State.height ) bs[ 3 ] = State.height;
-
-					const i4 = Math.floor( index / 8 ), i8 = 7 - ( index % 8 );
-
-					for ( let i = Math.floor( bs[ 2 ] / 32 ); i <= Math.ceil( bs[ 3 ] / 32 ); i ++ ) {
-
-						for ( let j = Math.floor( bs[ 0 ] / 32 ); j <= Math.ceil( bs[ 1 ] / 32 ); j ++ ) {
-
-							d[ ( State.cols * i + j ) * 4 + i4 ] |= 1 << i8;
-
-						}
-
-					}
-
-				} );
-
-				State.tileTexture.value.needsUpdate = true;
-				State.lightTexture.value.needsUpdate = true;
-
-			}
-
-			// Screen rectangle bounds from light sphere's world AABB
-			const lightBounds = function () {
-
-				const v = new THREE.Vector3();
-				return function ( camera, pos, r ) {
-
-					let minX = State.width, maxX = 0, minY = State.height, maxY = 0;
-					const hw = State.width / 2, hh = State.height / 2;
-
-					for ( let i = 0; i < 8; i ++ ) {
-
-						v.copy( pos );
-						v.x += i & 1 ? r : - r;
-						v.y += i & 2 ? r : - r;
-						v.z += i & 4 ? r : - r;
-						const vector = v.project( camera );
-						const x = ( vector.x * hw ) + hw;
-						const y = ( vector.y * hh ) + hh;
-						minX = Math.min( minX, x );
-						maxX = Math.max( maxX, x );
-						minY = Math.min( minY, y );
-						maxY = Math.max( maxY, y );
-
-					}
-
-					return [ minX, maxX, minY, maxY ];
-
-				};
-
-			}();
-
-
-			// Rendering
-
-			const container = document.createElement( 'div' );
-			document.body.appendChild( container );
-			const camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 );
-			camera.position.set( 0.0, 0.0, 240.0 );
-			const scene = new THREE.Scene();
-			scene.background = new THREE.Color( 0x111111 );
-
-			const renderer = new THREE.WebGLRenderer();
-			renderer.outputColorSpace = THREE.LinearSRGBColorSpace;
-			renderer.toneMapping = THREE.NoToneMapping;
-			container.appendChild( renderer.domElement );
-
-			const renderTarget = new THREE.WebGLRenderTarget();
-
-			scene.add( new THREE.AmbientLight( 0xffffff, 0.33 ) );
-			// At least one regular Pointlight is needed to activate light support
-			scene.add( new THREE.PointLight( 0xff0000, 0.1, 0.1 ) );
-
-			const bloom = new UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), 0.8, 0.6, 0.8 );
-			bloom.renderToScreen = true;
-
-			const stats = new Stats();
-			container.appendChild( stats.dom );
-
-			const controls = new OrbitControls( camera, renderer.domElement );
-			controls.minDistance = 120;
-			controls.maxDistance = 320;
-
-			const materials = [];
-
-			const Heads = [
-				{ type: 'physical', uniforms: { 'diffuse': 0x888888, 'metalness': 1.0, 'roughness': 0.66 }, defines: {} },
-				{ type: 'standard', uniforms: { 'diffuse': 0x666666, 'metalness': 0.1, 'roughness': 0.33 }, defines: {} },
-				{ type: 'phong', uniforms: { 'diffuse': 0x777777, 'shininess': 20 }, defines: {} },
-				{ type: 'phong', uniforms: { 'diffuse': 0x555555, 'shininess': 10 }, defines: { TOON: 1 } }
-			];
-
-			function init( geom ) {
-
-				const sphereGeom = new THREE.SphereGeometry( 0.5, 32, 32 );
-				const tIndex = Math.round( Math.random() * 3 );
-
-				Object.keys( Heads ).forEach( function ( t, index ) {
-
-					const g = new THREE.Group();
-					const conf = Heads[ t ];
-					const ml = THREE.ShaderLib[ conf.type ];
-					const mtl = new THREE.ShaderMaterial( {
-						lights: true,
-						fragmentShader: ml.fragmentShader,
-						vertexShader: ml.vertexShader,
-						uniforms: THREE.UniformsUtils.clone( ml.uniforms ),
-						defines: conf.defines,
-						transparent: tIndex === index ? true : false,
-					} );
-
-					mtl.extensions.derivatives = true;
-
-					mtl.uniforms[ 'opacity' ].value = tIndex === index ? 0.9 : 1;
-					mtl.uniforms[ 'tileData' ] = State.tileData;
-					mtl.uniforms[ 'tileTexture' ] = State.tileTexture;
-					mtl.uniforms[ 'lightTexture' ] = State.lightTexture;
-
-					for ( const u in conf.uniforms ) {
-
-						const vu = conf.uniforms[ u ];
-
-						if ( mtl.uniforms[ u ].value.set ) {
-
-							mtl.uniforms[ u ].value.set( vu );
-
-						} else {
-
-							mtl.uniforms[ u ].value = vu;
-
-						}
-
-					}
-
-					mtl.defines[ 'TILED_FORWARD' ] = 1;
-					materials.push( mtl );
-
-					const obj = new THREE.Mesh( geom, mtl );
-					obj.position.y = - 37;
-					mtl.side = tIndex === index ? THREE.FrontSide : THREE.DoubleSide;
-
-					g.rotation.y = index * Math.PI / 2;
-					g.position.x = Math.sin( index * Math.PI / 2 ) * RADIUS;
-					g.position.z = Math.cos( index * Math.PI / 2 ) * RADIUS;
-					g.add( obj );
-
-					for ( let i = 0; i < 8; i ++ ) {
-
-						const color = new THREE.Color().setHSL( Math.random(), 1.0, 0.5 );
-						const l = new THREE.Group();
-
-						l.add( new THREE.Mesh(
-							sphereGeom,
-							new THREE.MeshBasicMaterial( {
-								color: color
-							} )
-						) );
-
-						l.add( new THREE.Mesh(
-							sphereGeom,
-							new THREE.MeshBasicMaterial( {
-								color: color,
-								transparent: true,
-								opacity: 0.033
-							} )
-						) );
-
-						l.children[ 1 ].scale.set( 6.66, 6.66, 6.66 );
-
-						l._light = {
-							color: color,
-							radius: RADIUS,
-							decay: 1,
-							sy: Math.random(),
-							sr: Math.random(),
-							sc: Math.random(),
-							py: Math.random() * Math.PI,
-							pr: Math.random() * Math.PI,
-							pc: Math.random() * Math.PI,
-							dir: Math.random() > 0.5 ? 1 : - 1
-						};
-
-						lights.push( l );
-						g.add( l );
-
-					}
-
-					scene.add( g );
-
-				} );
-
-			}
-
-			function update( now ) {
-
-				lights.forEach( function ( l ) {
-
-					const ld = l._light;
-					const radius = 0.8 + 0.2 * Math.sin( ld.pr + ( 0.6 + 0.3 * ld.sr ) * now );
-					l.position.x = ( Math.sin( ld.pc + ( 0.8 + 0.2 * ld.sc ) * now * ld.dir ) ) * radius * RADIUS;
-					l.position.z = ( Math.cos( ld.pc + ( 0.8 + 0.2 * ld.sc ) * now * ld.dir ) ) * radius * RADIUS;
-					l.position.y = Math.sin( ld.py + ( 0.8 + 0.2 * ld.sy ) * now ) * radius * 32;
-
-				} );
-
-			}
-
-			function onWindowResize() {
-
-				renderer.setPixelRatio( window.devicePixelRatio );
-				renderer.setSize( window.innerWidth, window.innerHeight );
-				renderTarget.setSize( window.innerWidth, window.innerHeight );
-				bloom.setSize( window.innerWidth, window.innerHeight );
-				camera.aspect = window.innerWidth / window.innerHeight;
-				camera.updateProjectionMatrix();
-				resizeTiles();
-
-			}
-
-			function postEffect( renderer ) {
-
-				bloom.render( renderer, null, renderTarget );
-
-			}
-
-			scene.onBeforeRender = tileLights;
-
-			scene.onAfterRender = postEffect;
-
-			const loader = new OBJLoader();
-
-			loader.load( 'models/obj/walt/WaltHead.obj', function ( object ) {
-
-				const geometry = object.children[ 0 ].geometry;
-
-				window.addEventListener( 'resize', onWindowResize );
-
-				init( geometry );
-				onWindowResize();
-
-				renderer.setAnimationLoop( function ( time ) {
-
-					update( time / 1000 );
-					stats.begin();
-					renderer.setRenderTarget( renderTarget );
-					renderer.render( scene, camera );
-					stats.end();
-
-				} );
-
-			} );
-
-		</script>
-	</body>
-</html>