Browse Source

Merge branch 'dev' into patch-3

Conflicts:
	src/renderers/shaders/ShaderChunk.js
Ted Cipicchio 11 years ago
parent
commit
c18368973e
88 changed files with 3930 additions and 2849 deletions
  1. 320 312
      build/three.js
  2. 226 229
      build/three.min.js
  3. 3 5
      editor/js/Menubar.Edit.js
  4. 1 2
      editor/js/Sidebar.Geometry.BoxGeometry.js
  5. 1 3
      editor/js/Sidebar.Geometry.CircleGeometry.js
  6. 1 2
      editor/js/Sidebar.Geometry.CylinderGeometry.js
  7. 1 2
      editor/js/Sidebar.Geometry.IcosahedronGeometry.js
  8. 2 3
      editor/js/Sidebar.Geometry.PlaneGeometry.js
  9. 1 2
      editor/js/Sidebar.Geometry.SphereGeometry.js
  10. 1 2
      editor/js/Sidebar.Geometry.TorusGeometry.js
  11. 1 2
      editor/js/Sidebar.Geometry.TorusKnotGeometry.js
  12. 0 1
      editor/js/Sidebar.Geometry.js
  13. 2 2
      examples/js/UCSCharacter.js
  14. 1 1
      examples/js/libs/dat.gui.min.js
  15. 4 2
      examples/js/loaders/OBJLoader.js
  16. 3 2
      examples/webgl_loader_collada_keyframe.html
  17. 0 2
      examples/webgl_loader_scene.html
  18. 0 4
      examples/webgl_materials_cubemap_dynamic.html
  19. 220 0
      examples/webgl_objects_update.html
  20. 0 5
      examples/webgl_shading_physical.html
  21. 0 6
      examples/webgl_terrain_dynamic.html
  22. 10 15
      src/core/Geometry.js
  23. 14 0
      src/core/Object3D.js
  24. 58 73
      src/core/Projector.js
  25. 56 51
      src/extras/renderers/plugins/DepthPassPlugin.js
  26. 18 11
      src/extras/renderers/plugins/LensFlarePlugin.js
  27. 61 56
      src/extras/renderers/plugins/ShadowMapPlugin.js
  28. 23 19
      src/extras/renderers/plugins/SpritePlugin.js
  29. 2 0
      src/renderers/CanvasRenderer.js
  30. 257 268
      src/renderers/WebGLRenderer.js
  31. 1 1756
      src/renderers/shaders/ShaderChunk.js
  32. 5 0
      src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl
  33. 5 0
      src/renderers/shaders/ShaderChunk/alphamap_pars_fragment.glsl
  34. 5 0
      src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl
  35. 40 0
      src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl
  36. 5 0
      src/renderers/shaders/ShaderChunk/color_fragment.glsl
  37. 5 0
      src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl
  38. 5 0
      src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl
  39. 13 0
      src/renderers/shaders/ShaderChunk/color_vertex.glsl
  40. 21 0
      src/renderers/shaders/ShaderChunk/default_vertex.glsl
  41. 27 0
      src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl
  42. 61 0
      src/renderers/shaders/ShaderChunk/envmap_fragment.glsl
  43. 19 0
      src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl
  44. 8 0
      src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl
  45. 18 0
      src/renderers/shaders/ShaderChunk/envmap_vertex.glsl
  46. 27 0
      src/renderers/shaders/ShaderChunk/fog_fragment.glsl
  47. 15 0
      src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl
  48. 5 0
      src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl
  49. 6 0
      src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl
  50. 5 0
      src/renderers/shaders/ShaderChunk/lightmap_pars_vertex.glsl
  51. 5 0
      src/renderers/shaders/ShaderChunk/lightmap_vertex.glsl
  52. 45 0
      src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl
  53. 202 0
      src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl
  54. 278 0
      src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl
  55. 52 0
      src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl
  56. 5 0
      src/renderers/shaders/ShaderChunk/lights_phong_pars_vertex.glsl
  57. 5 0
      src/renderers/shaders/ShaderChunk/lights_phong_vertex.glsl
  58. 5 0
      src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl
  59. 5 0
      src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl
  60. 12 0
      src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl
  61. 11 0
      src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl
  62. 15 0
      src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl
  63. 13 0
      src/renderers/shaders/ShaderChunk/map_fragment.glsl
  64. 11 0
      src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl
  65. 6 0
      src/renderers/shaders/ShaderChunk/map_pars_vertex.glsl
  66. 5 0
      src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl
  67. 5 0
      src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl
  68. 5 0
      src/renderers/shaders/ShaderChunk/map_vertex.glsl
  69. 12 0
      src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl
  70. 13 0
      src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl
  71. 20 0
      src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl
  72. 27 0
      src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl
  73. 220 0
      src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl
  74. 19 0
      src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl
  75. 6 0
      src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl
  76. 9 0
      src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl
  77. 8 0
      src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl
  78. 44 0
      src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl
  79. 19 0
      src/renderers/shaders/ShaderChunk/skinning_vertex.glsl
  80. 19 0
      src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl
  81. 12 0
      src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl
  82. 5 0
      src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl
  83. 21 0
      src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl
  84. 1 4
      utils/build/build.js
  85. 9 7
      utils/build/build.py
  86. 50 0
      utils/build/includes/common.json
  87. 51 0
      utils/build/includes/webgl.json
  88. 1097 0
      utils/exporters/max/ThreeJSExporter_MorphTargets_v0.ms

File diff suppressed because it is too large
+ 320 - 312
build/three.js


File diff suppressed because it is too large
+ 226 - 229
build/three.min.js


+ 3 - 5
editor/js/Menubar.Edit.js

@@ -47,8 +47,6 @@ Menubar.Edit = function ( editor ) {
 
 			if ( confirm( 'Convert ' + object.name + ' to BufferGeometry?' ) === false ) return;
 
-			delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
-
 			object.geometry = new THREE.BufferGeometry().fromGeometry( object.geometry );
 
 			editor.signals.objectChanged.dispatch( object );
@@ -65,17 +63,17 @@ Menubar.Edit = function ( editor ) {
 
 		if ( confirm( 'Flatten ' + object.name + '?' ) === false ) return;
 
-		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
-
 		var geometry = object.geometry.clone();
 		geometry.applyMatrix( object.matrix );
 
+
 		object.geometry = geometry;
 
 		object.position.set( 0, 0, 0 );
 		object.rotation.set( 0, 0, 0 );
 		object.scale.set( 1, 1, 1 );
-
+		
+		object.geometry.buffersNeedUpdate = true;
 		editor.signals.objectChanged.dispatch( object );
 
 	}

+ 1 - 2
editor/js/Sidebar.Geometry.BoxGeometry.js

@@ -68,8 +68,6 @@ Sidebar.Geometry.BoxGeometry = function ( signals, object ) {
 
 	function update() {
 
-		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
-
 		object.geometry.dispose();
 
 		object.geometry = new THREE.BoxGeometry(
@@ -81,6 +79,7 @@ Sidebar.Geometry.BoxGeometry = function ( signals, object ) {
 			depthSegments.getValue()
 		);
 
+		object.geometry.buffersNeedUpdate = true;
 		object.geometry.computeBoundingSphere();
 
 		signals.objectChanged.dispatch( object );

+ 1 - 3
editor/js/Sidebar.Geometry.CircleGeometry.js

@@ -28,15 +28,13 @@ Sidebar.Geometry.CircleGeometry = function ( signals, object ) {
 
 	function update() {
 
-		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
-
 		object.geometry.dispose();
 
 		object.geometry = new THREE.CircleGeometry(
 			radius.getValue(),
 			segments.getValue()
 		);
-
+		object.geometry.buffersNeedUpdate = true;
 		object.geometry.computeBoundingSphere();
 
 		signals.objectChanged.dispatch( object );

+ 1 - 2
editor/js/Sidebar.Geometry.CylinderGeometry.js

@@ -68,8 +68,6 @@ Sidebar.Geometry.CylinderGeometry = function ( signals, object ) {
 
 	function update() {
 
-		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
-
 		object.geometry.dispose();
 
 		object.geometry = new THREE.CylinderGeometry(
@@ -81,6 +79,7 @@ Sidebar.Geometry.CylinderGeometry = function ( signals, object ) {
 			openEnded.getValue()
 		);
 
+		object.geometry.buffersNeedUpdate = true;
 		object.geometry.computeBoundingSphere();
 
 		signals.objectChanged.dispatch( object );

+ 1 - 2
editor/js/Sidebar.Geometry.IcosahedronGeometry.js

@@ -29,8 +29,6 @@ Sidebar.Geometry.IcosahedronGeometry = function ( signals, object ) {
 
 	function update() {
 
-		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
-
 		object.geometry.dispose();
 
 		object.geometry = new THREE.IcosahedronGeometry(
@@ -38,6 +36,7 @@ Sidebar.Geometry.IcosahedronGeometry = function ( signals, object ) {
 			detail.getValue()
 		);
 
+		object.geometry.buffersNeedUpdate = true;
 		object.geometry.computeBoundingSphere();
 
 		signals.objectChanged.dispatch( object );

+ 2 - 3
editor/js/Sidebar.Geometry.PlaneGeometry.js

@@ -48,9 +48,7 @@ Sidebar.Geometry.PlaneGeometry = function ( signals, object ) {
 	//
 
 	function update() {
-
-		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
-
+		
 		object.geometry.dispose();
 
 		object.geometry = new THREE.PlaneGeometry(
@@ -60,6 +58,7 @@ Sidebar.Geometry.PlaneGeometry = function ( signals, object ) {
 			heightSegments.getValue()
 		);
 
+		object.geometry.buffersNeedUpdate = true;
 		object.geometry.computeBoundingSphere();
 
 		signals.objectChanged.dispatch( object );

+ 1 - 2
editor/js/Sidebar.Geometry.SphereGeometry.js

@@ -79,8 +79,6 @@ Sidebar.Geometry.SphereGeometry = function ( signals, object ) {
 
 	function update() {
 
-		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
-
 		object.geometry.dispose();
 
 		object.geometry = new THREE.SphereGeometry(
@@ -93,6 +91,7 @@ Sidebar.Geometry.SphereGeometry = function ( signals, object ) {
 			thetaLength.getValue()
 		);
 
+		object.geometry.buffersNeedUpdate = true;
 		object.geometry.computeBoundingSphere();
 
 		signals.objectChanged.dispatch( object );

+ 1 - 2
editor/js/Sidebar.Geometry.TorusGeometry.js

@@ -59,8 +59,6 @@ Sidebar.Geometry.TorusGeometry = function ( signals, object ) {
 
 	function update() {
 
-		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
-
 		object.geometry.dispose();
 
 		object.geometry = new THREE.TorusGeometry(
@@ -71,6 +69,7 @@ Sidebar.Geometry.TorusGeometry = function ( signals, object ) {
 			arc.getValue()
 		);
 
+		object.geometry.buffersNeedUpdate = true;
 		object.geometry.computeBoundingSphere();
 
 		signals.objectChanged.dispatch( object );

+ 1 - 2
editor/js/Sidebar.Geometry.TorusKnotGeometry.js

@@ -79,8 +79,6 @@ Sidebar.Geometry.TorusKnotGeometry = function ( signals, object ) {
 
 	function update() {
 
-		delete object.__webglInit; // TODO: Remove hack (WebGLRenderer refactoring)
-
 		object.geometry.dispose();
 
 		object.geometry = new THREE.TorusKnotGeometry(
@@ -93,6 +91,7 @@ Sidebar.Geometry.TorusKnotGeometry = function ( signals, object ) {
 			heightScale.getValue()
 		);
 
+		object.geometry.buffersNeedUpdate = true;
 		object.geometry.computeBoundingSphere();
 
 		signals.objectChanged.dispatch( object );

+ 0 - 1
editor/js/Sidebar.Geometry.js

@@ -91,7 +91,6 @@ Sidebar.Geometry = function ( editor ) {
 
 			updateFields( geometry );
 
-			//
 
 			if ( parameters !== undefined ) {
 

+ 2 - 2
examples/js/UCSCharacter.js

@@ -41,7 +41,7 @@ THREE.UCSCharacter = function() {
 			geometry.computeBoundingBox();
 			geometry.computeVertexNormals();
 
-			THREE.AnimationHandler.add( geometry.animation );
+			//THREE.AnimationHandler.add( geometry.animation );
 
 			mesh = new THREE.SkinnedMesh( geometry, new THREE.MeshFaceMaterial() );
 			scope.root.add( mesh );
@@ -53,7 +53,7 @@ THREE.UCSCharacter = function() {
 			mesh.castShadow = true;
 			mesh.receiveShadow = true;
 
-			animation = new THREE.Animation( mesh, geometry.animation.name );
+			animation = new THREE.Animation( mesh, geometry.animation );
 			animation.play();
 			
 			scope.setSkin(0);

+ 1 - 1
examples/js/libs/dat.gui.min.js

@@ -87,7 +87,7 @@ b,c){Object.defineProperty(a,b,{get:function(){if(this.__state.space==="RGB")ret
 "HEX")b.__state[c]=a.component_from_hex(b.__state.hex,e);else if(b.__state.space==="HSV")d.extend(b.__state,a.hsv_to_rgb(b.__state.h,b.__state.s,b.__state.v));else throw"Corrupted color state";}function h(b){var c=a.rgb_to_hsv(b.r,b.g,b.b);d.extend(b.__state,{s:c.s,v:c.v});if(d.isNaN(c.h)){if(d.isUndefined(b.__state.h))b.__state.h=0}else b.__state.h=c.h}var j=function(){this.__state=e.apply(this,arguments);if(this.__state===false)throw"Failed to interpret color arguments";this.__state.a=this.__state.a||
 1};j.COMPONENTS="r,g,b,h,s,v,hex,a".split(",");d.extend(j.prototype,{toString:function(){return c(this)},toOriginal:function(){return this.__state.conversion.write(this)}});f(j.prototype,"r",2);f(j.prototype,"g",1);f(j.prototype,"b",0);b(j.prototype,"h");b(j.prototype,"s");b(j.prototype,"v");Object.defineProperty(j.prototype,"a",{get:function(){return this.__state.a},set:function(a){this.__state.a=a}});Object.defineProperty(j.prototype,"hex",{get:function(){if(!this.__state.space!=="HEX")this.__state.hex=
 a.rgb_to_hex(this.r,this.g,this.b);return this.__state.hex},set:function(a){this.__state.space="HEX";this.__state.hex=a}});return j}(dat.color.interpret,dat.color.math=function(){var e;return{hsv_to_rgb:function(a,c,d){var e=a/60-Math.floor(a/60),b=d*(1-c),n=d*(1-e*c),c=d*(1-(1-e)*c),a=[[d,c,b],[n,d,b],[b,d,c],[b,n,d],[c,b,d],[d,b,n]][Math.floor(a/60)%6];return{r:a[0]*255,g:a[1]*255,b:a[2]*255}},rgb_to_hsv:function(a,c,d){var e=Math.min(a,c,d),b=Math.max(a,c,d),e=b-e;if(b==0)return{h:NaN,s:0,v:0};
-a=a==b?(c-d)/e:c==b?2+(d-a)/e:4+(a-c)/e;a/=6;a<0&&(a+=1);return{h:a*360,s:e/b,v:b/255}},rgb_to_hex:function(a,c,d){a=this.hex_with_component(0,2,a);a=this.hex_with_component(a,1,c);return a=this.hex_with_component(a,0,d)},component_from_hex:function(a,c){return a>>c*8&255},hex_with_component:function(a,c,d){return d<<(e=c*8)|a&~(255<<e)}}}(),dat.color.toString,dat.utils.common),dat.color.interpret,dat.utils.common),dat.utils.requestAnimationFrame=function(){return window.webkitRequestAnimationFrame||
+a=a==b?(c-d)/e:c==b?2+(d-a)/e:4+(a-c)/e;a/=6;a<0&&(a+=1);return{h:a*360,s:e/b,v:b/255}},rgb_to_hex:function(a,c,d){a=this.hex_with_component(0,2,a);a=this.hex_with_component(a,1,c);return a=this.hex_with_component(a,0,d)},component_from_hex:function(a,c){return a>>c*8&255},hex_with_component:function(a,c,d){return d<<(e=c*8)|a&~(255<<e)}}}(),dat.color.toString,dat.utils.common),dat.color.interpret,dat.utils.common),dat.utils.requestAnimationFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||
 window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout(e,1E3/60)}}(),dat.dom.CenteredDiv=function(e,a){var c=function(){this.backgroundElement=document.createElement("div");a.extend(this.backgroundElement.style,{backgroundColor:"rgba(0,0,0,0.8)",top:0,left:0,display:"none",zIndex:"1000",opacity:0,WebkitTransition:"opacity 0.2s linear"});e.makeFullscreen(this.backgroundElement);this.backgroundElement.style.position="fixed";this.domElement=
 document.createElement("div");a.extend(this.domElement.style,{position:"fixed",display:"none",zIndex:"1001",opacity:0,WebkitTransition:"-webkit-transform 0.2s ease-out, opacity 0.2s linear"});document.body.appendChild(this.backgroundElement);document.body.appendChild(this.domElement);var c=this;e.bind(this.backgroundElement,"click",function(){c.hide()})};c.prototype.show=function(){var c=this;this.backgroundElement.style.display="block";this.domElement.style.display="block";this.domElement.style.opacity=
 0;this.domElement.style.webkitTransform="scale(1.1)";this.layout();a.defer(function(){c.backgroundElement.style.opacity=1;c.domElement.style.opacity=1;c.domElement.style.webkitTransform="scale(1)"})};c.prototype.hide=function(){var a=this,c=function(){a.domElement.style.display="none";a.backgroundElement.style.display="none";e.unbind(a.domElement,"webkitTransitionEnd",c);e.unbind(a.domElement,"transitionend",c);e.unbind(a.domElement,"oTransitionEnd",c)};e.bind(this.domElement,"webkitTransitionEnd",

+ 4 - 2
examples/js/loaders/OBJLoader.js

@@ -190,7 +190,9 @@ THREE.OBJLoader.prototype = {
 
 		var face_pattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))?/
 
-		//
+		// fixes
+
+		text = text.replace( /\\\r\n/g, '' ); // handles line continuations \
 
 		var lines = text.split( '\n' );
 
@@ -324,4 +326,4 @@ THREE.OBJLoader.prototype = {
 
 	}
 
-};
+};

+ 3 - 2
examples/webgl_loader_collada_keyframe.html

@@ -47,6 +47,7 @@
 
 			var stats;
 			var scene;
+			var pointLight;
 			var camera;
 			var renderer;
 			var model;
@@ -126,8 +127,6 @@
 				// Lights
 
 				pointLight = new THREE.PointLight( 0xffffff, 1.75 );
-				pointLight.position = camera.position;
-
 				scene.add( pointLight );
 
 				// Renderer
@@ -224,6 +223,8 @@
 
 				}
 
+				pointLight.position.copy( camera.position );
+
 				progress += frameTime;
 				lastTimestamp = timestamp;
 				renderer.render( scene, camera );

+ 0 - 2
examples/webgl_loader_scene.html

@@ -162,8 +162,6 @@
 
 			function handle_update( result, pieces ) {
 
-				//renderer.initWebGLObjects( result.scene );
-
 				var m, material, count = 0;
 
 				for ( m in result.materials ) {

+ 0 - 4
examples/webgl_materials_cubemap_dynamic.html

@@ -964,9 +964,6 @@
 
 					cubeCamera.position.copy( currentCar.root.position );
 
-					renderer.autoUpdateObjects = false;
-					renderer.initWebGLObjects( scene );
-
 					renderer.autoClear = true;
 					cubeCamera.updateCubeMap( renderer, scene );
 
@@ -979,7 +976,6 @@
 
 				renderer.autoClear = false;
 				renderer.shadowMapEnabled = true;
-				renderer.autoUpdateObjects = true;
 
 				camera.lookAt( cameraTarget );
 

+ 220 - 0
examples/webgl_objects_update.html

@@ -0,0 +1,220 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - geometries</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 {
+				font-family: Monospace;
+				background-color: #000;
+				margin: 0px;
+				overflow: hidden;
+			}
+		</style>
+	</head>
+	<body>
+
+		<script src="../build/three.min.js"></script>
+
+		<script src="js/Detector.js"></script>
+		<script src="js/libs/stats.min.js"></script>
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var container, stats;
+
+			var camera, scene, renderer;
+			
+			var objectNewGeometry;
+			var objectToggleAddRemove;
+			var objectRandomizeFaces;
+
+			init();
+			animate();
+
+			function init() {
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
+				camera.position.y = 1500;
+
+				scene = new THREE.Scene();
+
+				var light, object;
+
+				scene.add( new THREE.AmbientLight( 0x404040 ) );
+
+				light = new THREE.DirectionalLight( 0xffffff );
+				light.position.set( 0, 1, 0 );
+				scene.add( light );
+
+				var map = THREE.ImageUtils.loadTexture( 'textures/UV_Grid_Sm.jpg' );
+				map.wrapS = map.wrapT = THREE.RepeatWrapping;
+				map.anisotropy = 16;
+
+				//var material = new THREE.MeshLambertMaterial( { ambient: 0xbbbbbb, map: map, side: THREE.DoubleSide } );
+
+				//
+
+				object = createObject( createMeshFaceMaterial(), 4 );
+				object.position.set( -400, 0, 200 );
+				scene.add( object );
+				objectNewGeometry = object
+
+				object = createObject( createMeshFaceMaterial(), 4 );
+				object.position.set( -200, 0, 200 );
+				scene.add( object );
+				objectToggleAddRemove = object 
+
+				object = createObject( createMeshFaceMaterial(), 4 );
+				object.position.set( 0, 0, 200 );
+				scene.add( object );
+				objectRandomizeFaces = object
+/*
+				These are not yet used but they are ready to be shown
+				object = createObject( createMeshFaceMaterial(), 4 );
+				object.position.set( 200, 0, 200 );
+				scene.add( object );
+
+				//
+
+				object = createObject( createMeshFaceMaterial(), 4 );
+				object.position.set( -400, 0, 0 );
+				scene.add( object );
+
+				object = createObject( createMeshFaceMaterial(), 4 );
+				object.position.set( -200, 0, 0 );
+				scene.add( object );
+
+				object = createObject( createMeshFaceMaterial(), 4 );
+				object.position.set( 0, 0, 0 );
+				scene.add( object );
+
+				object = createObject( createMeshFaceMaterial(), 4 );
+				object.position.set( 200, 0, 0 );
+				scene.add( object );
+
+				object = createObject( createMeshFaceMaterial(), 4 );
+				object.position.set( 400, 0, 0 );
+				scene.add( object );
+				*/
+				//
+
+				//
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				container.appendChild( renderer.domElement );
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild( stats.domElement );
+
+				//
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+			
+			function createObject(material, segments ){
+				var geometry = createGeometry(segments);
+				var mesh = new THREE.Mesh( geometry , material);
+				return mesh;
+			}
+			function createGeometry(segments){
+				var matrix = new THREE.Matrix4();
+				var euler = new THREE.Euler()
+				var geometry = new THREE.BoxGeometry( 100, 100, 100, segments, segments, segments );
+				geometry.applyMatrix(matrix.makeRotationFromEuler(euler.set(parseInt(Math.random()*2,10)*Math.PI,parseInt(Math.random()*2,10)*Math.PI,parseInt(Math.random()*2,10)*Math.PI)))
+				return geometry;
+			}
+			
+			function createMeshFaceMaterial(){
+				var materials = [];
+				materials.push(new THREE.MeshBasicMaterial({color: 0xff0000}))
+				materials.push(new THREE.MeshBasicMaterial({color: 0xffff00}))
+				materials.push(new THREE.MeshBasicMaterial({color: 0x00ff00}))
+				materials.push(new THREE.MeshBasicMaterial({color: 0x00ffff}))
+				materials.push(new THREE.MeshBasicMaterial({color: 0x0000ff}))
+				materials.push(new THREE.MeshBasicMaterial({color: 0xff00ff}))
+				var material = new THREE.MeshFaceMaterial(materials);
+				return material;
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+				stats.update();
+
+			}
+			
+			function randomizeFaces(object){
+				for(var i = 0,l=object.geometry.faces.length;i<l;i++){
+					
+					object.geometry.faces[i].materialIndex = Math.floor(Math.random() * 6);
+					
+				}
+				object.geometry.groupsNeedUpdate = true;
+			};
+
+			function render() {
+
+				var timer = Date.now() * 0.001;
+				
+				if (parseInt(timer,10)%2 === 0){
+
+					if (scene.children.indexOf(objectToggleAddRemove) === -1) {
+						
+					
+						objectNewGeometry.geometry = createGeometry(1);
+						objectNewGeometry.geometry.buffersNeedUpdate = true;
+						randomizeFaces(objectRandomizeFaces);
+					
+						scene.add(objectToggleAddRemove);
+						
+					};
+					
+				} else {
+					
+					if (scene.children.indexOf(objectToggleAddRemove) !== -1) {
+											
+						objectNewGeometry.geometry = createGeometry(1);
+						objectNewGeometry.geometry.buffersNeedUpdate = true;
+						randomizeFaces(objectRandomizeFaces);
+					
+						scene.remove(objectToggleAddRemove);
+						
+					};
+					
+				};
+
+				camera.lookAt( scene.position );
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 0 - 5
examples/webgl_shading_physical.html

@@ -565,9 +565,6 @@
 
 				// render shadow map
 
-				renderer.autoUpdateObjects = false;
-
-				renderer.initWebGLObjects( scene );
 				renderer.updateShadowMap( scene, camera );
 
 				// render cube map
@@ -583,8 +580,6 @@
 
 				// render scene
 
-				renderer.autoUpdateObjects = true;
-
 				//renderer.render( scene, camera );
 				//renderer.clearTarget( null, 1, 1, 1 );
 				composer.render( 0.1 );

+ 0 - 6
examples/webgl_terrain_dynamic.html

@@ -512,8 +512,6 @@
 
 					morphs.push( meshAnim );
 
-					renderer.initWebGLObjects( scene );
-
 				}
 
 				function morphColorsToFaceColors( geometry ) {
@@ -560,10 +558,6 @@
 
 				} );
 
-				// PRE-INIT
-
-				renderer.initWebGLObjects( scene );
-
 			}
 
 			//

+ 10 - 15
src/core/Geometry.js

@@ -48,6 +48,7 @@ THREE.Geometry = function () {
 	this.lineDistancesNeedUpdate = false;
 
 	this.buffersNeedUpdate = false;
+	this.groupsNeedUpdate = false;
 
 };
 
@@ -678,12 +679,13 @@ THREE.Geometry.prototype = {
 		return function ( usesFaceMaterial, maxVerticesInGroup ) {
 
 			var f, fl, face, materialIndex,
-				groupHash, hash_map = {};
+				groupHash, hash_map = {},geometryGroup;
 
 			var numMorphTargets = this.morphTargets.length;
 			var numMorphNormals = this.morphNormals.length;
 
 			this.geometryGroups = {};
+			this.geometryGroupsList = [];
 
 			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
 
@@ -700,8 +702,9 @@ THREE.Geometry.prototype = {
 
 				if ( ! ( groupHash in this.geometryGroups ) ) {
 
-					this.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
-
+					geometryGroup = { 'id': geometryGroupCounter++, 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
+					this.geometryGroups[ groupHash ] = geometryGroup;
+					this.geometryGroupsList.push(geometryGroup);
 				}
 
 				if ( this.geometryGroups[ groupHash ].vertices + 3 > maxVerticesInGroup ) {
@@ -711,8 +714,10 @@ THREE.Geometry.prototype = {
 
 					if ( ! ( groupHash in this.geometryGroups ) ) {
 
-						this.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
-
+						geometryGroup = { 'id': geometryGroupCounter++, 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
+						this.geometryGroups[ groupHash ] = geometryGroup;
+						this.geometryGroupsList.push(geometryGroup);
+						
 					}
 
 				}
@@ -722,16 +727,6 @@ THREE.Geometry.prototype = {
 
 			}
 
-			this.geometryGroupsList = [];
-
-			for ( var g in this.geometryGroups ) {
-
-				this.geometryGroups[ g ].id = geometryGroupCounter ++;
-
-				this.geometryGroupsList.push( this.geometryGroups[ g ] );
-
-			}
-
 		};
 
 	} )(),

+ 14 - 0
src/core/Object3D.js

@@ -406,6 +406,20 @@ THREE.Object3D.prototype = {
 
 	},
 
+	traverseVisible: function ( callback ) {
+
+		if ( this.visible === false ) return;
+
+		callback( this );
+
+		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
+
+			this.children[ i ].traverseVisible( callback );
+
+		}
+
+	},
+
 	getObjectById: function ( id, recursive ) {
 
 		for ( var i = 0, l = this.children.length; i < l; i ++ ) {

+ 58 - 73
src/core/Projector.js

@@ -80,65 +80,6 @@ THREE.Projector = function () {
 
 	};
 
-	var projectObject = function ( object ) {
-
-		if ( object.visible === false ) return;
-
-		if ( object instanceof THREE.Light ) {
-
-			_renderData.lights.push( object );
-
-		} else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) {
-
-			if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) {
-
-				_object = getNextObjectInPool();
-				_object.id = object.id;
-				_object.object = object;
-
-				if ( object.renderDepth !== null ) {
-
-					_object.z = object.renderDepth;
-
-				} else {
-
-					_vector3.setFromMatrixPosition( object.matrixWorld );
-					_vector3.applyProjection( _viewProjectionMatrix );
-					_object.z = _vector3.z;
-
-				}
-
-				_renderData.objects.push( _object );
-
-			}
-
-		}
-
-		for ( var i = 0, l = object.children.length; i < l; i ++ ) {
-
-			projectObject( object.children[ i ] );
-
-		}
-
-	};
-
-	var projectGraph = function ( root, sortObjects ) {
-
-		_objectCount = 0;
-
-		_renderData.objects.length = 0;
-		_renderData.lights.length = 0;
-
-		projectObject( root );
-
-		if ( sortObjects === true ) {
-
-			_renderData.objects.sort( painterSort );
-
-		}
-
-	};
-
 	var RenderList = function () {
 
 		var normals = [];
@@ -303,9 +244,6 @@ THREE.Projector = function () {
 
 	this.projectScene = function ( scene, camera, sortObjects, sortElements ) {
 
-		var object, geometry, vertices, faces, face, faceVertexNormals, faceVertexUvs,
-		isFaceMaterial, objectMaterials;
-
 		_faceCount = 0;
 		_lineCount = 0;
 		_spriteCount = 0;
@@ -320,12 +258,59 @@ THREE.Projector = function () {
 
 		_frustum.setFromMatrix( _viewProjectionMatrix );
 
-		projectGraph( scene, sortObjects );
+		//
+
+		_objectCount = 0;
+
+		_renderData.objects.length = 0;
+		_renderData.lights.length = 0;
+
+		scene.traverseVisible( function ( object ) {
+
+			if ( object instanceof THREE.Light ) {
+
+				_renderData.lights.push( object );
+
+			} else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) {
+
+				if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) {
+
+					_object = getNextObjectInPool();
+					_object.id = object.id;
+					_object.object = object;
+
+					if ( object.renderDepth !== null ) {
+
+						_object.z = object.renderDepth;
+
+					} else {
+
+						_vector3.setFromMatrixPosition( object.matrixWorld );
+						_vector3.applyProjection( _viewProjectionMatrix );
+						_object.z = _vector3.z;
+
+					}
+
+					_renderData.objects.push( _object );
+
+				}
+
+			}
+
+		} );
+
+		if ( sortObjects === true ) {
+
+			_renderData.objects.sort( painterSort );
+
+		}
+
+		//
 
 		for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) {
 
-			object = _renderData.objects[ o ].object;
-			geometry = object.geometry;
+			var object = _renderData.objects[ o ].object;
+			var geometry = object.geometry;
 
 			renderList.setObject( object );
 
@@ -415,14 +400,14 @@ THREE.Projector = function () {
 
 				} else if ( geometry instanceof THREE.Geometry ) {
 
-					vertices = geometry.vertices;
-					faces = geometry.faces;
-					faceVertexUvs = geometry.faceVertexUvs[ 0 ];
+					var vertices = geometry.vertices;
+					var faces = geometry.faces;
+					var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
 
 					_normalMatrix.getNormalMatrix( _modelMatrix );
 
-					isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
-					objectMaterials = isFaceMaterial === true ? object.material : null;
+					var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
+					var objectMaterials = isFaceMaterial === true ? object.material : null;
 
 					for ( var v = 0, vl = vertices.length; v < vl; v ++ ) {
 
@@ -433,7 +418,7 @@ THREE.Projector = function () {
 
 					for ( var f = 0, fl = faces.length; f < fl; f ++ ) {
 
-						face = faces[ f ];
+						var face = faces[ f ];
 
 						var material = isFaceMaterial === true
 							 ? objectMaterials.materials[ face.materialIndex ]
@@ -518,7 +503,7 @@ THREE.Projector = function () {
 
 						_face.normalModel.applyMatrix3( _normalMatrix ).normalize();
 
-						faceVertexNormals = face.vertexNormals;
+						var faceVertexNormals = face.vertexNormals;
 
 						for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) {
 
@@ -604,7 +589,7 @@ THREE.Projector = function () {
 
 					_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
 
-					vertices = object.geometry.vertices;
+					var vertices = object.geometry.vertices;
 
 					if ( vertices.length === 0 ) continue;
 

+ 56 - 51
src/extras/renderers/plugins/DepthPassPlugin.js

@@ -12,7 +12,8 @@ THREE.DepthPassPlugin = function () {
 	_depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin,
 
 	_frustum = new THREE.Frustum(),
-	_projScreenMatrix = new THREE.Matrix4();
+	_projScreenMatrix = new THREE.Matrix4(),
+	_renderList = [];
 
 	this.init = function ( renderer ) {
 
@@ -76,84 +77,61 @@ THREE.DepthPassPlugin = function () {
 		_renderer.clear();
 
 		// set object matrices & frustum culling
-
-		renderList = scene.__webglObjects;
-
-		for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
-
-			webglObject = renderList[ j ];
-			object = webglObject.object;
-
-			webglObject.render = false;
-
-			if ( object.visible ) {
-
-				if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) {
-
-					object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
-
-					webglObject.render = true;
-
-				}
-
-			}
-
-		}
+		
+		_renderList.length = 0;
+		projectObject(scene,scene,camera);
 
 		// render regular objects
 
 		var objectMaterial, useMorphing, useSkinning;
 
-		for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
-
-			webglObject = renderList[ j ];
-
-			if ( webglObject.render ) {
+		for ( j = 0, jl = _renderList.length; j < jl; j ++ ) {
 
-				object = webglObject.object;
-				buffer = webglObject.buffer;
+			webglObject = _renderList[ j ];
 
-				// todo: create proper depth material for particles
+			object = webglObject.object;
+			buffer = webglObject.buffer;
 
-				if ( object instanceof THREE.PointCloud && ! object.customDepthMaterial ) continue;
+			// todo: create proper depth material for particles
 
-				objectMaterial = getObjectMaterial( object );
+			if ( object instanceof THREE.PointCloud && ! object.customDepthMaterial ) continue;
 
-				if ( objectMaterial ) _renderer.setMaterialFaces( object.material );
+			objectMaterial = getObjectMaterial( object );
 
-				useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets;
-				useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning;
+			if ( objectMaterial ) _renderer.setMaterialFaces( object.material );
 
-				if ( object.customDepthMaterial ) {
+			useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets;
+			useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning;
 
-					material = object.customDepthMaterial;
+			if ( object.customDepthMaterial ) {
 
-				} else if ( useSkinning ) {
+				material = object.customDepthMaterial;
 
-					material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin;
+			} else if ( useSkinning ) {
 
-				} else if ( useMorphing ) {
+				material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin;
 
-					material = _depthMaterialMorph;
+			} else if ( useMorphing ) {
 
-				} else {
+				material = _depthMaterialMorph;
 
-					material = _depthMaterial;
+			} else {
 
-				}
+				material = _depthMaterial;
 
-				if ( buffer instanceof THREE.BufferGeometry ) {
+			}
 
-					_renderer.renderBufferDirect( camera, scene.__lights, fog, material, buffer, object );
+			if ( buffer instanceof THREE.BufferGeometry ) {
 
-				} else {
+				_renderer.renderBufferDirect( camera, scene.__lights, fog, material, buffer, object );
 
-					_renderer.renderBuffer( camera, scene.__lights, fog, material, buffer, object );
+			} else {
 
-				}
+				_renderer.renderBuffer( camera, scene.__lights, fog, material, buffer, object );
 
 			}
 
+
 		}
 
 		// set matrices and render immediate objects
@@ -184,6 +162,33 @@ THREE.DepthPassPlugin = function () {
 		_gl.enable( _gl.BLEND );
 
 	};
+	
+	function projectObject(scene, object,camera){
+		
+		if ( object.visible ) {
+	
+			var webglObjects = scene.__webglObjects[object.id];
+	
+			if (webglObjects && (object.frustumCulled === false || _frustum.intersectsObject( object ) === true) ) {
+		
+		
+				for (var i = 0, l = webglObjects.length; i < l; i++){
+			
+					var webglObject = webglObjects[i];
+					
+					object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
+					_renderList.push(webglObject);
+					
+				}
+			}
+	
+			for(var i = 0, l = object.children.length; i < l; i++) {
+				
+				projectObject(scene, object.children[i], camera);
+			}
+		
+		}
+	}
 
 	// For the moment just ignore objects that have multiple materials with different animation methods
 	// Only the first material will be taken into account for deciding which depth material to use

+ 18 - 11
src/extras/renderers/plugins/LensFlarePlugin.js

@@ -5,6 +5,8 @@
 
 THREE.LensFlarePlugin = function () {
 
+	var flares = [];
+
 	var _gl, _renderer, _precision, _lensFlare = {};
 
 	this.init = function ( renderer ) {
@@ -105,10 +107,19 @@ THREE.LensFlarePlugin = function () {
 
 	this.render = function ( scene, camera, viewportWidth, viewportHeight ) {
 
-		var flares = scene.__webglFlares,
-			nFlares = flares.length;
+		flares.length = 0;
+
+		scene.traverseVisible( function ( child ) {
+
+			if ( child instanceof THREE.LensFlare ) {
 
-		if ( ! nFlares ) return;
+				flares.push( child );
+
+			}
+
+		} );
+
+		if ( flares.length === 0 ) return;
 
 		var tempPosition = new THREE.Vector3();
 
@@ -147,18 +158,14 @@ THREE.LensFlarePlugin = function () {
 		_gl.disable( _gl.CULL_FACE );
 		_gl.depthMask( false );
 
-		var i, j, jl, flare, sprite;
-
-		for ( i = 0; i < nFlares; i ++ ) {
+		for ( var i = 0, l = flares.length; i < l; i ++ ) {
 
 			size = 16 / viewportHeight;
 			scale.set( size * invAspect, size );
 
 			// calc object screen position
 
-			flare = flares[ i ];
-
-			if ( flare.visible === false ) continue;
+			var flare = flares[ i ];
 			
 			tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] );
 
@@ -235,9 +242,9 @@ THREE.LensFlarePlugin = function () {
 				_gl.uniform1i( uniforms.renderType, 2 );
 				_gl.enable( _gl.BLEND );
 
-				for ( j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {
+				for ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {
 
-					sprite = flare.lensFlares[ j ];
+					var sprite = flare.lensFlares[ j ];
 
 					if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) {
 

+ 61 - 56
src/extras/renderers/plugins/ShadowMapPlugin.js

@@ -14,7 +14,9 @@ THREE.ShadowMapPlugin = function () {
 	_min = new THREE.Vector3(),
 	_max = new THREE.Vector3(),
 
-	_matrixPosition = new THREE.Vector3();
+	_matrixPosition = new THREE.Vector3(),
+	
+	_renderList = [];
 
 	this.init = function ( renderer ) {
 
@@ -51,7 +53,6 @@ THREE.ShadowMapPlugin = function () {
 		shadowMap, shadowMatrix, shadowCamera,
 		program, buffer, material,
 		webglObject, object, light,
-		renderList,
 
 		lights = [],
 		k = 0,
@@ -230,85 +231,62 @@ THREE.ShadowMapPlugin = function () {
 
 			// set object matrices & frustum culling
 
-			renderList = scene.__webglObjects;
+			_renderList.length = 0;
+			projectObject(scene,scene,shadowCamera);
 
-			for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
-
-				webglObject = renderList[ j ];
-				object = webglObject.object;
-
-				webglObject.render = false;
-
-				if ( object.visible && object.castShadow ) {
-
-					if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) {
-
-						object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
-
-						webglObject.render = true;
-
-					}
-
-				}
-
-			}
 
 			// render regular objects
 
 			var objectMaterial, useMorphing, useSkinning;
 
-			for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
-
-				webglObject = renderList[ j ];
-
-				if ( webglObject.render ) {
+			for ( j = 0, jl = _renderList.length; j < jl; j ++ ) {
 
-					object = webglObject.object;
-					buffer = webglObject.buffer;
+				webglObject = _renderList[ j ];
 
-					// culling is overriden globally for all objects
-					// while rendering depth map
+				object = webglObject.object;
+				buffer = webglObject.buffer;
 
-					// need to deal with MeshFaceMaterial somehow
-					// in that case just use the first of material.materials for now
-					// (proper solution would require to break objects by materials
-					//  similarly to regular rendering and then set corresponding
-					//  depth materials per each chunk instead of just once per object)
+				// culling is overriden globally for all objects
+				// while rendering depth map
 
-					objectMaterial = getObjectMaterial( object );
+				// need to deal with MeshFaceMaterial somehow
+				// in that case just use the first of material.materials for now
+				// (proper solution would require to break objects by materials
+				//  similarly to regular rendering and then set corresponding
+				//  depth materials per each chunk instead of just once per object)
 
-					useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets;
-					useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning;
+				objectMaterial = getObjectMaterial( object );
 
-					if ( object.customDepthMaterial ) {
+				useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets;
+				useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning;
 
-						material = object.customDepthMaterial;
+				if ( object.customDepthMaterial ) {
 
-					} else if ( useSkinning ) {
+					material = object.customDepthMaterial;
 
-						material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin;
+				} else if ( useSkinning ) {
 
-					} else if ( useMorphing ) {
+					material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin;
 
-						material = _depthMaterialMorph;
+				} else if ( useMorphing ) {
 
-					} else {
+					material = _depthMaterialMorph;
 
-						material = _depthMaterial;
+				} else {
 
-					}
+					material = _depthMaterial;
 
-					_renderer.setMaterialFaces( objectMaterial );
+				}
 
-					if ( buffer instanceof THREE.BufferGeometry ) {
+				_renderer.setMaterialFaces( objectMaterial );
 
-						_renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object );
+				if ( buffer instanceof THREE.BufferGeometry ) {
 
-					} else {
+					_renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object );
 
-						_renderer.renderBuffer( shadowCamera, scene.__lights, fog, material, buffer, object );
+				} else {
 
-					}
+					_renderer.renderBuffer( shadowCamera, scene.__lights, fog, material, buffer, object );
 
 				}
 
@@ -316,7 +294,7 @@ THREE.ShadowMapPlugin = function () {
 
 			// set matrices and render immediate objects
 
-			renderList = scene.__webglObjectsImmediate;
+			var renderList = scene.__webglObjectsImmediate;
 
 			for ( j = 0, jl = renderList.length; j < jl; j ++ ) {
 
@@ -350,6 +328,33 @@ THREE.ShadowMapPlugin = function () {
 		}
 
 	};
+	
+	function projectObject(scene, object,shadowCamera){
+		
+		if ( object.visible ) {
+	
+			var webglObjects = scene.__webglObjects[object.id];
+	
+			if (webglObjects && object.castShadow && (object.frustumCulled === false || _frustum.intersectsObject( object ) === true) ) {
+		
+		
+				for (var i = 0, l = webglObjects.length; i < l; i++){
+			
+					var webglObject = webglObjects[i];
+					
+					object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
+					_renderList.push(webglObject);
+					
+				}
+			}
+	
+			for(var i = 0, l = object.children.length; i < l; i++) {
+				
+				projectObject(scene, object.children[i],shadowCamera);
+			}
+		
+		}
+	}
 
 	function createVirtualLight( light, cascade ) {
 

+ 23 - 19
src/extras/renderers/plugins/SpritePlugin.js

@@ -7,6 +7,8 @@ THREE.SpritePlugin = function () {
 
 	var _gl, _renderer, _texture;
 
+	var sprites = [];
+
 	var vertices, faces, vertexBuffer, elementBuffer;
 	var program, attributes, uniforms;
 
@@ -81,10 +83,19 @@ THREE.SpritePlugin = function () {
 
 	this.render = function ( scene, camera, viewportWidth, viewportHeight ) {
 
-		var sprites = scene.__webglSprites,
-			nSprites = sprites.length;
+		sprites.length = 0;
+
+		scene.traverseVisible( function ( child ) {
+
+			if ( child instanceof THREE.Sprite ) {
+
+				sprites.push( child );
+
+			}
+
+		} );
 
-		if ( ! nSprites ) return;
+		if ( sprites.length === 0 ) return;
 
 		// setup gl
 
@@ -145,14 +156,10 @@ THREE.SpritePlugin = function () {
 
 		// update positions and sort
 
-		var i, sprite, material, fogType, scale = [];
+		for ( var i = 0, l = sprites.length; i < l; i ++ ) {
 
-		for( i = 0; i < nSprites; i ++ ) {
-
-			sprite = sprites[ i ];
-			material = sprite.material;
-
-			if ( sprite.visible === false ) continue;
+			var sprite = sprites[ i ];
+			var material = sprite.material;
 
 			sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );
 			sprite.z = - sprite._modelViewMatrix.elements[ 14 ];
@@ -163,13 +170,12 @@ THREE.SpritePlugin = function () {
 
 		// render all sprites
 
-		for( i = 0; i < nSprites; i ++ ) {
+		var scale = [];
 
-			sprite = sprites[ i ];
+		for ( var i = 0, l = sprites.length; i < l; i ++ ) {
 
-			if ( sprite.visible === false ) continue;
-
-			material = sprite.material;
+			var sprite = sprites[ i ];
+			var material = sprite.material;
 
 			_gl.uniform1f( uniforms.alphaTest, material.alphaTest );
 			_gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements );
@@ -177,14 +183,12 @@ THREE.SpritePlugin = function () {
 			scale[ 0 ] = sprite.scale.x;
 			scale[ 1 ] = sprite.scale.y;
 
+			var fogType = 0;
+
 			if ( scene.fog && material.fog ) {
 
 				fogType = sceneFogType;
 
-			} else {
-
-				fogType = 0;
-
 			}
 
 			if ( oldFogType !== fogType ) {

+ 2 - 0
src/renderers/CanvasRenderer.js

@@ -782,6 +782,8 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 	function textureToPattern( texture ) {
 
+		if ( texture instanceof THREE.CompressedTexture ) return;
+
 		var repeatX = texture.wrapS === THREE.RepeatWrapping;
 		var repeatY = texture.wrapT === THREE.RepeatWrapping;
 

+ 257 - 268
src/renderers/WebGLRenderer.js

@@ -28,6 +28,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	_clearColor = new THREE.Color( 0x000000 ),
 	_clearAlpha = 0;
+	
+	var opaqueObjects = [];
+	var transparentObjects = [];
+	var _sortObjects = true;
 
 	// public properties
 
@@ -49,7 +53,6 @@ THREE.WebGLRenderer = function ( parameters ) {
 	// scene graph
 
 	this.sortObjects = true;
-	this.autoUpdateObjects = true;
 
 	// physically based shading
 
@@ -168,10 +171,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 	_lights = {
 
 		ambient: [ 0, 0, 0 ],
-		directional: { length: 0, colors: new Array(), positions: new Array() },
-		point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array() },
-		spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), directions: new Array(), anglesCos: new Array(), exponents: new Array() },
-		hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() }
+		directional: { length: 0, colors:[], positions: [] },
+		point: { length: 0, colors: [], positions: [], distances: [] },
+		spot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [] },
+		hemi: { length: 0, skyColors: [], groundColors: [], positions: [] }
 
 	};
 
@@ -218,16 +221,6 @@ THREE.WebGLRenderer = function ( parameters ) {
 	var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT );
 	var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT );
 
-	/*
-	var _vertexShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_INT );
-	var _vertexShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_INT );
-	var _vertexShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_INT );
-
-	var _fragmentShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_INT );
-	var _fragmentShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_INT );
-	var _fragmentShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_INT );
-	*/
-
 	// clamp precision to maximum available
 
 	var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0;
@@ -442,6 +435,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 		_oldDoubleSided = - 1;
 		_oldFlipSided = - 1;
 
+		initObjects( scene );
+
 		this.shadowMapPlugin.update( scene, camera );
 
 	};
@@ -619,9 +614,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			if ( geometry.geometryGroups !== undefined ) {
 
-				for ( var g in geometry.geometryGroups ) {
+				for ( var i = 0,l = geometry.geometryGroupsList.length; i<l;i++ ) {
 
-					var geometryGroup = geometry.geometryGroups[ g ];
+					var geometryGroup = geometry.geometryGroupsList[ i ];
 
 					if ( geometryGroup.numMorphTargets !== undefined ) {
 
@@ -2731,7 +2726,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 					}
 
-					_gl.drawElements( _gl.LINES, index.array.length, type, 0 ); // 2 bytes per Uint16Array
+					_gl.drawElements( mode, index.array.length, type, 0 ); // 2 bytes per Uint16Array
 
 					_this.info.render.calls ++;
 					_this.info.render.vertices += index.array.length; // not really true, here vertices can be shared
@@ -2757,7 +2752,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 						// render indexed lines
 
-						_gl.drawElements( _gl.LINES, offsets[ i ].count, type, offsets[ i ].start * size ); // 2 bytes per Uint16Array
+						_gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size ); // 2 bytes per Uint16Array
 
 						_this.info.render.calls ++;
 						_this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared
@@ -3217,6 +3212,20 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	};
 
+	function reversePainterSortStable ( a, b ) {
+
+		if ( a.z !== b.z ) {
+
+			return a.z - b.z;
+
+		} else {
+
+			return a.id - b.id;
+
+		}
+
+	};
+
 	function numericalSort ( a, b ) {
 
 		return b[ 0 ] - a[ 0 ];
@@ -3261,12 +3270,23 @@ THREE.WebGLRenderer = function ( parameters ) {
 		_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
 		_frustum.setFromMatrix( _projScreenMatrix );
 
-		// update WebGL objects
+		initObjects( scene );
 
-		if ( this.autoUpdateObjects ) this.initWebGLObjects( scene );
+		opaqueObjects.length = 0;
+		transparentObjects.length = 0;
+		_sortObjects = this.sortObjects;
+		
+		projectObject(scene,scene,camera);
 
-		// custom render plugins (pre pass)
+		if ( this.sortObjects ) {
+
+			opaqueObjects.sort( painterSortStable );
+			transparentObjects.sort( reversePainterSortStable );
 
+		}
+
+		// custom render plugins (pre pass)
+		
 		renderPlugins( this.renderPluginsPre, scene, camera );
 
 		//
@@ -3286,54 +3306,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		// set matrices for regular objects (frustum culled)
 
-		renderList = scene.__webglObjects;
-
-		for ( i = 0, il = renderList.length; i < il; i ++ ) {
-
-			webglObject = renderList[ i ];
-			object = webglObject.object;
-
-			webglObject.id = i;
-			webglObject.render = false;
-
-			if ( object.visible ) {
-
-				if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) {
-
-					setupMatrices( object, camera );
-
-					unrollBufferMaterial( webglObject );
-
-					webglObject.render = true;
-
-					if ( this.sortObjects === true ) {
-
-						if ( object.renderDepth !== null ) {
-
-							webglObject.z = object.renderDepth;
-
-						} else {
-
-							_vector3.setFromMatrixPosition( object.matrixWorld );
-							_vector3.applyProjection( _projScreenMatrix );
-
-							webglObject.z = _vector3.z;
-
-						}
-
-					}
-
-				}
-
-			}
-
-		}
-
-		if ( this.sortObjects ) {
-
-			renderList.sort( painterSortStable );
+		
 
-		}
 
 		// set matrices for immediate objects
 
@@ -3363,7 +3337,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 			this.setDepthWrite( material.depthWrite );
 			setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
 
-			renderObjects( scene.__webglObjects, false, '', camera, lights, fog, true, material );
+			renderObjects( opaqueObjects, camera, lights, fog, true, material );
+			renderObjects( transparentObjects, camera, lights, fog, true, material );
 			renderObjectsImmediate( scene.__webglObjectsImmediate, '', camera, lights, fog, false, material );
 
 		} else {
@@ -3374,12 +3349,12 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			this.setBlending( THREE.NoBlending );
 
-			renderObjects( scene.__webglObjects, true, 'opaque', camera, lights, fog, false, material );
+			renderObjects( opaqueObjects, camera, lights, fog, false, material );
 			renderObjectsImmediate( scene.__webglObjectsImmediate, 'opaque', camera, lights, fog, false, material );
 
 			// transparent pass (back-to-front order)
 
-			renderObjects( scene.__webglObjects, false, 'transparent', camera, lights, fog, true, material );
+			renderObjects( transparentObjects, camera, lights, fog, true, material );
 			renderObjectsImmediate( scene.__webglObjectsImmediate, 'transparent', camera, lights, fog, true, material );
 
 		}
@@ -3405,10 +3380,57 @@ THREE.WebGLRenderer = function ( parameters ) {
 		// _gl.finish();
 
 	};
+	
+	function projectObject(scene, object,camera){
+		
+		if ( object.visible === false ) return;
+			
+		var webglObjects = scene.__webglObjects[ object.id ];
+		
+		if ( webglObjects && (object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) {
+			
+			updateObject( scene, object );
+			
+			for ( var i = 0, l = webglObjects.length; i < l; i ++ ) {
+				
+				var webglObject = webglObjects[i];
+				
+				unrollBufferMaterial( webglObject );
+
+				webglObject.render = true;
+
+				if ( _sortObjects === true ) {
+
+					if ( object.renderDepth !== null ) {
+
+						webglObject.z = object.renderDepth;
+
+					} else {
+
+						_vector3.setFromMatrixPosition( object.matrixWorld );
+						_vector3.applyProjection( _projScreenMatrix );
+
+						webglObject.z = _vector3.z;
+
+					}
+
+				}
+
+			}
+
+		}
+		
+		for ( var i = 0, l = object.children.length; i < l; i ++ ) {
+
+			projectObject( scene, object.children[ i ], camera );
+
+		}
+				
+	}
 
 	function renderPlugins( plugins, scene, camera ) {
 
-		if ( ! plugins.length ) return;
+		if ( plugins.length === 0 ) return;
 
 		for ( var i = 0, il = plugins.length; i < il; i ++ ) {
 
@@ -3448,61 +3470,46 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	};
 
-	function renderObjects( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) {
-
-		var webglObject, object, buffer, material, start, end, delta;
-
-		if ( reverse ) {
+	function renderObjects( renderList, camera, lights, fog, useBlending, overrideMaterial ) {
 
-			start = renderList.length - 1;
-			end = - 1;
-			delta = - 1;
+		var webglObject, object, buffer, material;
 
-		} else {
-
-			start = 0;
-			end = renderList.length;
-			delta = 1;
-		}
-
-		for ( var i = start; i !== end; i += delta ) {
+		for ( var i = renderList.length - 1; i !== - 1; i -- ) {
 
 			webglObject = renderList[ i ];
 
-			if ( webglObject.render ) {
-
-				object = webglObject.object;
-				buffer = webglObject.buffer;
-
-				if ( overrideMaterial ) {
+			object = webglObject.object;
+			buffer = webglObject.buffer;
+							
+			setupMatrices( object, camera );
 
-					material = overrideMaterial;
+			if ( overrideMaterial ) {
 
-				} else {
+				material = overrideMaterial;
 
-					material = webglObject[ materialType ];
+			} else {
 
-					if ( ! material ) continue;
+				material = webglObject.material;
 
-					if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
+				if ( ! material ) continue;
 
-					_this.setDepthTest( material.depthTest );
-					_this.setDepthWrite( material.depthWrite );
-					setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
+				if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
 
-				}
+				_this.setDepthTest( material.depthTest );
+				_this.setDepthWrite( material.depthWrite );
+				setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
 
-				_this.setMaterialFaces( material );
+			}
 
-				if ( buffer instanceof THREE.BufferGeometry ) {
+			_this.setMaterialFaces( material );
 
-					_this.renderBufferDirect( camera, lights, fog, material, buffer, object );
+			if ( buffer instanceof THREE.BufferGeometry ) {
 
-				} else {
+				_this.renderBufferDirect( camera, lights, fog, material, buffer, object );
 
-					_this.renderBuffer( camera, lights, fog, material, buffer, object );
+			} else {
 
-				}
+				_this.renderBuffer( camera, lights, fog, material, buffer, object );
 
 			}
 
@@ -3602,13 +3609,13 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			if ( material.transparent ) {
 
-				globject.transparent = material;
-				globject.opaque = null;
+				globject.material = material; 
+				transparentObjects.push(globject);
 
 			} else {
 
-				globject.opaque = material;
-				globject.transparent = null;
+				globject.material = material; 
+				opaqueObjects.push(globject);
 
 			}
 
@@ -3618,13 +3625,13 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				if ( material.transparent ) {
 
-					globject.transparent = material;
-					globject.opaque = null;
+					globject.material = material; 
+					transparentObjects.push(globject);
 
 				} else {
 
-					globject.opaque = material;
-					globject.transparent = null;
+					globject.material = material; 
+					opaqueObjects.push(globject);
 
 				}
 
@@ -3636,14 +3643,12 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	// Objects refresh
 
-	this.initWebGLObjects = function ( scene ) {
+	var initObjects = function ( scene ) {
 
 		if ( ! scene.__webglObjects ) {
 
-			scene.__webglObjects = [];
+			scene.__webglObjects = {};
 			scene.__webglObjectsImmediate = [];
-			scene.__webglSprites = [];
-			scene.__webglFlares = [];
 
 		}
 
@@ -3661,37 +3666,13 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		}
 
-		// update must be called after objects adding / removal
-
-		for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) {
-
-			var object = scene.__webglObjects[ o ].object;
-
-			// TODO: Remove this hack (WebGLRenderer refactoring)
-
-			if ( object.__webglInit === undefined ) {
-
-				if ( object.__webglActive !== undefined ) {
-
-					removeObject( object, scene );
-
-				}
-
-				addObject( object, scene );
-
-			}
-
-			updateObject( object );
-
-		}
-
 	};
 
 	// Objects adding
 
 	function addObject( object, scene ) {
 
-		var g, geometry, material, geometryGroup;
+		var g, geometry, geometryGroup;
 
 		if ( object.__webglInit === undefined ) {
 
@@ -3700,80 +3681,55 @@ THREE.WebGLRenderer = function ( parameters ) {
 			object._modelViewMatrix = new THREE.Matrix4();
 			object._normalMatrix = new THREE.Matrix3();
 
-			geometry = object.geometry;
-
-			if ( geometry === undefined ) {
-
-				// ImmediateRenderObject
-
-			} else if ( geometry.__webglInit === undefined ) {
-
-				geometry.__webglInit = true;
-				geometry.addEventListener( 'dispose', onGeometryDispose );
-
-				if ( geometry instanceof THREE.BufferGeometry ) {
-
-					initDirectBuffers( geometry );
-
-				} else if ( object instanceof THREE.Mesh ) {
-
-					material = object.material;
-
-					if ( geometry.geometryGroups === undefined ) {
-
-						geometry.makeGroups( material instanceof THREE.MeshFaceMaterial, _glExtensionElementIndexUint ? 4294967296 : 65535  );
-
-					}
-
-					// create separate VBOs per geometry chunk
-
-					for ( g in geometry.geometryGroups ) {
+		}
+		
+		geometry = object.geometry;
+		
+		if ( geometry === undefined ) {
 
-						geometryGroup = geometry.geometryGroups[ g ];
+			// ImmediateRenderObject
 
-						// initialise VBO on the first access
+		} else if ( geometry.__webglInit === undefined ) {
 
-						if ( ! geometryGroup.__webglVertexBuffer ) {
+			geometry.__webglInit = true;
+			geometry.addEventListener( 'dispose', onGeometryDispose );
 
-							createMeshBuffers( geometryGroup );
-							initMeshBuffers( geometryGroup, object );
+			if ( geometry instanceof THREE.BufferGeometry ) {
 
-							geometry.verticesNeedUpdate = true;
-							geometry.morphTargetsNeedUpdate = true;
-							geometry.elementsNeedUpdate = true;
-							geometry.uvsNeedUpdate = true;
-							geometry.normalsNeedUpdate = true;
-							geometry.tangentsNeedUpdate = true;
-							geometry.colorsNeedUpdate = true;
+				initDirectBuffers( geometry );
 
-						}
+			} else if ( object instanceof THREE.Mesh ) {
+				
+				if ( object.__webglActive !== undefined ) {
 
-					}
+					removeObject( object, scene );
 
-				} else if ( object instanceof THREE.Line ) {
+				}
+				
+				initGeometryGroups(scene, object, geometry);
 
-					if ( ! geometry.__webglVertexBuffer ) {
+			} else if ( object instanceof THREE.Line ) {
 
-						createLineBuffers( geometry );
-						initLineBuffers( geometry, object );
+				if ( ! geometry.__webglVertexBuffer ) {
 
-						geometry.verticesNeedUpdate = true;
-						geometry.colorsNeedUpdate = true;
-						geometry.lineDistancesNeedUpdate = true;
+					createLineBuffers( geometry );
+					initLineBuffers( geometry, object );
 
-					}
+					geometry.verticesNeedUpdate = true;
+					geometry.colorsNeedUpdate = true;
+					geometry.lineDistancesNeedUpdate = true;
 
-				} else if ( object instanceof THREE.PointCloud ) {
+				}
 
-					if ( ! geometry.__webglVertexBuffer ) {
+			} else if ( object instanceof THREE.PointCloud ) {
 
-						createParticleBuffers( geometry );
-						initParticleBuffers( geometry, object );
+				if ( ! geometry.__webglVertexBuffer ) {
 
-						geometry.verticesNeedUpdate = true;
-						geometry.colorsNeedUpdate = true;
+					createParticleBuffers( geometry );
+					initParticleBuffers( geometry, object );
 
-					}
+					geometry.verticesNeedUpdate = true;
+					geometry.colorsNeedUpdate = true;
 
 				}
 
@@ -3781,7 +3737,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		}
 
-		if ( object.__webglActive === undefined ) {
+		if ( object.__webglActive === undefined) {
 
 			if ( object instanceof THREE.Mesh ) {
 
@@ -3793,14 +3749,12 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				} else if ( geometry instanceof THREE.Geometry ) {
 
-					for ( g in geometry.geometryGroups ) {
-
-						geometryGroup = geometry.geometryGroups[ g ];
-
+					for ( var i = 0,l = geometry.geometryGroupsList.length; i<l;i++ ) {
+	
+						geometryGroup = geometry.geometryGroupsList[ i ];
 						addBuffer( scene.__webglObjects, geometryGroup, object );
-
+						
 					}
-
 				}
 
 			} else if ( object instanceof THREE.Line ||
@@ -3813,31 +3767,76 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				addBufferImmediate( scene.__webglObjectsImmediate, object );
 
-			} else if ( object instanceof THREE.Sprite ) {
+			}
+
+			object.__webglActive = true;
+
+		}
 
-				scene.__webglSprites.push( object );
+	};
+	
+	function initGeometryGroups( scene, object, geometry ) {
+		
+		var g, geometryGroup, material,addBuffers = false;
+		material = object.material;
 
-			} else if ( object instanceof THREE.LensFlare ) {
+		if ( geometry.geometryGroups === undefined || geometry.groupsNeedUpdate ) {
+			
+			delete scene.__webglObjects[object.id];
+			geometry.makeGroups( material instanceof THREE.MeshFaceMaterial, _glExtensionElementIndexUint ? 4294967296 : 65535  );
+			geometry.groupsNeedUpdate = false;
 
-				scene.__webglFlares.push( object );
+		}
 
-			}
+		// create separate VBOs per geometry chunk
 
-			object.__webglActive = true;
+		for ( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) {
+
+			geometryGroup = geometry.geometryGroupsList[ i ];
+
+			// initialise VBO on the first access
+
+			if ( ! geometryGroup.__webglVertexBuffer ) {
+
+				createMeshBuffers( geometryGroup );
+				initMeshBuffers( geometryGroup, object );
+
+				geometry.verticesNeedUpdate = true;
+				geometry.morphTargetsNeedUpdate = true;
+				geometry.elementsNeedUpdate = true;
+				geometry.uvsNeedUpdate = true;
+				geometry.normalsNeedUpdate = true;
+				geometry.tangentsNeedUpdate = true;
+				geometry.colorsNeedUpdate = true;
+				
+				addBuffers = true;
+				
+			} else {
+				
+				addBuffers = false;
+				
+			}
+			
+			if ( addBuffers || object.__webglActive === undefined ) {
+				addBuffer( scene.__webglObjects, geometryGroup, object );
+			}
 
 		}
 
-	};
+		object.__webglActive = true;
 
+	}
+	
 	function addBuffer( objlist, buffer, object ) {
 
-		objlist.push(
+		var id = object.id;
+		objlist[id] = objlist[id] || [];
+		objlist[id].push(
 			{
-				id: null,
+				id: id,
 				buffer: buffer,
 				object: object,
-				opaque: null,
-				transparent: null,
+				material: null,
 				z: 0
 			}
 		);
@@ -3860,7 +3859,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	// Objects updates
 
-	function updateObject( object ) {
+	function updateObject(scene, object ) {
 
 		var geometry = object.geometry,
 			geometryGroup, customAttributesDirty, material;
@@ -3872,6 +3871,19 @@ THREE.WebGLRenderer = function ( parameters ) {
 		} else if ( object instanceof THREE.Mesh ) {
 
 			// check all geometry groups
+			if ( geometry.buffersNeedUpdate || geometry.groupsNeedUpdate ) {
+				
+				if ( geometry instanceof THREE.BufferGeometry ) {
+
+					initDirectBuffers( geometry );
+
+				} else if ( object instanceof THREE.Mesh ) {
+				
+					initGeometryGroups(scene, object,geometry);
+					
+				}
+				
+			}
 
 			for ( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) {
 
@@ -3879,7 +3891,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				material = getBufferMaterial( object, geometryGroup );
 
-				if ( geometry.buffersNeedUpdate ) {
+				if ( geometry.buffersNeedUpdate || geometry.groupsNeedUpdate) {
 
 					initMeshBuffers( geometryGroup, object );
 
@@ -3981,15 +3993,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 			 object instanceof THREE.PointCloud ||
 			 object instanceof THREE.Line ) {
 
-			removeInstances( scene.__webglObjects, object );
-
-		} else if ( object instanceof THREE.Sprite ) {
-
-			removeInstancesDirect( scene.__webglSprites, object );
-
-		} else if ( object instanceof THREE.LensFlare ) {
-
-			removeInstancesDirect( scene.__webglFlares, object );
+			removeInstancesWebglObjects( scene.__webglObjects, object );
 
 		} else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {
 
@@ -4000,26 +4004,20 @@ THREE.WebGLRenderer = function ( parameters ) {
 		delete object.__webglActive;
 
 	};
+	
+	
 
-	function removeInstances( objlist, object ) {
-
-		for ( var o = objlist.length - 1; o >= 0; o -- ) {
-
-			if ( objlist[ o ].object === object ) {
-
-				objlist.splice( o, 1 );
-
-			}
+	function removeInstancesWebglObjects( objlist, object ) {
 
-		}
+		delete objlist[ object.id ]; 
 
 	};
 
-	function removeInstancesDirect( objlist, object ) {
+	function removeInstances( objlist, object ) {
 
 		for ( var o = objlist.length - 1; o >= 0; o -- ) {
 
-			if ( objlist[ o ] === object ) {
+			if ( objlist[ o ].object === object ) {
 
 				objlist.splice( o, 1 );
 
@@ -4753,17 +4751,18 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	function loadUniformsGeneric ( program, uniforms ) {
 
-		var uniform, value, type, location, texture, textureUnit, i, il, j, jl, offset;
+		var texture, textureUnit, offset;
+
+		for ( var j = 0, jl = uniforms.length; j < jl; j ++ ) {
 
-		for ( j = 0, jl = uniforms.length; j < jl; j ++ ) {
+			var location = program.uniforms[ uniforms[ j ][ 1 ] ];
 
-			location = program.uniforms[ uniforms[ j ][ 1 ] ];
 			if ( ! location ) continue;
 
-			uniform = uniforms[ j ][ 0 ];
+			var uniform = uniforms[ j ][ 0 ];
 
-			type = uniform.type;
-			value = uniform.value;
+			var type = uniform.type;
+			var value = uniform.value;
 
 			if ( type === 'i' ) { // single integer
 
@@ -4813,7 +4812,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				}
 
-				for ( i = 0, il = value.length; i < il; i ++ ) {
+				for ( var i = 0, il = value.length; i < il; i ++ ) {
 
 					offset = i * 2;
 
@@ -4832,7 +4831,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				}
 
-				for ( i = 0, il = value.length; i < il; i ++ ) {
+				for ( var i = 0, il = value.length; i < il; i ++ ) {
 
 					offset = i * 3;
 
@@ -4852,7 +4851,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				}
 
-				for ( i = 0, il = value.length; i < il; i ++ ) {
+				for ( var i = 0, il = value.length; i < il; i ++ ) {
 
 					offset = i * 4;
 
@@ -4877,7 +4876,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				}
 
-				for ( i = 0, il = value.length; i < il; i ++ ) {
+				for ( var i = 0, il = value.length; i < il; i ++ ) {
 
 					value[ i ].flattenToArrayOffset( uniform._array, i * 9 );
 
@@ -4897,7 +4896,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				}
 
-				for ( i = 0, il = value.length; i < il; i ++ ) {
+				for ( var i = 0, il = value.length; i < il; i ++ ) {
 
 					value[ i ].flattenToArrayOffset( uniform._array, i * 16 );
 
@@ -4937,7 +4936,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				}
 
-				for ( i = 0, il = uniform.value.length; i < il; i ++ ) {
+				for ( var i = 0, il = uniform.value.length; i < il; i ++ ) {
 
 					uniform._array[ i ] = getTextureUnit();
 
@@ -4945,7 +4944,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				_gl.uniform1iv( location, uniform._array );
 
-				for ( i = 0, il = uniform.value.length; i < il; i ++ ) {
+				for ( var i = 0, il = uniform.value.length; i < il; i ++ ) {
 
 					texture = uniform.value[ i ];
 					textureUnit = uniform._array[ i ];
@@ -5074,11 +5073,6 @@ THREE.WebGLRenderer = function ( parameters ) {
 				_direction.sub( _vector3 );
 				_direction.normalize();
 
-				// skip lights with undefined direction
-				// these create troubles in OpenGL (making pixel black)
-
-				if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue;
-
 				dirOffset = dirLength * 3;
 
 				dirPositions[ dirOffset ]     = _direction.x;
@@ -5174,11 +5168,6 @@ THREE.WebGLRenderer = function ( parameters ) {
 				_direction.setFromMatrixPosition( light.matrixWorld );
 				_direction.normalize();
 
-				// skip lights with undefined direction
-				// these create troubles in OpenGL (making pixel black)
-
-				if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue;
-
 				hemiOffset = hemiLength * 3;
 
 				hemiPositions[ hemiOffset ]     = _direction.x;

+ 1 - 1756
src/renderers/shaders/ShaderChunk.js

@@ -1,1756 +1 @@
-/**
- * Shader chunks for WebLG Shader library
- *
- * @author alteredq / http://alteredqualia.com/
- * @author mrdoob / http://mrdoob.com/
- * @author mikael emtinger / http://gomo.se/
- */
-
-THREE.ShaderChunk = {
-
-	// FOG
-
-	fog_pars_fragment: [
-
-		"#ifdef USE_FOG",
-
-		"	uniform vec3 fogColor;",
-
-		"	#ifdef FOG_EXP2",
-
-		"		uniform float fogDensity;",
-
-		"	#else",
-
-		"		uniform float fogNear;",
-		"		uniform float fogFar;",
-
-		"	#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	fog_fragment: [
-
-		"#ifdef USE_FOG",
-
-		"	#ifdef USE_LOGDEPTHBUF_EXT",
-
-		"		float depth = gl_FragDepthEXT / gl_FragCoord.w;",
-
-		"	#else",
-
-		"		float depth = gl_FragCoord.z / gl_FragCoord.w;",
-
-		"	#endif",
-
-		"	#ifdef FOG_EXP2",
-
-		"		const float LOG2 = 1.442695;",
-		"		float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );",
-		"		fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );",
-
-		"	#else",
-
-		"		float fogFactor = smoothstep( fogNear, fogFar, depth );",
-
-		"	#endif",
-
-		"	gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );",
-
-		"#endif"
-
-	].join("\n"),
-
-	// ENVIRONMENT MAP
-
-	envmap_pars_fragment: [
-
-		"#ifdef USE_ENVMAP",
-
-		"	uniform float reflectivity;",
-		"	uniform samplerCube envMap;",
-		"	uniform float flipEnvMap;",
-		"	uniform int combine;",
-
-		"	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )",
-
-		"		uniform bool useRefract;",
-		"		uniform float refractionRatio;",
-
-		"	#else",
-
-		"		varying vec3 vReflect;",
-
-		"	#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	envmap_fragment: [
-
-		"#ifdef USE_ENVMAP",
-
-		"	vec3 reflectVec;",
-
-		"	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )",
-
-		"		vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );",
-
-				// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations
-				// "Transforming Normal Vectors with the Inverse Transformation"
-
-		"		vec3 worldNormal = normalize( vec3( vec4( normal, 0.0 ) * viewMatrix ) );",
-
-		"		if ( useRefract ) {",
-
-		"			reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );",
-
-		"		} else { ",
-
-		"			reflectVec = reflect( cameraToVertex, worldNormal );",
-
-		"		}",
-
-		"	#else",
-
-		"		reflectVec = vReflect;",
-
-		"	#endif",
-
-		"	#ifdef DOUBLE_SIDED",
-
-		"		float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );",
-		"		vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );",
-
-		"	#else",
-
-		"		vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );",
-
-		"	#endif",
-
-		"	#ifdef GAMMA_INPUT",
-
-		"		cubeColor.xyz *= cubeColor.xyz;",
-
-		"	#endif",
-
-		"	if ( combine == 1 ) {",
-
-		"		gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );",
-
-		"	} else if ( combine == 2 ) {",
-
-		"		gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;",
-
-		"	} else {",
-
-		"		gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );",
-
-		"	}",
-
-		"#endif"
-
-	].join("\n"),
-
-	envmap_pars_vertex: [
-
-		"#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )",
-
-		"	varying vec3 vReflect;",
-
-		"	uniform float refractionRatio;",
-		"	uniform bool useRefract;",
-
-		"#endif"
-
-	].join("\n"),
-
-	worldpos_vertex : [
-
-		"#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )",
-
-		"	#ifdef USE_SKINNING",
-
-		"		vec4 worldPosition = modelMatrix * skinned;",
-
-		"	#endif",
-
-		"	#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )",
-
-		"		vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );",
-
-		"	#endif",
-
-		"	#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )",
-
-		"		vec4 worldPosition = modelMatrix * vec4( position, 1.0 );",
-
-		"	#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	envmap_vertex : [
-
-		"#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )",
-
-		"	vec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;",
-		"	worldNormal = normalize( worldNormal );",
-
-		"	vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );",
-
-		"	if ( useRefract ) {",
-
-		"		vReflect = refract( cameraToVertex, worldNormal, refractionRatio );",
-
-		"	} else {",
-
-		"		vReflect = reflect( cameraToVertex, worldNormal );",
-
-		"	}",
-
-		"#endif"
-
-	].join("\n"),
-
-	// COLOR MAP (particles)
-
-	map_particle_pars_fragment: [
-
-		"#ifdef USE_MAP",
-
-		"	uniform sampler2D map;",
-
-		"#endif"
-
-	].join("\n"),
-
-
-	map_particle_fragment: [
-
-		"#ifdef USE_MAP",
-
-		"	gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );",
-
-		"#endif"
-
-	].join("\n"),
-
-	// COLOR MAP (triangles)
-
-	map_pars_vertex: [
-
-		"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )",
-
-		"	varying vec2 vUv;",
-		"	uniform vec4 offsetRepeat;",
-
-		"#endif"
-
-	].join("\n"),
-
-	map_pars_fragment: [
-
-		"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )",
-
-		"	varying vec2 vUv;",
-
-		"#endif",
-
-		"#ifdef USE_MAP",
-
-		"	uniform sampler2D map;",
-
-		"#endif"
-
-	].join("\n"),
-
-	map_vertex: [
-
-		"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )",
-
-		"	vUv = uv * offsetRepeat.zw + offsetRepeat.xy;",
-
-		"#endif"
-
-	].join("\n"),
-
-	map_fragment: [
-
-		"#ifdef USE_MAP",
-
-		"	vec4 texelColor = texture2D( map, vUv );",
-
-		"	#ifdef GAMMA_INPUT",
-
-		"		texelColor.xyz *= texelColor.xyz;",
-
-		"	#endif",
-
-		"	gl_FragColor = gl_FragColor * texelColor;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// LIGHT MAP
-
-	lightmap_pars_fragment: [
-
-		"#ifdef USE_LIGHTMAP",
-
-		"	varying vec2 vUv2;",
-		"	uniform sampler2D lightMap;",
-
-		"#endif"
-
-	].join("\n"),
-
-	lightmap_pars_vertex: [
-
-		"#ifdef USE_LIGHTMAP",
-
-		"	varying vec2 vUv2;",
-
-		"#endif"
-
-	].join("\n"),
-
-	lightmap_fragment: [
-
-		"#ifdef USE_LIGHTMAP",
-
-		"	gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );",
-
-		"#endif"
-
-	].join("\n"),
-
-	lightmap_vertex: [
-
-		"#ifdef USE_LIGHTMAP",
-
-		"	vUv2 = uv2;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// BUMP MAP
-
-	bumpmap_pars_fragment: [
-
-		"#ifdef USE_BUMPMAP",
-
-		"	uniform sampler2D bumpMap;",
-		"	uniform float bumpScale;",
-
-			// Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen
-			//	http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html
-
-			// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)
-
-		"	vec2 dHdxy_fwd() {",
-
-		"		vec2 dSTdx = dFdx( vUv );",
-		"		vec2 dSTdy = dFdy( vUv );",
-
-		"		float Hll = bumpScale * texture2D( bumpMap, vUv ).x;",
-		"		float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;",
-		"		float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;",
-
-		"		return vec2( dBx, dBy );",
-
-		"	}",
-
-		"	vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {",
-
-		"		vec3 vSigmaX = dFdx( surf_pos );",
-		"		vec3 vSigmaY = dFdy( surf_pos );",
-		"		vec3 vN = surf_norm;",		// normalized
-
-		"		vec3 R1 = cross( vSigmaY, vN );",
-		"		vec3 R2 = cross( vN, vSigmaX );",
-
-		"		float fDet = dot( vSigmaX, R1 );",
-
-		"		vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );",
-		"		return normalize( abs( fDet ) * surf_norm - vGrad );",
-
-		"	}",
-
-		"#endif"
-
-	].join("\n"),
-
-	// NORMAL MAP
-
-	normalmap_pars_fragment: [
-
-		"#ifdef USE_NORMALMAP",
-
-		"	uniform sampler2D normalMap;",
-		"	uniform vec2 normalScale;",
-
-			// Per-Pixel Tangent Space Normal Mapping
-			// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html
-
-		"	vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {",
-
-		"		vec3 q0 = dFdx( eye_pos.xyz );",
-		"		vec3 q1 = dFdy( eye_pos.xyz );",
-		"		vec2 st0 = dFdx( vUv.st );",
-		"		vec2 st1 = dFdy( vUv.st );",
-
-		"		vec3 S = normalize( q0 * st1.t - q1 * st0.t );",
-		"		vec3 T = normalize( -q0 * st1.s + q1 * st0.s );",
-		"		vec3 N = normalize( surf_norm );",
-
-		"		vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;",
-		"		mapN.xy = normalScale * mapN.xy;",
-		"		mat3 tsn = mat3( S, T, N );",
-		"		return normalize( tsn * mapN );",
-
-		"	}",
-
-		"#endif"
-
-	].join("\n"),
-
-	// SPECULAR MAP
-
-	specularmap_pars_fragment: [
-
-		"#ifdef USE_SPECULARMAP",
-
-		"	uniform sampler2D specularMap;",
-
-		"#endif"
-
-	].join("\n"),
-
-	specularmap_fragment: [
-
-		"float specularStrength;",
-
-		"#ifdef USE_SPECULARMAP",
-
-		"	vec4 texelSpecular = texture2D( specularMap, vUv );",
-		"	specularStrength = texelSpecular.r;",
-
-		"#else",
-
-		"	specularStrength = 1.0;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// ALPHA MAP
-
-	alphamap_pars_fragment: [
-
-		"#ifdef USE_ALPHAMAP",
-
-		"	uniform sampler2D alphaMap;",
-
-		"#endif"
-
-	].join("\n"),
-
-	alphamap_fragment: [
-
-		"#ifdef USE_ALPHAMAP",
-
-		"	gl_FragColor.a *= texture2D( alphaMap, vUv ).g;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// LIGHTS LAMBERT
-
-	lights_lambert_pars_vertex: [
-
-		"uniform vec3 ambient;",
-		"uniform vec3 diffuse;",
-		"uniform vec3 emissive;",
-
-		"uniform vec3 ambientLightColor;",
-
-		"#if MAX_DIR_LIGHTS > 0",
-
-		"	uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
-		"	uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
-
-		"#endif",
-
-		"#if MAX_HEMI_LIGHTS > 0",
-
-		"	uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];",
-		"	uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];",
-		"	uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];",
-
-		"#endif",
-
-		"#if MAX_POINT_LIGHTS > 0",
-
-		"	uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
-		"	uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
-		"	uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0",
-
-		"	uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];",
-		"	uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
-		"	uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];",
-		"	uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",
-		"	uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];",
-		"	uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];",
-
-		"#endif",
-
-		"#ifdef WRAP_AROUND",
-
-		"	uniform vec3 wrapRGB;",
-
-		"#endif"
-
-	].join("\n"),
-
-	lights_lambert_vertex: [
-
-		"vLightFront = vec3( 0.0 );",
-
-		"#ifdef DOUBLE_SIDED",
-
-		"	vLightBack = vec3( 0.0 );",
-
-		"#endif",
-
-		"transformedNormal = normalize( transformedNormal );",
-
-		"#if MAX_DIR_LIGHTS > 0",
-
-		"for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {",
-
-		"	vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
-		"	vec3 dirVector = normalize( lDirection.xyz );",
-
-		"	float dotProduct = dot( transformedNormal, dirVector );",
-		"	vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );",
-
-		"	#ifdef DOUBLE_SIDED",
-
-		"		vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",
-
-		"		#ifdef WRAP_AROUND",
-
-		"			vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",
-
-		"		#endif",
-
-		"	#endif",
-
-		"	#ifdef WRAP_AROUND",
-
-		"		vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
-		"		directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );",
-
-		"		#ifdef DOUBLE_SIDED",
-
-		"			directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );",
-
-		"		#endif",
-
-		"	#endif",
-
-		"	vLightFront += directionalLightColor[ i ] * directionalLightWeighting;",
-
-		"	#ifdef DOUBLE_SIDED",
-
-		"		vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;",
-
-		"	#endif",
-
-		"}",
-
-		"#endif",
-
-		"#if MAX_POINT_LIGHTS > 0",
-
-		"	for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
-
-		"		vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
-		"		vec3 lVector = lPosition.xyz - mvPosition.xyz;",
-
-		"		float lDistance = 1.0;",
-		"		if ( pointLightDistance[ i ] > 0.0 )",
-		"			lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
-
-		"		lVector = normalize( lVector );",
-		"		float dotProduct = dot( transformedNormal, lVector );",
-
-		"		vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );",
-
-		"		#ifdef DOUBLE_SIDED",
-
-		"			vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",
-
-		"			#ifdef WRAP_AROUND",
-
-		"				vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",
-
-		"			#endif",
-
-		"		#endif",
-
-		"		#ifdef WRAP_AROUND",
-
-		"			vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
-		"			pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );",
-
-		"			#ifdef DOUBLE_SIDED",
-
-		"				pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );",
-
-		"			#endif",
-
-		"		#endif",
-
-		"		vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;",
-
-		"		#ifdef DOUBLE_SIDED",
-
-		"			vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;",
-
-		"		#endif",
-
-		"	}",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0",
-
-		"	for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",
-
-		"		vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
-		"		vec3 lVector = lPosition.xyz - mvPosition.xyz;",
-
-		"		float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );",
-
-		"		if ( spotEffect > spotLightAngleCos[ i ] ) {",
-
-		"			spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );",
-
-		"			float lDistance = 1.0;",
-		"			if ( spotLightDistance[ i ] > 0.0 )",
-		"				lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );",
-
-		"			lVector = normalize( lVector );",
-
-		"			float dotProduct = dot( transformedNormal, lVector );",
-		"			vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );",
-
-		"			#ifdef DOUBLE_SIDED",
-
-		"				vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );",
-
-		"				#ifdef WRAP_AROUND",
-
-		"					vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );",
-
-		"				#endif",
-
-		"			#endif",
-
-		"			#ifdef WRAP_AROUND",
-
-		"				vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );",
-		"				spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );",
-
-		"				#ifdef DOUBLE_SIDED",
-
-		"					spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );",
-
-		"				#endif",
-
-		"			#endif",
-
-		"			vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;",
-
-		"			#ifdef DOUBLE_SIDED",
-
-		"				vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;",
-
-		"			#endif",
-
-		"		}",
-
-		"	}",
-
-		"#endif",
-
-		"#if MAX_HEMI_LIGHTS > 0",
-
-		"	for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
-
-		"		vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );",
-		"		vec3 lVector = normalize( lDirection.xyz );",
-
-		"		float dotProduct = dot( transformedNormal, lVector );",
-
-		"		float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
-		"		float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;",
-
-		"		vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
-
-		"		#ifdef DOUBLE_SIDED",
-
-		"			vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );",
-
-		"		#endif",
-
-		"	}",
-
-		"#endif",
-
-		"vLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;",
-
-		"#ifdef DOUBLE_SIDED",
-
-		"	vLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// LIGHTS PHONG
-
-	lights_phong_pars_vertex: [
-
-		"#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )",
-
-		"	varying vec3 vWorldPosition;",
-
-		"#endif"
-
-	].join("\n"),
-
-
-	lights_phong_vertex: [
-
-		"#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )",
-
-		"	vWorldPosition = worldPosition.xyz;",
-
-		"#endif"
-
-	].join("\n"),
-
-	lights_phong_pars_fragment: [
-
-		"uniform vec3 ambientLightColor;",
-
-		"#if MAX_DIR_LIGHTS > 0",
-
-		"	uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
-		"	uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
-
-		"#endif",
-
-		"#if MAX_HEMI_LIGHTS > 0",
-
-		"	uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];",
-		"	uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];",
-		"	uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];",
-
-		"#endif",
-
-		"#if MAX_POINT_LIGHTS > 0",
-
-		"	uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
-
-		"	uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
-		"	uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0",
-
-		"	uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];",
-		"	uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];",
-		"	uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];",
-		"	uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];",
-		"	uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];",
-
-		"	uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )",
-
-		"	varying vec3 vWorldPosition;",
-
-		"#endif",
-
-		"#ifdef WRAP_AROUND",
-
-		"	uniform vec3 wrapRGB;",
-
-		"#endif",
-
-		"varying vec3 vViewPosition;",
-		"varying vec3 vNormal;"
-
-	].join("\n"),
-
-	lights_phong_fragment: [
-
-		"vec3 normal = normalize( vNormal );",
-		"vec3 viewPosition = normalize( vViewPosition );",
-
-		"#ifdef DOUBLE_SIDED",
-
-		"	normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );",
-
-		"#endif",
-
-		"#ifdef USE_NORMALMAP",
-
-		"	normal = perturbNormal2Arb( -vViewPosition, normal );",
-
-		"#elif defined( USE_BUMPMAP )",
-
-		"	normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );",
-
-		"#endif",
-
-		"#if MAX_POINT_LIGHTS > 0",
-
-		"	vec3 pointDiffuse = vec3( 0.0 );",
-		"	vec3 pointSpecular = vec3( 0.0 );",
-
-		"	for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
-
-		"		vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
-		"		vec3 lVector = lPosition.xyz + vViewPosition.xyz;",
-
-		"		float lDistance = 1.0;",
-		"		if ( pointLightDistance[ i ] > 0.0 )",
-		"			lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
-
-		"		lVector = normalize( lVector );",
-
-				// diffuse
-
-		"		float dotProduct = dot( normal, lVector );",
-
-		"		#ifdef WRAP_AROUND",
-
-		"			float pointDiffuseWeightFull = max( dotProduct, 0.0 );",
-		"			float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );",
-
-		"			vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );",
-
-		"		#else",
-
-		"			float pointDiffuseWeight = max( dotProduct, 0.0 );",
-
-		"		#endif",
-
-		"		pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;",
-
-				// specular
-
-		"		vec3 pointHalfVector = normalize( lVector + viewPosition );",
-		"		float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );",
-		"		float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );",
-
-		"		float specularNormalization = ( shininess + 2.0 ) / 8.0;",
-
-		"		vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );",
-		"		pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;",
-
-		"	}",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0",
-
-		"	vec3 spotDiffuse = vec3( 0.0 );",
-		"	vec3 spotSpecular = vec3( 0.0 );",
-
-		"	for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",
-
-		"		vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
-		"		vec3 lVector = lPosition.xyz + vViewPosition.xyz;",
-
-		"		float lDistance = 1.0;",
-		"		if ( spotLightDistance[ i ] > 0.0 )",
-		"			lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );",
-
-		"		lVector = normalize( lVector );",
-
-		"		float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );",
-
-		"		if ( spotEffect > spotLightAngleCos[ i ] ) {",
-
-		"			spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );",
-
-					// diffuse
-
-		"			float dotProduct = dot( normal, lVector );",
-
-		"			#ifdef WRAP_AROUND",
-
-		"				float spotDiffuseWeightFull = max( dotProduct, 0.0 );",
-		"				float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );",
-
-		"				vec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );",
-
-		"			#else",
-
-		"				float spotDiffuseWeight = max( dotProduct, 0.0 );",
-
-		"			#endif",
-
-		"			spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;",
-
-					// specular
-
-		"			vec3 spotHalfVector = normalize( lVector + viewPosition );",
-		"			float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );",
-		"			float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );",
-
-		"			float specularNormalization = ( shininess + 2.0 ) / 8.0;",
-
-		"			vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );",
-		"			spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;",
-
-		"		}",
-
-		"	}",
-
-		"#endif",
-
-		"#if MAX_DIR_LIGHTS > 0",
-
-		"	vec3 dirDiffuse = vec3( 0.0 );",
-		"	vec3 dirSpecular = vec3( 0.0 );" ,
-
-		"	for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {",
-
-		"		vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
-		"		vec3 dirVector = normalize( lDirection.xyz );",
-
-				// diffuse
-
-		"		float dotProduct = dot( normal, dirVector );",
-
-		"		#ifdef WRAP_AROUND",
-
-		"			float dirDiffuseWeightFull = max( dotProduct, 0.0 );",
-		"			float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );",
-
-		"			vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );",
-
-		"		#else",
-
-		"			float dirDiffuseWeight = max( dotProduct, 0.0 );",
-
-		"		#endif",
-
-		"		dirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;",
-
-		// specular
-
-		"		vec3 dirHalfVector = normalize( dirVector + viewPosition );",
-		"		float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );",
-		"		float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );",
-
-		/*
-		// fresnel term from skin shader
-		"		const float F0 = 0.128;",
-
-		"		float base = 1.0 - dot( viewPosition, dirHalfVector );",
-		"		float exponential = pow( base, 5.0 );",
-
-		"		float fresnel = exponential + F0 * ( 1.0 - exponential );",
-		*/
-
-		/*
-		// fresnel term from fresnel shader
-		"		const float mFresnelBias = 0.08;",
-		"		const float mFresnelScale = 0.3;",
-		"		const float mFresnelPower = 5.0;",
-
-		"		float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );",
-		*/
-
-		"		float specularNormalization = ( shininess + 2.0 ) / 8.0;",
-
-		// "		dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;",
-
-		"		vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );",
-		"		dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;",
-
-
-		"	}",
-
-		"#endif",
-
-		"#if MAX_HEMI_LIGHTS > 0",
-
-		"	vec3 hemiDiffuse = vec3( 0.0 );",
-		"	vec3 hemiSpecular = vec3( 0.0 );" ,
-
-		"	for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
-
-		"		vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );",
-		"		vec3 lVector = normalize( lDirection.xyz );",
-
-		// diffuse
-
-		"		float dotProduct = dot( normal, lVector );",
-		"		float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
-
-		"		vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
-
-		"		hemiDiffuse += diffuse * hemiColor;",
-
-		// specular (sky light)
-
-		"		vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );",
-		"		float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;",
-		"		float hemiSpecularWeightSky = specularStrength * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );",
-
-		// specular (ground light)
-
-		"		vec3 lVectorGround = -lVector;",
-
-		"		vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );",
-		"		float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;",
-		"		float hemiSpecularWeightGround = specularStrength * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );",
-
-		"		float dotProductGround = dot( normal, lVectorGround );",
-
-		"		float specularNormalization = ( shininess + 2.0 ) / 8.0;",
-
-		"		vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );",
-		"		vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );",
-		"		hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );",
-
-		"	}",
-
-		"#endif",
-
-		"vec3 totalDiffuse = vec3( 0.0 );",
-		"vec3 totalSpecular = vec3( 0.0 );",
-
-		"#if MAX_DIR_LIGHTS > 0",
-
-		"	totalDiffuse += dirDiffuse;",
-		"	totalSpecular += dirSpecular;",
-
-		"#endif",
-
-		"#if MAX_HEMI_LIGHTS > 0",
-
-		"	totalDiffuse += hemiDiffuse;",
-		"	totalSpecular += hemiSpecular;",
-
-		"#endif",
-
-		"#if MAX_POINT_LIGHTS > 0",
-
-		"	totalDiffuse += pointDiffuse;",
-		"	totalSpecular += pointSpecular;",
-
-		"#endif",
-
-		"#if MAX_SPOT_LIGHTS > 0",
-
-		"	totalDiffuse += spotDiffuse;",
-		"	totalSpecular += spotSpecular;",
-
-		"#endif",
-
-		"#ifdef METAL",
-
-		"	gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );",
-
-		"#else",
-
-		"	gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// VERTEX COLORS
-
-	color_pars_fragment: [
-
-		"#ifdef USE_COLOR",
-
-		"	varying vec3 vColor;",
-
-		"#endif"
-
-	].join("\n"),
-
-
-	color_fragment: [
-
-		"#ifdef USE_COLOR",
-
-		"	gl_FragColor = gl_FragColor * vec4( vColor, 1.0 );",
-
-		"#endif"
-
-	].join("\n"),
-
-	color_pars_vertex: [
-
-		"#ifdef USE_COLOR",
-
-		"	varying vec3 vColor;",
-
-		"#endif"
-
-	].join("\n"),
-
-
-	color_vertex: [
-
-		"#ifdef USE_COLOR",
-
-		"	#ifdef GAMMA_INPUT",
-
-		"		vColor = color * color;",
-
-		"	#else",
-
-		"		vColor = color;",
-
-		"	#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	// SKINNING
-
-	skinning_pars_vertex: [
-
-		"#ifdef USE_SKINNING",
-
-		"	#ifdef BONE_TEXTURE",
-
-		"		uniform sampler2D boneTexture;",
-		"		uniform int boneTextureWidth;",
-		"		uniform int boneTextureHeight;",
-
-		"		mat4 getBoneMatrix( const in float i ) {",
-
-		"			float j = i * 4.0;",
-		"			float x = mod( j, float( boneTextureWidth ) );",
-		"			float y = floor( j / float( boneTextureWidth ) );",
-
-		"			float dx = 1.0 / float( boneTextureWidth );",
-		"			float dy = 1.0 / float( boneTextureHeight );",
-
-		"			y = dy * ( y + 0.5 );",
-
-		"			vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );",
-		"			vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );",
-		"			vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );",
-		"			vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );",
-
-		"			mat4 bone = mat4( v1, v2, v3, v4 );",
-
-		"			return bone;",
-
-		"		}",
-
-		"	#else",
-
-		"		uniform mat4 boneGlobalMatrices[ MAX_BONES ];",
-
-		"		mat4 getBoneMatrix( const in float i ) {",
-
-		"			mat4 bone = boneGlobalMatrices[ int(i) ];",
-		"			return bone;",
-
-		"		}",
-
-		"	#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	skinbase_vertex: [
-
-		"#ifdef USE_SKINNING",
-
-		"	mat4 boneMatX = getBoneMatrix( skinIndex.x );",
-		"	mat4 boneMatY = getBoneMatrix( skinIndex.y );",
-		"	mat4 boneMatZ = getBoneMatrix( skinIndex.z );",
-		"	mat4 boneMatW = getBoneMatrix( skinIndex.w );",
-
-		"#endif"
-
-	].join("\n"),
-
-	skinning_vertex: [
-
-		"#ifdef USE_SKINNING",
-
-		"	#ifdef USE_MORPHTARGETS",
-
-		"	vec4 skinVertex = vec4( morphed, 1.0 );",
-
-		"	#else",
-
-		"	vec4 skinVertex = vec4( position, 1.0 );",
-
-		"	#endif",
-
-		"	vec4 skinned = vec4( 0.0 );",
-		"	skinned += boneMatX * skinVertex * skinWeight.x;",
-		"	skinned += boneMatY * skinVertex * skinWeight.y;",
-		"	skinned += boneMatZ * skinVertex * skinWeight.z;",
-		"	skinned += boneMatW * skinVertex * skinWeight.w;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// MORPHING
-
-	morphtarget_pars_vertex: [
-
-		"#ifdef USE_MORPHTARGETS",
-
-		"	#ifndef USE_MORPHNORMALS",
-
-		"	uniform float morphTargetInfluences[ 8 ];",
-
-		"	#else",
-
-		"	uniform float morphTargetInfluences[ 4 ];",
-
-		"	#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	morphtarget_vertex: [
-
-		"#ifdef USE_MORPHTARGETS",
-
-		"	vec3 morphed = vec3( 0.0 );",
-		"	morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];",
-		"	morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];",
-		"	morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];",
-		"	morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];",
-
-		"	#ifndef USE_MORPHNORMALS",
-
-		"	morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];",
-		"	morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];",
-		"	morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];",
-		"	morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];",
-
-		"	#endif",
-
-		"	morphed += position;",
-
-		"#endif"
-
-	].join("\n"),
-
-	default_vertex : [
-
-		"vec4 mvPosition;",
-
-		"#ifdef USE_SKINNING",
-
-		"	mvPosition = modelViewMatrix * skinned;",
-
-		"#endif",
-
-		"#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )",
-
-		"	mvPosition = modelViewMatrix * vec4( morphed, 1.0 );",
-
-		"#endif",
-
-		"#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )",
-
-		"	mvPosition = modelViewMatrix * vec4( position, 1.0 );",
-
-		"#endif",
-
-		"gl_Position = projectionMatrix * mvPosition;"
-
-	].join("\n"),
-
-	morphnormal_vertex: [
-
-		"#ifdef USE_MORPHNORMALS",
-
-		"	vec3 morphedNormal = vec3( 0.0 );",
-
-		"	morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];",
-		"	morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];",
-		"	morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];",
-		"	morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];",
-
-		"	morphedNormal += normal;",
-
-		"#endif"
-
-	].join("\n"),
-
-	skinnormal_vertex: [
-
-		"#ifdef USE_SKINNING",
-
-		"	mat4 skinMatrix = mat4( 0.0 );",
-		"	skinMatrix += skinWeight.x * boneMatX;",
-		"	skinMatrix += skinWeight.y * boneMatY;",
-		"	skinMatrix += skinWeight.z * boneMatZ;",
-		"	skinMatrix += skinWeight.w * boneMatW;",
-
-		"	#ifdef USE_MORPHNORMALS",
-
-		"	vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );",
-
-		"	#else",
-
-		"	vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );",
-
-		"	#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	defaultnormal_vertex: [
-
-		"vec3 objectNormal;",
-
-		"#ifdef USE_SKINNING",
-
-		"	objectNormal = skinnedNormal.xyz;",
-
-		"#endif",
-
-		"#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )",
-
-		"	objectNormal = morphedNormal;",
-
-		"#endif",
-
-		"#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )",
-
-		"	objectNormal = normal;",
-
-		"#endif",
-
-		"#ifdef FLIP_SIDED",
-
-		"	objectNormal = -objectNormal;",
-
-		"#endif",
-
-		"vec3 transformedNormal = normalMatrix * objectNormal;"
-
-	].join("\n"),
-
-	// SHADOW MAP
-
-	// based on SpiderGL shadow map and Fabien Sanglard's GLSL shadow mapping examples
-	// http://spidergl.org/example.php?id=6
-	// http://fabiensanglard.net/shadowmapping
-
-	shadowmap_pars_fragment: [
-
-		"#ifdef USE_SHADOWMAP",
-
-		"	uniform sampler2D shadowMap[ MAX_SHADOWS ];",
-		"	uniform vec2 shadowMapSize[ MAX_SHADOWS ];",
-
-		"	uniform float shadowDarkness[ MAX_SHADOWS ];",
-		"	uniform float shadowBias[ MAX_SHADOWS ];",
-
-		"	varying vec4 vShadowCoord[ MAX_SHADOWS ];",
-
-		"	float unpackDepth( const in vec4 rgba_depth ) {",
-
-		"		const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );",
-		"		float depth = dot( rgba_depth, bit_shift );",
-		"		return depth;",
-
-		"	}",
-
-		"#endif"
-
-	].join("\n"),
-
-	shadowmap_fragment: [
-
-		"#ifdef USE_SHADOWMAP",
-
-		"	#ifdef SHADOWMAP_DEBUG",
-
-		"		vec3 frustumColors[3];",
-		"		frustumColors[0] = vec3( 1.0, 0.5, 0.0 );",
-		"		frustumColors[1] = vec3( 0.0, 1.0, 0.8 );",
-		"		frustumColors[2] = vec3( 0.0, 0.5, 1.0 );",
-
-		"	#endif",
-
-		"	#ifdef SHADOWMAP_CASCADE",
-
-		"		int inFrustumCount = 0;",
-
-		"	#endif",
-
-		"	float fDepth;",
-		"	vec3 shadowColor = vec3( 1.0 );",
-
-		"	for( int i = 0; i < MAX_SHADOWS; i ++ ) {",
-
-		"		vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;",
-
-				// "if ( something && something )" breaks ATI OpenGL shader compiler
-				// "if ( all( something, something ) )" using this instead
-
-		"		bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );",
-		"		bool inFrustum = all( inFrustumVec );",
-
-				// don't shadow pixels outside of light frustum
-				// use just first frustum (for cascades)
-				// don't shadow pixels behind far plane of light frustum
-
-		"		#ifdef SHADOWMAP_CASCADE",
-
-		"			inFrustumCount += int( inFrustum );",
-		"			bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );",
-
-		"		#else",
-
-		"			bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );",
-
-		"		#endif",
-
-		"		bool frustumTest = all( frustumTestVec );",
-
-		"		if ( frustumTest ) {",
-
-		"			shadowCoord.z += shadowBias[ i ];",
-
-		"			#if defined( SHADOWMAP_TYPE_PCF )",
-
-						// Percentage-close filtering
-						// (9 pixel kernel)
-						// http://fabiensanglard.net/shadowmappingPCF/
-
-		"				float shadow = 0.0;",
-
-		/*
-						// nested loops breaks shader compiler / validator on some ATI cards when using OpenGL
-						// must enroll loop manually
-
-		"				for ( float y = -1.25; y <= 1.25; y += 1.25 )",
-		"					for ( float x = -1.25; x <= 1.25; x += 1.25 ) {",
-
-		"						vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );",
-
-								// doesn't seem to produce any noticeable visual difference compared to simple "texture2D" lookup
-								//"vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );",
-
-		"						float fDepth = unpackDepth( rgbaDepth );",
-
-		"						if ( fDepth < shadowCoord.z )",
-		"							shadow += 1.0;",
-
-		"				}",
-
-		"				shadow /= 9.0;",
-
-		*/
-
-		"				const float shadowDelta = 1.0 / 9.0;",
-
-		"				float xPixelOffset = 1.0 / shadowMapSize[ i ].x;",
-		"				float yPixelOffset = 1.0 / shadowMapSize[ i ].y;",
-
-		"				float dx0 = -1.25 * xPixelOffset;",
-		"				float dy0 = -1.25 * yPixelOffset;",
-		"				float dx1 = 1.25 * xPixelOffset;",
-		"				float dy1 = 1.25 * yPixelOffset;",
-
-		"				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );",
-		"				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-		"				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );",
-		"				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-		"				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );",
-		"				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-		"				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );",
-		"				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-		"				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );",
-		"				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-		"				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );",
-		"				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-		"				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );",
-		"				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-		"				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );",
-		"				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-		"				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );",
-		"				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;",
-
-		"				shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );",
-
-		"			#elif defined( SHADOWMAP_TYPE_PCF_SOFT )",
-
-						// Percentage-close filtering
-						// (9 pixel kernel)
-						// http://fabiensanglard.net/shadowmappingPCF/
-
-		"				float shadow = 0.0;",
-
-		"				float xPixelOffset = 1.0 / shadowMapSize[ i ].x;",
-		"				float yPixelOffset = 1.0 / shadowMapSize[ i ].y;",
-
-		"				float dx0 = -1.0 * xPixelOffset;",
-		"				float dy0 = -1.0 * yPixelOffset;",
-		"				float dx1 = 1.0 * xPixelOffset;",
-		"				float dy1 = 1.0 * yPixelOffset;",
-
-		"				mat3 shadowKernel;",
-		"				mat3 depthKernel;",
-
-		"				depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );",
-		"				depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );",
-		"				depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );",
-		"				depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );",
-		"				depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );",
-		"				depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );",
-		"				depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );",
-		"				depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );",
-		"				depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );",
-
-		"				vec3 shadowZ = vec3( shadowCoord.z );",
-		"				shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));",
-		"				shadowKernel[0] *= vec3(0.25);",
-
-		"				shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));",
-		"				shadowKernel[1] *= vec3(0.25);",
-
-		"				shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));",
-		"				shadowKernel[2] *= vec3(0.25);",
-
-		"				vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );",
-
-		"				shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );",
-		"				shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );",
-
-		"				vec4 shadowValues;",
-		"				shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );",
-		"				shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );",
-		"				shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );",
-		"				shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );",
-
-		"				shadow = dot( shadowValues, vec4( 1.0 ) );",
-
-		"				shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );",
-
-		"			#else",
-
-		"				vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );",
-		"				float fDepth = unpackDepth( rgbaDepth );",
-
-		"				if ( fDepth < shadowCoord.z )",
-
-		// spot with multiple shadows is darker
-
-		"					shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );",
-
-		// spot with multiple shadows has the same color as single shadow spot
-
-		// "					shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );",
-
-		"			#endif",
-
-		"		}",
-
-
-		"		#ifdef SHADOWMAP_DEBUG",
-
-		"			#ifdef SHADOWMAP_CASCADE",
-
-		"				if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];",
-
-		"			#else",
-
-		"				if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];",
-
-		"			#endif",
-
-		"		#endif",
-
-		"	}",
-
-		"	#ifdef GAMMA_OUTPUT",
-
-		"		shadowColor *= shadowColor;",
-
-		"	#endif",
-
-		"	gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;",
-
-		"#endif"
-
-	].join("\n"),
-
-	shadowmap_pars_vertex: [
-
-		"#ifdef USE_SHADOWMAP",
-
-		"	varying vec4 vShadowCoord[ MAX_SHADOWS ];",
-		"	uniform mat4 shadowMatrix[ MAX_SHADOWS ];",
-
-		"#endif"
-
-	].join("\n"),
-
-	shadowmap_vertex: [
-
-		"#ifdef USE_SHADOWMAP",
-
-		"	for( int i = 0; i < MAX_SHADOWS; i ++ ) {",
-
-		"		vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;",
-
-		"	}",
-
-		"#endif"
-
-	].join("\n"),
-
-	// ALPHATEST
-
-	alphatest_fragment: [
-
-		"#ifdef ALPHATEST",
-
-		"	if ( gl_FragColor.a < ALPHATEST ) discard;",
-
-		"#endif"
-
-	].join("\n"),
-
-	// LINEAR SPACE
-
-	linear_to_gamma_fragment: [
-
-		"#ifdef GAMMA_OUTPUT",
-
-		"	gl_FragColor.xyz = sqrt( gl_FragColor.xyz );",
-
-		"#endif"
-
-	].join("\n"),
-
-	// LOGARITHMIC DEPTH BUFFER
-	// http://outerra.blogspot.com/2012/11/maximizing-depth-buffer-range-and.html
-
-	// WebGL doesn't support gl_FragDepth out of the box, unless the EXT_frag_depth extension is available.  On platforms
-	// without EXT_frag_depth, we have to fall back on linear z-buffer in the fragment shader, which means that some long
-	// faces close to the camera may have issues.	This can be worked around by tesselating the model more finely when
-	// the camera is near the surface.
-
-	logdepthbuf_pars_vertex: [
-
-		"#ifdef USE_LOGDEPTHBUF",
-
-		"	#ifdef USE_LOGDEPTHBUF_EXT",
-
-		"		varying float vFragDepth;",
-
-		"	#endif",
-
-		"	uniform float logDepthBufFC;",
-
-		"#endif",
-
-	].join('\n'),
-
-	logdepthbuf_vertex: [
-
-		"#ifdef USE_LOGDEPTHBUF",
-
-		"	gl_Position.z = log2(max(1e-6, gl_Position.w + 1.0)) * logDepthBufFC;",
-
-		"	#ifdef USE_LOGDEPTHBUF_EXT",
-
-		"		vFragDepth = 1.0 + gl_Position.w;",
-
-		"#else",
-
-		"		gl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;",
-
-		"	#endif",
-
-		"#endif"
-
-	].join("\n"),
-
-	logdepthbuf_pars_fragment: [
-
-		"#ifdef USE_LOGDEPTHBUF",
-
-		"	uniform float logDepthBufFC;",
-
-		"	#ifdef USE_LOGDEPTHBUF_EXT",
-
-		"		#extension GL_EXT_frag_depth : enable",
-		"		varying float vFragDepth;",
-
-		"	#endif",
-
-		"#endif"
-
-	].join('\n'),
-
-	logdepthbuf_fragment: [
-
-		"#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)",
-
-		"	gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;",
-
-		"#endif"
-
-	].join("\n")
-
-};
+THREE.ShaderChunk = {};

+ 5 - 0
src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl

@@ -0,0 +1,5 @@
+#ifdef USE_ALPHAMAP
+
+	gl_FragColor.a *= texture2D( alphaMap, vUv ).g;
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/alphamap_pars_fragment.glsl

@@ -0,0 +1,5 @@
+#ifdef USE_ALPHAMAP
+
+	uniform sampler2D alphaMap;
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl

@@ -0,0 +1,5 @@
+#ifdef ALPHATEST
+
+	if ( gl_FragColor.a < ALPHATEST ) discard;
+
+#endif

+ 40 - 0
src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl

@@ -0,0 +1,40 @@
+#ifdef USE_BUMPMAP
+
+	uniform sampler2D bumpMap;
+	uniform float bumpScale;
+
+			// Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen
+			//	http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html
+
+			// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)
+
+	vec2 dHdxy_fwd() {
+
+		vec2 dSTdx = dFdx( vUv );
+		vec2 dSTdy = dFdy( vUv );
+
+		float Hll = bumpScale * texture2D( bumpMap, vUv ).x;
+		float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;
+		float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;
+
+		return vec2( dBx, dBy );
+
+	}
+
+	vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {
+
+		vec3 vSigmaX = dFdx( surf_pos );
+		vec3 vSigmaY = dFdy( surf_pos );
+		vec3 vN = surf_norm;		// normalized
+
+		vec3 R1 = cross( vSigmaY, vN );
+		vec3 R2 = cross( vN, vSigmaX );
+
+		float fDet = dot( vSigmaX, R1 );
+
+		vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );
+		return normalize( abs( fDet ) * surf_norm - vGrad );
+
+	}
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/color_fragment.glsl

@@ -0,0 +1,5 @@
+#ifdef USE_COLOR
+
+	gl_FragColor = gl_FragColor * vec4( vColor, 1.0 );
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl

@@ -0,0 +1,5 @@
+#ifdef USE_COLOR
+
+	varying vec3 vColor;
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl

@@ -0,0 +1,5 @@
+#ifdef USE_COLOR
+
+	varying vec3 vColor;
+
+#endif

+ 13 - 0
src/renderers/shaders/ShaderChunk/color_vertex.glsl

@@ -0,0 +1,13 @@
+#ifdef USE_COLOR
+
+	#ifdef GAMMA_INPUT
+
+		vColor = color * color;
+
+	#else
+
+		vColor = color;
+
+	#endif
+
+#endif

+ 21 - 0
src/renderers/shaders/ShaderChunk/default_vertex.glsl

@@ -0,0 +1,21 @@
+vec4 mvPosition;
+
+#ifdef USE_SKINNING
+
+	mvPosition = modelViewMatrix * skinned;
+
+#endif
+
+#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )
+
+	mvPosition = modelViewMatrix * vec4( morphed, 1.0 );
+
+#endif
+
+#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )
+
+	mvPosition = modelViewMatrix * vec4( position, 1.0 );
+
+#endif
+
+gl_Position = projectionMatrix * mvPosition;

+ 27 - 0
src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl

@@ -0,0 +1,27 @@
+vec3 objectNormal;
+
+#ifdef USE_SKINNING
+
+	objectNormal = skinnedNormal.xyz;
+
+#endif
+
+#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )
+
+	objectNormal = morphedNormal;
+
+#endif
+
+#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )
+
+	objectNormal = normal;
+
+#endif
+
+#ifdef FLIP_SIDED
+
+	objectNormal = -objectNormal;
+
+#endif
+
+vec3 transformedNormal = normalMatrix * objectNormal;

+ 61 - 0
src/renderers/shaders/ShaderChunk/envmap_fragment.glsl

@@ -0,0 +1,61 @@
+#ifdef USE_ENVMAP
+
+	vec3 reflectVec;
+
+	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )
+
+		vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );
+
+		// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations
+		// Transforming Normal Vectors with the Inverse Transformation
+
+		vec3 worldNormal = normalize( vec3( vec4( normal, 0.0 ) * viewMatrix ) );
+
+		if ( useRefract ) {
+
+			reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );
+
+		} else { 
+
+			reflectVec = reflect( cameraToVertex, worldNormal );
+
+		}
+
+	#else
+
+		reflectVec = vReflect;
+
+	#endif
+
+	#ifdef DOUBLE_SIDED
+
+		float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );
+		vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );
+
+	#else
+
+		vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );
+
+	#endif
+
+	#ifdef GAMMA_INPUT
+
+		cubeColor.xyz *= cubeColor.xyz;
+
+	#endif
+
+	if ( combine == 1 ) {
+
+		gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );
+
+	} else if ( combine == 2 ) {
+
+		gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;
+
+	} else {
+
+		gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );
+
+	}
+
+#endif

+ 19 - 0
src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl

@@ -0,0 +1,19 @@
+#ifdef USE_ENVMAP
+
+	uniform float reflectivity;
+	uniform samplerCube envMap;
+	uniform float flipEnvMap;
+	uniform int combine;
+
+	#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )
+
+		uniform bool useRefract;
+		uniform float refractionRatio;
+
+	#else
+
+		varying vec3 vReflect;
+
+	#endif
+
+#endif

+ 8 - 0
src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl

@@ -0,0 +1,8 @@
+#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )
+
+	varying vec3 vReflect;
+
+	uniform float refractionRatio;
+	uniform bool useRefract;
+
+#endif

+ 18 - 0
src/renderers/shaders/ShaderChunk/envmap_vertex.glsl

@@ -0,0 +1,18 @@
+#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )
+
+	vec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;
+	worldNormal = normalize( worldNormal );
+
+	vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );
+
+	if ( useRefract ) {
+
+		vReflect = refract( cameraToVertex, worldNormal, refractionRatio );
+
+	} else {
+
+		vReflect = reflect( cameraToVertex, worldNormal );
+
+	}
+
+#endif

+ 27 - 0
src/renderers/shaders/ShaderChunk/fog_fragment.glsl

@@ -0,0 +1,27 @@
+#ifdef USE_FOG
+
+	#ifdef USE_LOGDEPTHBUF_EXT
+
+		float depth = gl_FragDepthEXT / gl_FragCoord.w;
+
+	#else
+
+		float depth = gl_FragCoord.z / gl_FragCoord.w;
+
+	#endif
+
+	#ifdef FOG_EXP2
+
+		const float LOG2 = 1.442695;
+		float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );
+		fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );
+
+	#else
+
+		float fogFactor = smoothstep( fogNear, fogFar, depth );
+
+	#endif
+	
+	gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );
+
+#endif

+ 15 - 0
src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl

@@ -0,0 +1,15 @@
+#ifdef USE_FOG
+
+	uniform vec3 fogColor;
+
+	#ifdef FOG_EXP2
+
+		uniform float fogDensity;
+
+	#else
+
+		uniform float fogNear;
+		uniform float fogFar;
+	#endif
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl

@@ -0,0 +1,5 @@
+#ifdef USE_LIGHTMAP
+
+	gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );
+
+#endif

+ 6 - 0
src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl

@@ -0,0 +1,6 @@
+#ifdef USE_LIGHTMAP
+
+	varying vec2 vUv2;
+	uniform sampler2D lightMap;
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/lightmap_pars_vertex.glsl

@@ -0,0 +1,5 @@
+#ifdef USE_LIGHTMAP
+
+	varying vec2 vUv2;
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/lightmap_vertex.glsl

@@ -0,0 +1,5 @@
+#ifdef USE_LIGHTMAP
+
+	vUv2 = uv2;
+
+#endif

+ 45 - 0
src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl

@@ -0,0 +1,45 @@
+uniform vec3 ambient;
+uniform vec3 diffuse;
+uniform vec3 emissive;
+
+uniform vec3 ambientLightColor;
+
+#if MAX_DIR_LIGHTS > 0
+
+	uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];
+	uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];
+
+#endif
+
+#if MAX_HEMI_LIGHTS > 0
+
+	uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];
+	uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];
+	uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];
+
+#endif
+
+#if MAX_POINT_LIGHTS > 0
+
+	uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];
+	uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];
+	uniform float pointLightDistance[ MAX_POINT_LIGHTS ];
+
+#endif
+
+#if MAX_SPOT_LIGHTS > 0
+
+	uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];
+	uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];
+	uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];
+	uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];
+	uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];
+	uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];
+
+#endif
+
+#ifdef WRAP_AROUND
+
+	uniform vec3 wrapRGB;
+
+#endif

+ 202 - 0
src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl

@@ -0,0 +1,202 @@
+vLightFront = vec3( 0.0 );
+
+#ifdef DOUBLE_SIDED
+
+	vLightBack = vec3( 0.0 );
+
+#endif
+
+transformedNormal = normalize( transformedNormal );
+
+#if MAX_DIR_LIGHTS > 0
+
+for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
+
+	vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );
+	vec3 dirVector = normalize( lDirection.xyz );
+
+	float dotProduct = dot( transformedNormal, dirVector );
+	vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );
+
+	#ifdef DOUBLE_SIDED
+
+		vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );
+
+		#ifdef WRAP_AROUND
+
+			vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );
+
+		#endif
+
+	#endif
+
+	#ifdef WRAP_AROUND
+
+		vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );
+		directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );
+
+		#ifdef DOUBLE_SIDED
+
+			directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );
+
+		#endif
+
+	#endif
+
+	vLightFront += directionalLightColor[ i ] * directionalLightWeighting;
+
+	#ifdef DOUBLE_SIDED
+
+		vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;
+
+	#endif
+
+}
+
+#endif
+
+#if MAX_POINT_LIGHTS > 0
+
+	for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {
+
+		vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );
+		vec3 lVector = lPosition.xyz - mvPosition.xyz;
+
+		float lDistance = 1.0;
+		if ( pointLightDistance[ i ] > 0.0 )
+			lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );
+
+		lVector = normalize( lVector );
+		float dotProduct = dot( transformedNormal, lVector );
+
+		vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );
+
+		#ifdef DOUBLE_SIDED
+
+			vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );
+
+			#ifdef WRAP_AROUND
+
+				vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );
+
+			#endif
+
+		#endif
+
+		#ifdef WRAP_AROUND
+
+			vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );
+			pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );
+
+			#ifdef DOUBLE_SIDED
+
+				pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );
+
+			#endif
+
+		#endif
+
+		vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;
+
+		#ifdef DOUBLE_SIDED
+
+			vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;
+
+		#endif
+
+	}
+
+#endif
+
+#if MAX_SPOT_LIGHTS > 0
+
+	for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {
+
+		vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );
+		vec3 lVector = lPosition.xyz - mvPosition.xyz;
+
+		float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );
+
+		if ( spotEffect > spotLightAngleCos[ i ] ) {
+
+			spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );
+
+			float lDistance = 1.0;
+			if ( spotLightDistance[ i ] > 0.0 )
+				lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );
+
+			lVector = normalize( lVector );
+
+			float dotProduct = dot( transformedNormal, lVector );
+			vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );
+
+			#ifdef DOUBLE_SIDED
+
+				vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );
+
+				#ifdef WRAP_AROUND
+
+					vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );
+
+				#endif
+
+			#endif
+
+			#ifdef WRAP_AROUND
+
+				vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );
+				spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );
+
+				#ifdef DOUBLE_SIDED
+
+					spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );
+
+				#endif
+
+			#endif
+
+			vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;
+
+			#ifdef DOUBLE_SIDED
+
+				vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;
+
+			#endif
+
+		}
+
+	}
+
+#endif
+
+#if MAX_HEMI_LIGHTS > 0
+
+	for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {
+
+		vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );
+		vec3 lVector = normalize( lDirection.xyz );
+
+		float dotProduct = dot( transformedNormal, lVector );
+
+		float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;
+		float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;
+
+		vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );
+
+		#ifdef DOUBLE_SIDED
+
+			vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );
+
+		#endif
+
+	}
+
+#endif
+
+vLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;
+
+#ifdef DOUBLE_SIDED
+
+	vLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;
+
+#endif

+ 278 - 0
src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl

@@ -0,0 +1,278 @@
+vec3 normal = normalize( vNormal );
+vec3 viewPosition = normalize( vViewPosition );
+
+#ifdef DOUBLE_SIDED
+
+	normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );
+
+#endif
+
+#ifdef USE_NORMALMAP
+
+	normal = perturbNormal2Arb( -vViewPosition, normal );
+
+#elif defined( USE_BUMPMAP )
+
+	normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );
+
+#endif
+
+#if MAX_POINT_LIGHTS > 0
+
+	vec3 pointDiffuse = vec3( 0.0 );
+	vec3 pointSpecular = vec3( 0.0 );
+
+	for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {
+
+		vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );
+		vec3 lVector = lPosition.xyz + vViewPosition.xyz;
+
+		float lDistance = 1.0;
+		if ( pointLightDistance[ i ] > 0.0 )
+			lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );
+
+		lVector = normalize( lVector );
+
+				// diffuse
+
+		float dotProduct = dot( normal, lVector );
+
+		#ifdef WRAP_AROUND
+
+			float pointDiffuseWeightFull = max( dotProduct, 0.0 );
+			float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );
+
+			vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );
+
+		#else
+
+			float pointDiffuseWeight = max( dotProduct, 0.0 );
+
+		#endif
+
+		pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;
+
+				// specular
+
+		vec3 pointHalfVector = normalize( lVector + viewPosition );
+		float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );
+		float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );
+
+		float specularNormalization = ( shininess + 2.0 ) / 8.0;
+
+		vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );
+		pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;
+
+	}
+
+#endif
+
+#if MAX_SPOT_LIGHTS > 0
+
+	vec3 spotDiffuse = vec3( 0.0 );
+	vec3 spotSpecular = vec3( 0.0 );
+
+	for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {
+
+		vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );
+		vec3 lVector = lPosition.xyz + vViewPosition.xyz;
+
+		float lDistance = 1.0;
+		if ( spotLightDistance[ i ] > 0.0 )
+			lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );
+
+		lVector = normalize( lVector );
+
+		float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );
+
+		if ( spotEffect > spotLightAngleCos[ i ] ) {
+
+			spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );
+
+					// diffuse
+
+			float dotProduct = dot( normal, lVector );
+
+			#ifdef WRAP_AROUND
+
+				float spotDiffuseWeightFull = max( dotProduct, 0.0 );
+				float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );
+
+				vec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );
+
+			#else
+
+				float spotDiffuseWeight = max( dotProduct, 0.0 );
+
+			#endif
+
+			spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;
+
+					// specular
+
+			vec3 spotHalfVector = normalize( lVector + viewPosition );
+			float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );
+			float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );
+
+			float specularNormalization = ( shininess + 2.0 ) / 8.0;
+
+			vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );
+			spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;
+
+		}
+
+	}
+
+#endif
+
+#if MAX_DIR_LIGHTS > 0
+
+	vec3 dirDiffuse = vec3( 0.0 );
+	vec3 dirSpecular = vec3( 0.0 );
+
+	for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
+
+		vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );
+		vec3 dirVector = normalize( lDirection.xyz );
+
+				// diffuse
+
+		float dotProduct = dot( normal, dirVector );
+
+		#ifdef WRAP_AROUND
+
+			float dirDiffuseWeightFull = max( dotProduct, 0.0 );
+			float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );
+
+			vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );
+
+		#else
+
+			float dirDiffuseWeight = max( dotProduct, 0.0 );
+
+		#endif
+
+		dirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;
+
+		// specular
+
+		vec3 dirHalfVector = normalize( dirVector + viewPosition );
+		float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );
+		float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );
+
+		/*
+		// fresnel term from skin shader
+		const float F0 = 0.128;
+
+		float base = 1.0 - dot( viewPosition, dirHalfVector );
+		float exponential = pow( base, 5.0 );
+
+		float fresnel = exponential + F0 * ( 1.0 - exponential );
+		*/
+
+		/*
+		// fresnel term from fresnel shader
+		const float mFresnelBias = 0.08;
+		const float mFresnelScale = 0.3;
+		const float mFresnelPower = 5.0;
+
+		float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );
+		*/
+
+		float specularNormalization = ( shininess + 2.0 ) / 8.0;
+
+		// 		dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;
+
+		vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );
+		dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;
+
+
+	}
+
+#endif
+
+#if MAX_HEMI_LIGHTS > 0
+
+	vec3 hemiDiffuse = vec3( 0.0 );
+	vec3 hemiSpecular = vec3( 0.0 );
+
+	for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {
+
+		vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );
+		vec3 lVector = normalize( lDirection.xyz );
+
+		// diffuse
+
+		float dotProduct = dot( normal, lVector );
+		float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;
+
+		vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );
+
+		hemiDiffuse += diffuse * hemiColor;
+
+		// specular (sky light)
+
+		vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );
+		float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;
+		float hemiSpecularWeightSky = specularStrength * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );
+
+		// specular (ground light)
+
+		vec3 lVectorGround = -lVector;
+
+		vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );
+		float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;
+		float hemiSpecularWeightGround = specularStrength * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );
+
+		float dotProductGround = dot( normal, lVectorGround );
+
+		float specularNormalization = ( shininess + 2.0 ) / 8.0;
+
+		vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );
+		vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );
+		hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );
+
+	}
+
+#endif
+
+vec3 totalDiffuse = vec3( 0.0 );
+vec3 totalSpecular = vec3( 0.0 );
+
+#if MAX_DIR_LIGHTS > 0
+
+	totalDiffuse += dirDiffuse;
+	totalSpecular += dirSpecular;
+
+#endif
+
+#if MAX_HEMI_LIGHTS > 0
+
+	totalDiffuse += hemiDiffuse;
+	totalSpecular += hemiSpecular;
+
+#endif
+
+#if MAX_POINT_LIGHTS > 0
+
+	totalDiffuse += pointDiffuse;
+	totalSpecular += pointSpecular;
+
+#endif
+
+#if MAX_SPOT_LIGHTS > 0
+
+	totalDiffuse += spotDiffuse;
+	totalSpecular += spotSpecular;
+
+#endif
+
+#ifdef METAL
+
+	gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );
+
+#else
+
+	gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;
+
+#endif

+ 52 - 0
src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl

@@ -0,0 +1,52 @@
+uniform vec3 ambientLightColor;
+
+#if MAX_DIR_LIGHTS > 0
+
+	uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];
+	uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];
+
+#endif
+
+#if MAX_HEMI_LIGHTS > 0
+
+	uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];
+	uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];
+	uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];
+
+#endif
+
+#if MAX_POINT_LIGHTS > 0
+
+	uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];
+
+	uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];
+	uniform float pointLightDistance[ MAX_POINT_LIGHTS ];
+
+#endif
+
+#if MAX_SPOT_LIGHTS > 0
+
+	uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];
+	uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];
+	uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];
+	uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];
+	uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];
+
+	uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];
+
+#endif
+
+#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )
+
+	varying vec3 vWorldPosition;
+
+#endif
+
+#ifdef WRAP_AROUND
+
+	uniform vec3 wrapRGB;
+
+#endif
+
+varying vec3 vViewPosition;
+varying vec3 vNormal;

+ 5 - 0
src/renderers/shaders/ShaderChunk/lights_phong_pars_vertex.glsl

@@ -0,0 +1,5 @@
+#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )
+
+	varying vec3 vWorldPosition;
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/lights_phong_vertex.glsl

@@ -0,0 +1,5 @@
+#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )
+
+	vWorldPosition = worldPosition.xyz;
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl

@@ -0,0 +1,5 @@
+#ifdef GAMMA_OUTPUT
+
+	gl_FragColor.xyz = sqrt( gl_FragColor.xyz );
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl

@@ -0,0 +1,5 @@
+#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)
+
+	gl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;
+
+#endif

+ 12 - 0
src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl

@@ -0,0 +1,12 @@
+#ifdef USE_LOGDEPTHBUF
+
+	uniform float logDepthBufFC;
+
+	#ifdef USE_LOGDEPTHBUF_EXT
+
+		#extension GL_EXT_frag_depth : enable
+		varying float vFragDepth;
+
+	#endif
+
+#endif

+ 11 - 0
src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl

@@ -0,0 +1,11 @@
+#ifdef USE_LOGDEPTHBUF
+
+	#ifdef USE_LOGDEPTHBUF_EXT
+
+		varying float vFragDepth;
+
+	#endif
+
+	uniform float logDepthBufFC;
+
+#endif

+ 15 - 0
src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl

@@ -0,0 +1,15 @@
+#ifdef USE_LOGDEPTHBUF
+
+	gl_Position.z = log2(max(1e-6, gl_Position.w + 1.0)) * logDepthBufFC;
+
+	#ifdef USE_LOGDEPTHBUF_EXT
+
+		vFragDepth = 1.0 + gl_Position.w;
+
+#else
+
+		gl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;
+
+	#endif
+
+#endif

+ 13 - 0
src/renderers/shaders/ShaderChunk/map_fragment.glsl

@@ -0,0 +1,13 @@
+#ifdef USE_MAP
+
+	vec4 texelColor = texture2D( map, vUv );
+
+	#ifdef GAMMA_INPUT
+
+		texelColor.xyz *= texelColor.xyz;
+
+	#endif
+
+	gl_FragColor = gl_FragColor * texelColor;
+
+#endif

+ 11 - 0
src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl

@@ -0,0 +1,11 @@
+#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )
+
+	varying vec2 vUv;
+
+#endif
+
+#ifdef USE_MAP
+
+	uniform sampler2D map;
+
+#endif

+ 6 - 0
src/renderers/shaders/ShaderChunk/map_pars_vertex.glsl

@@ -0,0 +1,6 @@
+#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )
+
+	varying vec2 vUv;
+	uniform vec4 offsetRepeat;
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl

@@ -0,0 +1,5 @@
+#ifdef USE_MAP
+
+	gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl

@@ -0,0 +1,5 @@
+#ifdef USE_MAP
+
+	uniform sampler2D map;
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/map_vertex.glsl

@@ -0,0 +1,5 @@
+#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )
+
+	vUv = uv * offsetRepeat.zw + offsetRepeat.xy;
+
+#endif

+ 12 - 0
src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl

@@ -0,0 +1,12 @@
+#ifdef USE_MORPHNORMALS
+
+	vec3 morphedNormal = vec3( 0.0 );
+
+	morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];
+	morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];
+	morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];
+	morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];
+
+	morphedNormal += normal;
+
+#endif

+ 13 - 0
src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl

@@ -0,0 +1,13 @@
+#ifdef USE_MORPHTARGETS
+
+	#ifndef USE_MORPHNORMALS
+
+	uniform float morphTargetInfluences[ 8 ];
+
+	#else
+
+	uniform float morphTargetInfluences[ 4 ];
+
+	#endif
+
+#endif

+ 20 - 0
src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl

@@ -0,0 +1,20 @@
+#ifdef USE_MORPHTARGETS
+
+	vec3 morphed = vec3( 0.0 );
+	morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];
+	morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];
+	morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];
+	morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];
+
+	#ifndef USE_MORPHNORMALS
+
+	morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];
+	morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];
+	morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];
+	morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];
+
+	#endif
+
+	morphed += position;
+
+#endif

+ 27 - 0
src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl

@@ -0,0 +1,27 @@
+#ifdef USE_NORMALMAP
+
+	uniform sampler2D normalMap;
+	uniform vec2 normalScale;
+
+			// Per-Pixel Tangent Space Normal Mapping
+			// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html
+
+	vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {
+
+		vec3 q0 = dFdx( eye_pos.xyz );
+		vec3 q1 = dFdy( eye_pos.xyz );
+		vec2 st0 = dFdx( vUv.st );
+		vec2 st1 = dFdy( vUv.st );
+
+		vec3 S = normalize( q0 * st1.t - q1 * st0.t );
+		vec3 T = normalize( -q0 * st1.s + q1 * st0.s );
+		vec3 N = normalize( surf_norm );
+
+		vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;
+		mapN.xy = normalScale * mapN.xy;
+		mat3 tsn = mat3( S, T, N );
+		return normalize( tsn * mapN );
+
+	}
+
+#endif

+ 220 - 0
src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl

@@ -0,0 +1,220 @@
+#ifdef USE_SHADOWMAP
+
+	#ifdef SHADOWMAP_DEBUG
+
+		vec3 frustumColors[3];
+		frustumColors[0] = vec3( 1.0, 0.5, 0.0 );
+		frustumColors[1] = vec3( 0.0, 1.0, 0.8 );
+		frustumColors[2] = vec3( 0.0, 0.5, 1.0 );
+
+	#endif
+
+	#ifdef SHADOWMAP_CASCADE
+
+		int inFrustumCount = 0;
+
+	#endif
+
+	float fDepth;
+	vec3 shadowColor = vec3( 1.0 );
+
+	for( int i = 0; i < MAX_SHADOWS; i ++ ) {
+
+		vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;
+
+				// if ( something && something ) breaks ATI OpenGL shader compiler
+				// if ( all( something, something ) ) using this instead
+
+		bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );
+		bool inFrustum = all( inFrustumVec );
+
+				// don't shadow pixels outside of light frustum
+				// use just first frustum (for cascades)
+				// don't shadow pixels behind far plane of light frustum
+
+		#ifdef SHADOWMAP_CASCADE
+
+			inFrustumCount += int( inFrustum );
+			bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );
+
+		#else
+
+			bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );
+
+		#endif
+
+		bool frustumTest = all( frustumTestVec );
+
+		if ( frustumTest ) {
+
+			shadowCoord.z += shadowBias[ i ];
+
+			#if defined( SHADOWMAP_TYPE_PCF )
+
+						// Percentage-close filtering
+						// (9 pixel kernel)
+						// http://fabiensanglard.net/shadowmappingPCF/
+
+				float shadow = 0.0;
+
+		/*
+						// nested loops breaks shader compiler / validator on some ATI cards when using OpenGL
+						// must enroll loop manually
+
+				for ( float y = -1.25; y <= 1.25; y += 1.25 )
+					for ( float x = -1.25; x <= 1.25; x += 1.25 ) {
+
+						vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );
+
+								// doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup
+								//vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );
+
+						float fDepth = unpackDepth( rgbaDepth );
+
+						if ( fDepth < shadowCoord.z )
+							shadow += 1.0;
+
+				}
+
+				shadow /= 9.0;
+
+		*/
+
+				const float shadowDelta = 1.0 / 9.0;
+
+				float xPixelOffset = 1.0 / shadowMapSize[ i ].x;
+				float yPixelOffset = 1.0 / shadowMapSize[ i ].y;
+
+				float dx0 = -1.25 * xPixelOffset;
+				float dy0 = -1.25 * yPixelOffset;
+				float dx1 = 1.25 * xPixelOffset;
+				float dy1 = 1.25 * yPixelOffset;
+
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );
+				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+
+				fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );
+				if ( fDepth < shadowCoord.z ) shadow += shadowDelta;
+
+				shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );
+
+			#elif defined( SHADOWMAP_TYPE_PCF_SOFT )
+
+						// Percentage-close filtering
+						// (9 pixel kernel)
+						// http://fabiensanglard.net/shadowmappingPCF/
+
+				float shadow = 0.0;
+
+				float xPixelOffset = 1.0 / shadowMapSize[ i ].x;
+				float yPixelOffset = 1.0 / shadowMapSize[ i ].y;
+
+				float dx0 = -1.0 * xPixelOffset;
+				float dy0 = -1.0 * yPixelOffset;
+				float dx1 = 1.0 * xPixelOffset;
+				float dy1 = 1.0 * yPixelOffset;
+
+				mat3 shadowKernel;
+				mat3 depthKernel;
+
+				depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );
+				depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );
+				depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );
+				depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );
+				depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );
+				depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );
+				depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );
+				depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );
+				depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );
+
+				vec3 shadowZ = vec3( shadowCoord.z );
+				shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));
+				shadowKernel[0] *= vec3(0.25);
+
+				shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));
+				shadowKernel[1] *= vec3(0.25);
+
+				shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));
+				shadowKernel[2] *= vec3(0.25);
+
+				vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );
+
+				shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );
+				shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );
+
+				vec4 shadowValues;
+				shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );
+				shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );
+				shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );
+				shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );
+
+				shadow = dot( shadowValues, vec4( 1.0 ) );
+
+				shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );
+
+			#else
+
+				vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );
+				float fDepth = unpackDepth( rgbaDepth );
+
+				if ( fDepth < shadowCoord.z )
+
+		// spot with multiple shadows is darker
+
+					shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );
+
+		// spot with multiple shadows has the same color as single shadow spot
+
+		// 					shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );
+
+			#endif
+
+		}
+
+
+		#ifdef SHADOWMAP_DEBUG
+
+			#ifdef SHADOWMAP_CASCADE
+
+				if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];
+
+			#else
+
+				if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];
+
+			#endif
+
+		#endif
+
+	}
+
+	#ifdef GAMMA_OUTPUT
+
+		shadowColor *= shadowColor;
+
+	#endif
+
+	gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;
+
+#endif

+ 19 - 0
src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl

@@ -0,0 +1,19 @@
+#ifdef USE_SHADOWMAP
+
+	uniform sampler2D shadowMap[ MAX_SHADOWS ];
+	uniform vec2 shadowMapSize[ MAX_SHADOWS ];
+
+	uniform float shadowDarkness[ MAX_SHADOWS ];
+	uniform float shadowBias[ MAX_SHADOWS ];
+
+	varying vec4 vShadowCoord[ MAX_SHADOWS ];
+
+	float unpackDepth( const in vec4 rgba_depth ) {
+
+		const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );
+		float depth = dot( rgba_depth, bit_shift );
+		return depth;
+
+	}
+
+#endif

+ 6 - 0
src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl

@@ -0,0 +1,6 @@
+#ifdef USE_SHADOWMAP
+
+	varying vec4 vShadowCoord[ MAX_SHADOWS ];
+	uniform mat4 shadowMatrix[ MAX_SHADOWS ];
+
+#endif

+ 9 - 0
src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl

@@ -0,0 +1,9 @@
+#ifdef USE_SHADOWMAP
+
+	for( int i = 0; i < MAX_SHADOWS; i ++ ) {
+
+		vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;
+
+	}
+
+#endif

+ 8 - 0
src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl

@@ -0,0 +1,8 @@
+#ifdef USE_SKINNING
+
+	mat4 boneMatX = getBoneMatrix( skinIndex.x );
+	mat4 boneMatY = getBoneMatrix( skinIndex.y );
+	mat4 boneMatZ = getBoneMatrix( skinIndex.z );
+	mat4 boneMatW = getBoneMatrix( skinIndex.w );
+
+#endif

+ 44 - 0
src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl

@@ -0,0 +1,44 @@
+#ifdef USE_SKINNING
+
+	#ifdef BONE_TEXTURE
+
+		uniform sampler2D boneTexture;
+		uniform int boneTextureWidth;
+		uniform int boneTextureHeight;
+
+		mat4 getBoneMatrix( const in float i ) {
+
+			float j = i * 4.0;
+			float x = mod( j, float( boneTextureWidth ) );
+			float y = floor( j / float( boneTextureWidth ) );
+
+			float dx = 1.0 / float( boneTextureWidth );
+			float dy = 1.0 / float( boneTextureHeight );
+
+			y = dy * ( y + 0.5 );
+
+			vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );
+			vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );
+			vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );
+			vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );
+
+			mat4 bone = mat4( v1, v2, v3, v4 );
+
+			return bone;
+
+		}
+
+	#else
+
+		uniform mat4 boneGlobalMatrices[ MAX_BONES ];
+
+		mat4 getBoneMatrix( const in float i ) {
+
+			mat4 bone = boneGlobalMatrices[ int(i) ];
+			return bone;
+
+		}
+
+	#endif
+
+#endif

+ 19 - 0
src/renderers/shaders/ShaderChunk/skinning_vertex.glsl

@@ -0,0 +1,19 @@
+#ifdef USE_SKINNING
+
+	#ifdef USE_MORPHTARGETS
+
+	vec4 skinVertex = vec4( morphed, 1.0 );
+
+	#else
+
+	vec4 skinVertex = vec4( position, 1.0 );
+
+	#endif
+
+	vec4 skinned = vec4( 0.0 );
+	skinned += boneMatX * skinVertex * skinWeight.x;
+	skinned += boneMatY * skinVertex * skinWeight.y;
+	skinned += boneMatZ * skinVertex * skinWeight.z;
+	skinned += boneMatW * skinVertex * skinWeight.w;
+
+#endif

+ 19 - 0
src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl

@@ -0,0 +1,19 @@
+#ifdef USE_SKINNING
+
+	mat4 skinMatrix = mat4( 0.0 );
+	skinMatrix += skinWeight.x * boneMatX;
+	skinMatrix += skinWeight.y * boneMatY;
+	skinMatrix += skinWeight.z * boneMatZ;
+	skinMatrix += skinWeight.w * boneMatW;
+
+	#ifdef USE_MORPHNORMALS
+
+	vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );
+
+	#else
+
+	vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );
+
+	#endif
+
+#endif

+ 12 - 0
src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl

@@ -0,0 +1,12 @@
+float specularStrength;
+
+#ifdef USE_SPECULARMAP
+
+	vec4 texelSpecular = texture2D( specularMap, vUv );
+	specularStrength = texelSpecular.r;
+
+#else
+
+	specularStrength = 1.0;
+
+#endif

+ 5 - 0
src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl

@@ -0,0 +1,5 @@
+#ifdef USE_SPECULARMAP
+
+	uniform sampler2D specularMap;
+
+#endif

+ 21 - 0
src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl

@@ -0,0 +1,21 @@
+#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )
+
+	#ifdef USE_SKINNING
+
+		vec4 worldPosition = modelMatrix * skinned;
+
+	#endif
+
+	#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )
+
+		vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );
+
+	#endif
+
+	#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )
+
+		vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
+
+	#endif
+
+#endif

+ 1 - 4
utils/build/build.js

@@ -34,10 +34,7 @@ function main() {
 
 	var buffer = [];
 	var sources = [];
-		
-	buffer.push('// You shouldn\'t edit this build file. \n');
-	buffer.push('// The following source code is build from the src folder. \n');
-	
+			
 	if ( args.amd ){
 		buffer.push('function ( root, factory ) {\n\n\tif ( typeof define === \'function\' && define.amd ) {\n\n\t\tdefine( [ \'exports\' ], factory );\n\n\t} else if ( typeof exports === \'object\' ) {\n\n\t\tfactory( exports );\n\n\t} else {\n\n\t\tfactory( root );\n\n\t}\n\n}( this, function ( exports ) {\n\n');
 	};

+ 9 - 7
utils/build/build.py

@@ -44,10 +44,7 @@ def main(argv=None):
 	fd, path = tempfile.mkstemp()
 	tmp = open(path, 'w')
 	sources = []
-	
-	tmp.write('// You shouldn\'t edit this build file. \n')
-	tmp.write('// The following source code is build from the src folder. \n')
-	
+		
 	if args.amd:
 		tmp.write('( function ( root, factory ) {\n\n\tif ( typeof define === \'function\' && define.amd ) {\n\n\t\tdefine( [ \'exports\' ], factory );\n\n\t} else if ( typeof exports === \'object\' ) {\n\n\t\tfactory( exports );\n\n\t} else {\n\n\t\tfactory( root );\n\n\t}\n\n}( this, function ( exports ) {\n\n')
 
@@ -60,8 +57,13 @@ def main(argv=None):
 			filename = '../../' + filename;
 			sources.append(filename)
 			with open(filename, 'r') as f:
-				tmp.write(f.read())
-				tmp.write('\n')
+				if filename.endswith(".glsl"):
+					tmp.write('THREE.ShaderChunk[ \'' + os.path.splitext(os.path.basename(filename))[0] + '\'] = "') 
+					tmp.write(f.read().replace('\n','\\n'))
+					tmp.write('";\n\n')
+				else:
+					tmp.write(f.read())
+					tmp.write('\n')
 
 	if args.amd:
 		tmp.write('exports.THREE = THREE;\n\n} ) );')
@@ -78,7 +80,7 @@ def main(argv=None):
 
 		externs = ' --externs '.join(args.externs)
 		source = ' '.join(sources)
-		cmd = 'java -jar compiler/compiler.jar --warning_level=VERBOSE --jscomp_off=globalThis --externs %s --jscomp_off=checkTypes --language_in=ECMASCRIPT5_STRICT --js %s --js_output_file %s %s' % (externs, source, output, sourcemapargs)
+		cmd = 'java -jar compiler/compiler.jar --warning_level=VERBOSE --jscomp_off=globalThis --externs %s --jscomp_off=checkTypes --language_in=ECMASCRIPT5_STRICT --js %s --js_output_file %s %s' % (externs, path, output, sourcemapargs)
 		os.system(cmd)
 
 		# header

+ 50 - 0
utils/build/includes/common.json

@@ -81,6 +81,56 @@
 	"src/scenes/FogExp2.js",
 	"src/renderers/CanvasRenderer.js",
 	"src/renderers/shaders/ShaderChunk.js",
+	"src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/default_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lightmap_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/lights_phong_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lights_phong_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/map_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/lightmap_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/color_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/skinning_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/map_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/envmap_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/fog_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/map_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/color_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/envmap_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl",
 	"src/renderers/shaders/UniformsUtils.js",
 	"src/renderers/shaders/UniformsLib.js",
 	"src/renderers/shaders/ShaderLib.js",

+ 51 - 0
utils/build/includes/webgl.json

@@ -71,6 +71,56 @@
 	"src/scenes/Fog.js",
 	"src/scenes/FogExp2.js",
 	"src/renderers/shaders/ShaderChunk.js",
+	"src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/default_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/map_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/logdepthbuf_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lightmap_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/lights_phong_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lightmap_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lights_phong_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/map_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/lightmap_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/color_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/skinning_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/map_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/envmap_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/logdepthbuf_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/morphtarget_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/specularmap_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/fog_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/map_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/color_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/envmap_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl",
+	"src/renderers/shaders/ShaderChunk/skinning_pars_vertex.glsl",
+	"src/renderers/shaders/ShaderChunk/logdepthbuf_pars_fragment.glsl",
 	"src/renderers/shaders/UniformsUtils.js",
 	"src/renderers/shaders/UniformsLib.js",
 	"src/renderers/shaders/ShaderLib.js",
@@ -97,3 +147,4 @@
 	"src/extras/renderers/plugins/SpritePlugin.js",
 	"src/extras/shaders/ShaderFlares.js"
 ]
+

+ 1097 - 0
utils/exporters/max/ThreeJSExporter_MorphTargets_v0.ms

@@ -0,0 +1,1097 @@
+-------------------------------------------------------------------------------------
+-- ThreeJSExporter.ms
+-- Exports geometry from 3ds max to Three.js models in ASCII JSON format v3
+-- By alteredq / http://alteredqualia.com
+--
+--	2014.06.25
+--	Add vertex export from each frame
+-------------------------------------------------------------------------------------
+function eav_attime obj t =
+(
+	local i
+	local s_out = ""
+	s_out = s_out as stringstream
+	
+	local zmesh = at time t (SnapshotAsMesh obj)
+	local n = zmesh.numverts
+	
+	local vrs_ar = #()
+	local v = [0,0,0]
+	
+	for i = 1 to n do
+	(
+		v = (GetVert zmesh i)
+		append vrs_ar v
+	)
+
+	for i = 1 to vrs_ar.count do
+	(
+		v = vrs_ar[i]
+		format "%, %, %" v.x v.z -v.y to:s_out
+		
+		if i < vrs_ar.count then
+		(
+			format ",  " to:s_out
+		)
+	)
+
+	return (s_out as string)
+)
+
+
+/*
+TODO 2014.06.25
+Export animation from modifiers
+*/
+function eav_get_range_from_trans_con obj &i_t1 &i_t2 =
+(
+--	Get keys range from Pos, rotation, scale controllers	
+	local i
+	local con
+	local t1min = 0, t2max = 0
+	
+	for i = 1 to 3 do
+	(
+		con = obj.controller[i]
+		
+		format "\nController: %" obj.controller[i].name
+		format " (keys count: %)" con.keys.count
+		
+		if con.keys.count == 0 then
+		(
+			continue
+		)
+		
+		t1 = con.keys[1].time.frame as integer
+		t2 = (con.keys[con.keys.count].time.frame) as integer
+		
+		if i == 1 then
+		(
+			t1min = t1
+			t2max = t2
+		)
+		
+		if t1 < t1min then
+		(
+			t1min = t1
+		)
+		
+		if t2 > t2max then
+		(
+			t2max = t2
+		)
+	)
+	
+	i_t1 = t1min
+	i_t2 = t2max
+	
+	if( i_t1 == 0 )and( i_t2 == 0 )then
+	(
+		return(false)
+	)
+	else
+	(
+		return(true)
+	)
+)
+
+function eav_get_range_from_mods_con obj &i_t1 &i_t2 =
+(
+	local i
+	local cmod, mod_con
+	local props, pr
+	local t1min = 0, t2max = 0
+	
+--	format "\n\nModifiers:\n"
+	
+	for i = 1 to obj.modifiers.count do
+	(
+		cmod = obj.modifiers[i]
+		
+	--	format "\n%: \"%\" (%)\n" i (cmod.name) (classof cmod)
+		
+		props = getpropnames cmod
+		
+		for pr in props do
+		(
+			mod_con = (getPropertyController cmod pr)
+			
+			if mod_con == undefined then
+			(
+				continue
+			)
+			
+			if mod_con.keys.count <= 0 then
+			(
+				continue
+			)
+			
+		--	format "\t%\t(keys: %)\n" pr (mod_con.keys.count)
+			
+			t1 = mod_con.keys[1].time.frame as integer
+			t2 = (mod_con.keys[mod_con.keys.count].time.frame) as integer
+			
+			if i == 1 then
+			(
+				t1min = t1
+				t2max = t2
+			)
+			
+			if t1 < t1min then
+			(
+				t1min = t1
+			)
+			
+			if t2 > t2max then
+			(
+				t2max = t2
+			)
+		)
+	)
+	
+	i_t1 = t1min
+	i_t2 = t2max
+	
+	if( i_t1 == 0 )and( i_t2 == 0 )then
+	(
+		return(false)
+	)
+	else
+	(
+		return(true)
+	)
+	
+)
+
+function eav_exp_obj obj ostream =
+(
+	local i, t1, t2, t1_m, t2_m
+	local b_ran_set = false
+	local b_ran_mod_set = false
+	format "\n\n-----------------------------\nObject: \"%\"\n" obj.name
+
+	-- Total range:
+/*	local frames_num = animationRange.end.frame - animationRange.start.frame
+	frames_num = frames_num as integer
+*/
+	
+	-- Range detection between keys:
+	b_ran_set = eav_get_range_from_trans_con obj &t1 &t2
+	b_ran_mod_set = eav_get_range_from_mods_con obj &t1_m &t2_m
+	
+	format "\n\nKey ranges detected:\n"
+	format "  transform: (% to %) - %\n" t1 t2 b_ran_set
+	format "  modifiers: (% to %) - %\n" t1_m t2_m b_ran_mod_set
+	
+	if b_ran_set and b_ran_mod_set then
+	(
+	--	format "\nAll ranges set - compare\n"
+		-- Set smallest first key, and latest final key
+		if t1_m < t1 then
+		(
+			t1 = t1_m
+		)
+		
+		if t2_m > t2 then
+		(
+			t2 = t2_m
+		)
+	)
+	else if( not b_ran_set )and( b_ran_mod_set )then
+	(
+	--	format "\nTrans range not set\n"
+		t1 = t1_m
+		t2 = t2_m
+	)
+	else if( not b_ran_mod_set )and( b_ran_set )then
+	(
+	--	format "\nmods range not set\n"
+		-- all values t1, t2 - save in initial state
+	)
+	else if( not b_ran_set )and( not b_ran_mod_set )then
+	(
+		format "\n  No key range set. Exit function\n"
+		return(false)
+	)
+	
+	format "\n  final range for export: (% to %)\n" t1 t2
+
+	---- Output
+	format "\n\"morphTargets\": [" to:ostream
+	
+	for i = t1 to t2 do
+	(
+		format "\n{\"name\": \"FRAME000\", \"vertices\": [" to:ostream
+		format "%]}" (eav_attime obj i) to:ostream
+		
+		if i < t2 then
+		(
+			format "," to:ostream
+		)
+	)
+	format " ],\n\n" to:ostream
+	
+	format "\n\n\"morphColors\": [],\n\n\n" to:ostream
+)
+
+function exp_anim_verts_sel ostream =
+(
+	Clearlistener()
+	format "\n---- Export verts:\n"
+	
+	for obj in selection do
+	(
+		if superclassof obj != geometryclass then continue
+		eav_exp_obj obj ostream
+	)
+	format "\n----\n"
+)
+----
+
+
+
+
+
+--------------------------------------------------------------------------------
+--------------------------------------------------------------------------------
+rollout ThreeJSExporter "ThreeJSExporter"
+(
+	-- Variables
+
+	local ostream,
+	headerFormat = "\"metadata\":{\"sourceFile\": \"%\",\"generatedBy\": \"3ds max ThreeJSExporter\",\"formatVersion\": 3.1,\"vertices\": %,\"normals\": %,\"colors\": %,\"uvs\": %,\"triangles\": %,\"materials\": %},",
+
+	vertexFormat = "%,%,%",
+
+	vertexNormalFormat = "%,%,%",
+	UVFormat = "%,%",
+
+	triFormat = "%,%,%,%",
+	triUVFormat = "%,%,%,%,%,%,%",
+	triNFormat = "%,%,%,%,%,%,%",
+	triUVNFormat = "%,%,%,%,%,%,%,%,%,%",
+
+	footerFormat = "}"
+
+	-------------------------------------------------------------------------------------
+	-- User interface
+
+	group "ThreeJSExporter  v0.8"
+	(
+		label msg "Exports selected meshes in Three.js ascii JSON format" align:#left
+		hyperLink lab1 "Original source at GitHub" address:"https://github.com/alteredq/three.js/blob/master/utils/exporters/max/ThreeJSExporter.ms" color:(color 255 120 0) align:#left
+
+		label dummy1 "--------------------------------------------------------" align:#left
+
+		checkbox exportColor "Export vertex colors" checked:false enabled:true
+		checkbox exportUv "Export uvs" checked:true enabled:true
+		checkbox exportNormal "Export normals" checked:true enabled:true
+		checkbox smoothNormal "Use vertex normals" checked:false enabled:true
+
+		label dummy2 "--------------------------------------------------------" align:#left
+
+		checkbox flipYZ "Flip YZ" checked:true enabled:true
+		checkbox flipUV "Flip UV" checked:false enabled:true
+		checkbox flipFace "Flip all faces" checked:false enabled:true
+		checkbox autoflipFace "Try fixing flipped faces" checked:false enabled:true
+
+		label dummy3 "--------------------------------------------------------" align:#left
+		
+		checkbox cb_exp_mt "Export Morph Targets" checked:true enabled:true
+		
+		label dummy4 "--------------------------------------------------------" align:#left
+		button btn_export "Export selected objects"
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Dump vertices
+	function DumpVertices src =
+	(
+		Format "\"vertices\": [" to:ostream
+		num = src.count
+
+		if num > 0 then
+		(
+			for i = 1 to num do
+			(
+				vert = src[i]
+
+				if flipYZ.checked then
+				(
+					x = vert.x
+					y = vert.z
+					z = vert.y
+
+					z *= -1
+				)
+				else
+				(
+					x = vert.x
+					y = vert.y
+					z = vert.z
+				)
+
+				Format vertexFormat x y z to:ostream
+				if i < num then Format "," to:ostream
+			)
+		)
+		Format "],\n\n" to:ostream
+	)
+
+	----	2014.06.25	16:15
+	function dump_morph_targets =
+	(
+		Clearlistener()
+		format "\n---- dump_morph_targets():\n"
+		
+		if not cb_exp_mt.state then
+		(
+			format "\nNot checked\n"
+			return()
+		)
+		
+		exp_anim_verts_sel ostream
+
+		format "\n----\n"
+	)
+	
+	
+	-------------------------------------------------------------------------------------
+	-- Dump colors
+	function DumpColors src useColors =
+	(
+		Format "\"colors\": [" to:ostream
+		num = src.count
+
+		if num > 0 and useColors then
+		(
+			for i = 1 to num do
+			(
+				col = src[i]
+
+				r = col.r as Integer
+				g = col.g as Integer
+				b = col.b as Integer
+
+				hexNum = ( bit.shift r 16 ) + ( bit.shift g 8 ) + b
+
+				-- hexColor = formattedPrint hexNum format:"#x"
+				-- Format "%" hexColor to:ostream
+
+				decColor = formattedPrint hexNum format:"#d"
+				Format "%" decColor to:ostream
+
+				if i < num then Format "," to:ostream
+			)
+		)
+		Format "],\n\n" to:ostream
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Dump normals
+	function DumpNormals src =
+	(
+		Format "\"normals\": [" to:ostream
+		num = src.count
+
+		if num > 0 and exportNormal.checked then
+		(
+			for i = 1 to num do
+			(
+				normal = src[i]
+				normal = normalize normal as point3
+
+				if flipYZ.checked then
+				(
+					x = normal.x
+					y = normal.z
+					z = normal.y
+
+					z *= -1
+				)
+				else
+				(
+					x = normal.x
+					y = normal.y
+					z = normal.z
+				)
+
+				Format vertexNormalFormat x y z to:ostream
+				if i < num then Format "," to:ostream
+			)
+		)
+		Format "],\n\n" to:ostream
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Dump uvs
+	function DumpUvs src =
+	(
+		Format "\"uvs\": [[" to:ostream
+		num = src.count
+
+		if num > 0 and exportUv.checked then
+		(
+			for i = 1 to num do
+			(
+				uvw = src[i]
+
+				u = uvw.x
+
+				if flipUV.checked then
+				(
+					v = 1 - uvw.y
+				)
+				else
+				(
+					v = uvw.y
+				)
+
+				Format UVFormat u v to:ostream
+				if i < num then Format "," to:ostream
+			)
+		)
+		Format "]],\n\n" to:ostream
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Dump faces
+	function DumpFaces src useColors =
+	(
+		Format "\"faces\": [" to:ostream
+		num = src.count
+
+		if num > 0 then
+		(
+			for i = 1 to num do
+			(
+				zface = src[i]
+
+				fv  = zface[1]
+				fuv = zface[2]
+				m   = zface[3] - 1
+				fc  = zface[4]
+
+				needsFlip = zface[5]
+
+				isTriangle = true
+				hasMaterial = true
+				hasFaceUvs = false
+				hasFaceVertexUvs = ((classof fuv == Point3) and exportUv.checked)
+				hasFaceNormals = false
+				hasFaceVertexNormals = (exportNormal.checked)
+				hasFaceColors = false
+				hasFaceVertexColors = ((classof fc == Point3) and useColors)
+
+				faceType = 0
+				faceType = bit.set faceType 1 (not isTriangle)
+				faceType = bit.set faceType 2 hasMaterial
+				faceType = bit.set faceType 3 hasFaceUvs
+				faceType = bit.set faceType 4 hasFaceVertexUvs
+				faceType = bit.set faceType 5 hasFaceNormals
+				faceType = bit.set faceType 6 hasFaceVertexNormals
+				faceType = bit.set faceType 7 hasFaceColors
+				faceType = bit.set faceType 8 hasFaceVertexColors
+
+				if i > 1 then
+				(
+					Format "," faceType to:ostream
+				)
+
+				Format "%" faceType to:ostream
+
+				if isTriangle then
+				(
+					va = (fv.x - 1) as Integer
+					vb = (fv.y - 1) as Integer
+					vc = (fv.z - 1) as Integer
+
+					if flipFace.checked or needsFlip then
+					(
+						tmp = vb
+						vb = vc
+						vc = tmp
+					)
+
+					Format ",%,%,%" va vb vc to:ostream
+
+					if hasMaterial then
+					(
+						Format ",%" m to:ostream
+					)
+
+					if hasFaceVertexUvs then
+					(
+						ua = (fuv.x - 1) as Integer
+						ub = (fuv.y - 1) as Integer
+						uc = (fuv.z - 1) as Integer
+
+						if flipFace.checked or needsFlip then
+						(
+							tmp = ub
+							ub = uc
+							uc = tmp
+						)
+						Format ",%,%,%" ua ub uc to:ostream
+					)
+
+					if hasFaceVertexNormals then
+					(
+						if smoothNormal.checked then
+						(
+							-- normals have the same indices as vertices
+							na = va
+							nb = vb
+							nc = vc
+						)
+						else
+						(
+							-- normals have the same indices as face
+							na = i - 1
+							nb = na
+							nc = na
+						)
+
+						if flipFace.checked or needsFlip then
+						(
+							tmp = nb
+							nb = nc
+							nc = tmp
+						)
+						Format ",%,%,%" na nb nc to:ostream
+					)
+
+					if hasFaceVertexColors then
+					(
+						ca = (fc.x - 1) as Integer
+						cb = (fc.y - 1) as Integer
+						cc = (fc.z - 1) as Integer
+
+						if flipFace.checked or needsFlip then
+						(
+							tmp = cb
+							cb = cc
+							cc = tmp
+						)
+						Format ",%,%,%" ca cb cc to:ostream
+					)
+				)
+			)
+		)
+		Format "]\n\n" to:ostream
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Dump color
+
+	function DumpColor pcolor label =
+	(
+		r = pcolor.r / 255
+		g = pcolor.g / 255
+		b = pcolor.b / 255
+
+		fr = formattedPrint r format:".4f"
+		fg = formattedPrint g format:".4f"
+		fb = formattedPrint b format:".4f"
+
+		Format "\"%\"  : [%, %, %],\n" label fr fg fb to:ostream
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Dump map
+	function DumpMap pmap label =
+	(
+		if classof pmap == BitmapTexture then
+		(
+			bm = pmap.bitmap
+
+			if bm != undefined then
+			(
+				fname = filenameFromPath bm.filename
+				Format "\"%\"    : \"%\",\n" label fname to:ostream
+			)
+		)
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Export materials
+	function ExportMaterials zmaterials zcolors =
+	(
+		Format "\"materials\": [\n" to:ostream
+
+		totalMaterials = zmaterials.count
+
+		for i = 1 to totalMaterials do
+		(
+			mat = zmaterials[i]
+
+			Format "{\n" to:ostream
+
+			-- debug
+			Format "\"DbgIndex\" : %,\n" (i-1) to:ostream
+
+			if classof mat != BooleanClass then
+			(
+				useVertexColors = zcolors[i]
+
+				Format "\"DbgName\"  : \"%\",\n" mat.name to:ostream
+
+				-- colors
+				DumpColor mat.diffuse  "colorDiffuse"
+				DumpColor mat.ambient  "colorAmbient"
+				DumpColor mat.specular "colorSpecular"
+
+				t = mat.opacity / 100
+				s = mat.glossiness
+
+				Format "\"transparency\"  : %,\n" t to:ostream
+				Format "\"specularCoef\"  : %,\n" s to:ostream
+
+				-- maps
+				DumpMap mat.diffuseMap  "mapDiffuse"
+				DumpMap mat.ambientMap  "mapAmbient"
+				DumpMap mat.specularMap "mapSpecular"
+				DumpMap mat.bumpMap 	"mapBump"
+				DumpMap mat.opacityMap 	"mapAlpha"
+			)
+			else
+			(
+				useVertexColors = false
+				Format "\"DbgName\"  : \"%\",\n" "dummy" to:ostream
+				DumpColor red "colorDiffuse"
+			)
+
+			Format "\"vertexColors\" : %\n" useVertexColors to:ostream
+			Format "}" to:ostream
+
+			if ( i < totalMaterials ) then Format "," to:ostream
+			Format "\n\n" to:ostream
+		)
+		Format "],\n\n" to:ostream
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Extract vertices from mesh
+	function ExtractVertices obj whereto =
+	(
+		n = obj.numVerts
+		for i = 1 to n do
+		(
+			v = GetVert obj i
+			append whereto v
+		)
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Extract vertex colors from mesh
+
+	function ExtractColors obj whereto =
+	(
+		nColors = GetNumCPVVerts obj
+
+		if nColors > 0 then
+		(
+			for i = 1 to nColors do
+			(
+				c = GetVertColor obj i
+				append whereto c
+			)
+		)
+	)
+
+
+	-------------------------------------------------------------------------------------
+	-- Extract normals from mesh
+
+	function ExtractNormals obj whereto needsFlip =
+	(
+		if smoothNormal.checked then
+		(
+			num = obj.numVerts
+
+			for i = 1 to num do
+			(
+				n = GetNormal obj i
+
+				if flipFace.checked or needsFlip then
+				(
+					n.x *= -1
+					n.y *= -1
+					n.z *= -1
+				)
+				append whereto n
+			)
+		)
+		else
+		(
+			num = obj.numFaces
+
+			for i = 1 to num do
+			(
+				n = GetFaceNormal obj i
+
+				if flipFace.checked or needsFlip then
+				(
+					n.x *= -1
+					n.y *= -1
+					n.z *= -1
+				)
+
+				append whereto n
+			)
+		)
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Extract uvs from mesh
+
+	function ExtractUvs obj whereto =
+	(
+		n = obj.numTVerts
+		for i = 1 to n do
+		(
+			v = GetTVert obj i
+			append whereto v
+		)
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Extract faces from mesh
+	function ExtractFaces objMesh objMaterial whereto allMaterials needsFlip hasVColors offsetVert offsetUv offsetColor =
+	(
+		n = objMesh.numFaces
+		hasUVs = objMesh.numTVerts > 0
+
+		useMultiMaterial = false
+		materialIDList = #()
+
+		materialClass = classof objMaterial
+
+		if materialClass == StandardMaterial then
+		(
+			fm = findItem allMaterials objMaterial
+		)
+		else if materialClass == MultiMaterial then
+		(
+			useMultiMaterial = true
+			for i = 1 to n do
+			(
+				mID = GetFaceMatID objMesh i
+				materialIndex = findItem objMaterial.materialIDList mID
+
+				if materialIndex > 0 then
+				(
+					subMaterial = objMaterial.materialList[materialIndex]
+
+					mMergedIndex = findItem allMaterials subMaterial
+
+					if mMergedIndex > 0 then
+					(
+						materialIDList[mID] = mMergedIndex
+					)
+					else
+					(
+						materialIDList[mID] = findItem allMaterials false
+					)
+				)
+				else
+				(
+					materialIDList[mID] = findItem allMaterials false
+				)
+			)
+		)
+		else
+		(
+			-- undefined material
+			fm = findItem allMaterials false
+		)
+
+		for i = 1 to n do
+		(
+			zface = #()
+
+			fv = GetFace objMesh i
+
+			fv.x += offsetVert
+			fv.y += offsetVert
+			fv.z += offsetVert
+
+			if useMultiMaterial then
+			(
+				mID = GetFaceMatID objMesh i
+				fm = materialIDList[mID]
+			)
+
+			if hasUVs then
+			(
+				fuv = GetTVFace objMesh i
+
+				fuv.x += offsetUv
+				fuv.y += offsetUv
+				fuv.z += offsetUv
+			)
+			else
+			(
+				fuv = false
+			)
+
+			if hasVColors then
+			(
+				fc = GetVCFace objMesh i
+
+				fc.x += offsetColor
+				fc.y += offsetColor
+				fc.z += offsetColor
+			)
+			else
+			(
+				fc = false
+			)
+
+			append zface fv
+			append zface fuv
+			append zface fm
+			append zface fc
+			append zface needsFlip
+
+			append whereto zface
+		)
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Extract materials from eventual multi-material
+	function ExtractMaterials objMesh objMaterial whereto wheretoColors zname hasVColors =
+	(
+		materialClass = classof objMaterial
+
+		if materialClass == StandardMaterial then
+		(
+			if ( findItem whereto objMaterial ) == 0 then
+			(
+				append whereto objMaterial
+				append wheretoColors hasVColors
+			)
+		)
+		else if materialClass == MultiMaterial then
+		(
+			n = objMesh.numFaces
+
+			for i = 1 to n do
+			(
+				mID = getFaceMatId objMesh i
+				materialIndex = findItem objMaterial.materialIDList mID
+
+				if materialIndex > 0 then
+				(
+					subMaterial = objMaterial.materialList[materialIndex]
+
+					if ( findItem whereto subMaterial ) == 0 then
+					(
+						append whereto subMaterial
+						append wheretoColors hasVColors
+					)
+				)
+			)
+		)
+		else
+		(
+			-- unknown or undefined material
+			append whereto false
+			append wheretoColors false
+		)
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Hack to figure out if normals are messed up
+	function NeedsFaceFlip node =
+	(
+		needsFlip = false
+		local tmp = Snapshot node
+		face_normal = normalize ( getfacenormal tmp 1 )
+		face = getface tmp 1
+
+		va = getvert tmp face[1]
+		vb = getvert tmp face[2]
+		vc = getvert tmp face[3]
+
+		computed_normal = normalize ( cross (vc - vb)  (va - vb) )
+		if distance computed_normal face_normal > 0.1 then needsFlip = true
+		delete tmp
+		return needsFlip
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Extract only things that either already are or can be converted to meshes
+	function ExtractMesh node =
+	(
+		if SuperClassOf node == GeometryClass then
+		(
+			needsFlip = false
+			hasVColors = false
+
+			zmesh = SnapshotAsMesh node
+
+			if autoflipFace.checked then
+			(
+				needsFlip = NeedsFaceFlip node
+			)
+
+			if exportColor.checked and ( getNumCPVVerts zmesh ) > 0 then
+			(
+				hasVColors = true
+			)
+			return #( zmesh, node.name, node.material, needsFlip, hasVColors )
+		)
+		-- Not geometry ... could be a camera, light, etc.
+		return #( false, node.name, 0, false, false )
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Export scene
+	function ExportScene =
+	(
+		-- Extract meshes
+		meshObjects = #()
+
+		mergedVertices = #()
+		mergedNormals = #()
+		mergedColors = #()
+
+		mergedUvs = #()
+		mergedFaces = #()
+
+		mergedMaterials = #()
+		mergedMaterialsColors = #()
+
+		sceneHasVColors = false
+
+		for obj in selection do
+		(
+			result = ExtractMesh obj
+			meshObj = result[1]
+
+			if ClassOf meshObj == TriMesh then
+			(
+				meshName     = result[2]
+				meshMaterial = result[3]
+				needsFlip    = result[4]
+				hasVColors   = result[5]
+
+				sceneHasVColors = sceneHasVColors or hasVColors
+
+				append meshObjects result
+
+				vertexOffset = mergedVertices.count
+				uvOffset = mergedUvs.count
+				colorOffset = mergedColors.count
+
+				ExtractMaterials meshObj meshMaterial mergedMaterials mergedMaterialsColors meshName hasVColors
+
+				ExtractVertices meshObj mergedVertices
+				ExtractNormals meshObj mergedNormals needsFlip
+				ExtractColors meshObj mergedColors
+
+				ExtractUvs meshObj mergedUvs
+
+				ExtractFaces meshObj meshMaterial mergedFaces mergedMaterials needsFlip hasVColors vertexOffset uvOffset colorOffset
+			)
+		)
+
+		totalVertices = mergedVertices.count
+		totalFaces = mergedFaces.count
+		totalMaterials = mergedMaterials.count
+
+		totalColors = 0
+		totalNormals = 0
+		totalUvs = 0
+
+		useColors = false
+
+		if sceneHasVColors and exportColor.checked then
+		(
+			totalColors = mergedColors.count
+			useColors = true
+		)
+
+		if exportNormal.checked then
+		(
+			totalNormals = mergedNormals.count
+		)
+
+		if exportUv.checked then
+		(
+			totalUvs = mergedUvs.count
+		)
+
+
+		-- Dump objects (debug)
+		-- Format "// Source objects:\n\n" to:ostream
+		-- i = 0
+		-- for obj in meshObjects do
+		-- (
+		-- 	meshName = obj[2]
+		-- 	Format "// %: %\n" i meshName to:ostream
+		-- 	i += 1
+		-- )
+
+		-- Dump model
+		Format "{\n\n" to:ostream
+
+		-- Dump header
+		Format headerFormat maxFileName totalVertices totalNormals totalColors totalUvs totalFaces totalMaterials to:ostream
+
+		-- Dump all materials in the scene
+		ExportMaterials mergedMaterials mergedMaterialsColors
+
+		-- Dump merged data from all selected geometries
+		DumpVertices mergedVertices
+		
+		----	2014.06.25	16:14
+		dump_morph_targets()
+		----
+		
+		DumpNormals mergedNormals
+		DumpColors mergedColors useColors
+		DumpUvs mergedUvs
+		DumpFaces mergedFaces useColors
+
+		-- Dump footer
+		Format footerFormat to:ostream
+	)
+
+
+	-------------------------------------------------------------------------------------
+	-- Open and prepare a file handle for writing
+	function GetSaveFileStream =
+	(
+		zname = getFilenameFile maxFileName
+		zname += ".js"
+
+		fname = GetSaveFileName filename:zname types:"JavaScript file (*.js)|*.js|All Files(*.*)|*.*|"
+		if fname == undefined then
+		(
+			return undefined
+		)
+
+		ostream = CreateFile fname
+		if ostream == undefined then
+		(
+			MessageBox "Couldn't open file for writing !"
+			return undefined
+		)
+		return ostream
+	)
+
+	-------------------------------------------------------------------------------------
+	-- Export button click handler
+	on btn_export pressed do
+	(
+		ostream = GetSaveFileStream()
+		if ostream != undefined then
+		(
+			ExportScene()
+			close ostream
+		)
+	)
+)
+createDialog ThreeJSExporter width:300

Some files were not shown because too many files changed in this diff