Browse Source

Merge branch 'dev' into lighthelper_colours

Mr.doob 8 years ago
parent
commit
985220c007
100 changed files with 2941 additions and 1584 deletions
  1. 1 1
      README.md
  2. 55 25
      build/three.js
  3. 343 335
      build/three.min.js
  4. 55 25
      build/three.module.js
  5. 1 1
      docs/api/materials/Material.html
  6. 6 2
      docs/api/materials/MeshBasicMaterial.html
  7. 6 2
      docs/api/materials/MeshLambertMaterial.html
  8. 6 2
      docs/api/materials/MeshPhongMaterial.html
  9. 6 2
      docs/api/materials/MeshStandardMaterial.html
  10. 4 13
      docs/api/math/Euler.html
  11. 16 34
      docs/api/math/Plane.html
  12. 9 0
      docs/api/math/Vector4.html
  13. 1 1
      docs/api/objects/Group.html
  14. 3 0
      docs/api/renderers/WebGLRenderer.html
  15. 1 1
      examples/css3d_sandbox.html
  16. 2 0
      examples/files.js
  17. 8 7
      examples/js/GPUParticleSystem.js
  18. 25 15
      examples/js/Mirror.js
  19. 2 0
      examples/js/controls/OrbitControls.js
  20. 2 0
      examples/js/controls/TrackballControls.js
  21. 4 11
      examples/js/effects/OutlineEffect.js
  22. 151 34
      examples/js/loaders/ColladaLoader2.js
  23. 77 18
      examples/js/loaders/FBXLoader.js
  24. 66 31
      examples/js/loaders/GLTF2Loader.js
  25. 1 1
      examples/js/loaders/GLTFLoader.js
  26. 293 0
      examples/js/loaders/PRWMLoader.js
  27. 52 53
      examples/js/nodes/materials/PhongNode.js
  28. 139 0
      examples/js/nodes/materials/SpriteNode.js
  29. 17 0
      examples/js/nodes/materials/SpriteNodeMaterial.js
  30. 82 78
      examples/js/nodes/materials/StandardNode.js
  31. 4 3
      examples/js/nodes/utils/ResolutionNode.js
  32. 48 0
      examples/js/nodes/utils/UVTransformNode.js
  33. 52 52
      examples/js/renderers/WebGLDeferredRenderer.js
  34. 0 153
      examples/js/vr/WebVRCamera.js
  35. BIN
      examples/models/prwm/faceted-nefertiti.be.prwm
  36. BIN
      examples/models/prwm/faceted-nefertiti.le.prwm
  37. BIN
      examples/models/prwm/smooth-suzanne.be.prwm
  38. BIN
      examples/models/prwm/smooth-suzanne.le.prwm
  39. BIN
      examples/models/prwm/vive-controller.be.prwm
  40. BIN
      examples/models/prwm/vive-controller.le.prwm
  41. BIN
      examples/textures/WalkingManSpriteSheet.png
  42. 1 0
      examples/webgl_clipping.html
  43. 1 1
      examples/webgl_gpgpu_water.html
  44. 7 2
      examples/webgl_loader_imagebitmap.html
  45. 250 0
      examples/webgl_loader_prwm.html
  46. 249 181
      examples/webgl_materials_nodes.html
  47. 12 2
      examples/webgl_mirror.html
  48. 6 6
      examples/webgl_panorama_equirectangular.html
  49. 2 20
      examples/webgl_postprocessing_outline.html
  50. 74 5
      examples/webgl_shadowmap_pointlight.html
  51. 281 0
      examples/webgl_sprites_nodes.html
  52. 8 12
      examples/webvr_cubes.html
  53. 11 17
      examples/webvr_daydream.html
  54. 16 15
      examples/webvr_panorama.html
  55. 15 17
      examples/webvr_rollercoaster.html
  56. 13 15
      examples/webvr_sandbox.html
  57. 9 18
      examples/webvr_video.html
  58. 11 17
      examples/webvr_vive.html
  59. 9 15
      examples/webvr_vive_camerarig.html
  60. 9 15
      examples/webvr_vive_dragging.html
  61. 14 20
      examples/webvr_vive_paint.html
  62. 9 15
      examples/webvr_vive_sculpt.html
  63. 1 1
      package.json
  64. 2 0
      src/Three.js
  65. 1 1
      src/constants.js
  66. 5 5
      src/helpers/AxisHelper.js
  67. 55 0
      src/helpers/Box3Helper.js
  68. 5 5
      src/helpers/BoxHelper.js
  69. 9 9
      src/helpers/CameraHelper.js
  70. 6 6
      src/helpers/DirectionalLightHelper.js
  71. 5 5
      src/helpers/FaceNormalsHelper.js
  72. 4 4
      src/helpers/GridHelper.js
  73. 6 6
      src/helpers/HemisphereLightHelper.js
  74. 60 0
      src/helpers/PlaneHelper.js
  75. 4 4
      src/helpers/PointLightHelper.js
  76. 6 6
      src/helpers/PolarGridHelper.js
  77. 8 8
      src/helpers/SkeletonHelper.js
  78. 6 6
      src/helpers/SpotLightHelper.js
  79. 5 5
      src/helpers/VertexNormalsHelper.js
  80. 1 1
      src/materials/MeshNormalMaterial.js
  81. 2 2
      src/math/Matrix3.js
  82. 14 4
      src/math/Matrix4.js
  83. 7 15
      src/math/Plane.js
  84. 4 4
      src/math/Vector2.js
  85. 17 11
      src/math/Vector3.js
  86. 19 5
      src/math/Vector4.js
  87. 3 4
      src/objects/Mesh.js
  88. 98 141
      src/renderers/WebGLRenderer.js
  89. 3 3
      src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl
  90. 1 1
      src/renderers/shaders/ShaderChunk/displacementmap_vertex.glsl
  91. 1 9
      src/renderers/shaders/ShaderChunk/project_vertex.glsl
  92. 6 4
      src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl
  93. 2 1
      src/renderers/shaders/ShaderChunk/skinning_vertex.glsl
  94. 1 9
      src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl
  95. 6 3
      src/renderers/shaders/ShaderLib.js
  96. 9 1
      src/renderers/shaders/ShaderLib/depth_vert.glsl
  97. 9 0
      src/renderers/shaders/ShaderLib/distanceRGBA_frag.glsl
  98. 3 0
      src/renderers/shaders/ShaderLib/distanceRGBA_vert.glsl
  99. 1 1
      src/renderers/shaders/ShaderLib/meshphong_vert.glsl
  100. 1 1
      src/renderers/shaders/ShaderLib/meshphysical_vert.glsl

+ 1 - 1
README.md

@@ -66,7 +66,7 @@ function animate() {
 }
 ```
 
-If everything went well you should see [this](http://jsfiddle.net/hfj7gm6t/).
+If everything went well you should see [this](https://jsfiddle.net/hfj7gm6t/).
 
 ### Change log ###
 

File diff suppressed because it is too large
+ 55 - 25
build/three.js


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


File diff suppressed because it is too large
+ 55 - 25
build/three.module.js


+ 1 - 1
docs/api/materials/Material.html

@@ -84,7 +84,7 @@
 		<div>
 		User-defined clipping planes specified as THREE.Plane objects in world space.
 		These planes apply to the objects this material is attached to.
-		Points in space whose dot product with the plane is negative are cut away.
+		Points in space whose signed distance to the plane is negative are clipped (not rendered).
 		See the [example:webgl_clipping_intersection WebGL / clipping /intersection] example.
 		Default is *null*.
 		</div>

+ 6 - 2
docs/api/materials/MeshBasicMaterial.html

@@ -63,7 +63,9 @@
 		</div>
 
 		<h3>[property:Texture aoMap]</h3>
-		<div>The red channel of this texture is used as the ambient occlusion map. Default is null. The aoMap requires a second set of UVs.</div>
+		<div>The red channel of this texture is used as the ambient occlusion map. Default is null. 
+		The aoMap requires a second set of UVs, and consequently will ignore the [page:Texture repeat]
+		and [page:Texture offset] Texture properties.</div>
 
 		<h3>[property:Float aoMapIntensity]</h3>
 		<div>Intensity of the ambient occlusion effect. Default is 1. Zero is no occlusion effect.</div>
@@ -91,7 +93,9 @@
 		<div>The environment map. Default is null.</div>
 
 		<h3>[property:Texture lightMap]</h3>
-		<div>The light map. Default is null. The lightMap requires a second set of UVs.</div>
+		<div>The light map. Default is null. The lightMap requires a second set of UVs, 
+		and consequently will ignore the [page:Texture repeat] and [page:Texture offset] 
+		Texture properties.</div>
 
 		<h3>[property:Float lightMapIntensity]</h3>
 		<div>Intensity of the baked light. Default is 1.</div>

+ 6 - 2
docs/api/materials/MeshLambertMaterial.html

@@ -74,7 +74,9 @@
 		</div>
 
 		<h3>[property:Texture aoMap]</h3>
-		<div>The red channel of this texture is used as the ambient occlusion map. Default is null. The aoMap requires a second set of UVs.</div>
+		<div>The red channel of this texture is used as the ambient occlusion map. Default is null. 
+		The aoMap requires a second set of UVs, and consequently will ignore the [page:Texture repeat]
+		and [page:Texture offset] Texture properties.</div>
 
 		<h3>[property:Float aoMapIntensity]</h3>
 		<div>Intensity of the ambient occlusion effect. Default is 1. Zero is no occlusion effect.</div>
@@ -118,7 +120,9 @@
 		</div>
 
 		<h3>[property:Texture lightMap]</h3>
-		<div>The light map. Default is null. The lightMap requires a second set of UVs.</div>
+		<div>The light map. Default is null. The lightMap requires a second set of UVs, 
+		and consequently will ignore the [page:Texture repeat] and [page:Texture offset] 
+		Texture properties.</div>
 
 		<h3>[property:Float lightMapIntensity]</h3>
 		<div>Intensity of the baked light. Default is 1.</div>

+ 6 - 2
docs/api/materials/MeshPhongMaterial.html

@@ -73,7 +73,9 @@
 		</div>
 
 		<h3>[property:Texture aoMap]</h3>
-		<div>The red channel of this texture is used as the ambient occlusion map. Default is null. The aoMap requires a second set of UVs.</div>
+		<div>The red channel of this texture is used as the ambient occlusion map. Default is null. 
+		The aoMap requires a second set of UVs, and consequently will ignore the [page:Texture repeat]
+		and [page:Texture offset] Texture properties.</div>
 
 		<h3>[property:Float aoMapIntensity]</h3>
 		<div>Intensity of the ambient occlusion effect. Default is 1. Zero is no occlusion effect.</div>
@@ -151,7 +153,9 @@
 
 
 		<h3>[property:Texture lightMap]</h3>
-		<div>The light map. Default is null. The lightMap requires a second set of UVs.</div>
+		<div>The light map. Default is null. The lightMap requires a second set of UVs, 
+		and consequently will ignore the [page:Texture repeat] and [page:Texture offset] 
+		Texture properties.</div>
 
 		<h3>[property:Float lightMapIntensity]</h3>
 		<div>Intensity of the baked light. Default is 1.</div>

+ 6 - 2
docs/api/materials/MeshStandardMaterial.html

@@ -97,7 +97,9 @@
 		</div>
 
 		<h3>[property:Texture aoMap]</h3>
-		<div>The red channel of this texture is used as the ambient occlusion map. Default is null. The aoMap requires a second set of UVs.</div>
+		<div>The red channel of this texture is used as the ambient occlusion map. Default is null. 
+		The aoMap requires a second set of UVs, and consequently will ignore the [page:Texture repeat]
+		and [page:Texture offset] Texture properties.</div>
 
 		<h3>[property:Float aoMapIntensity]</h3>
 		<div>Intensity of the ambient occlusion effect. Default is 1. Zero is no occlusion effect.</div>
@@ -182,7 +184,9 @@
 
 
 		<h3>[property:Texture lightMap]</h3>
-		<div>The light map. Default is null. The lightMap requires a second set of UVs.</div>
+		<div>The light map. Default is null. The lightMap requires a second set of UVs, 
+		and consequently will ignore the [page:Texture repeat] and [page:Texture offset] 
+		Texture properties.</div>
 
 		<h3>[property:Float lightMapIntensity]</h3>
 		<div>Intensity of the baked light. Default is 1.</div>

+ 4 - 13
docs/api/math/Euler.html

@@ -54,19 +54,10 @@
 			rotated around its X axis, then its Y axis and finally its Z axis. Other possibilities are:
 			'YZX', 'ZXY', 'XZY', 'YXZ' and 'ZYX'. These must be in upper case.<br /><br />
 
-			Three.js uses <em>intrinsic</em> (Tait-Bryan) ordering, also known as <em>yaw</em>, <em>pitch</em>
-			and <em>roll</em>. This means that rotations are performed with respect to the <em>local</em>
-			coordinate system. That is, for order 'XYZ', the rotation is first around world-X, then around
-			local-Y (which may now be different from the world Y-axis), then local-Z (which may be different
-			from the world Z-axis).<br /><br />
-
-			Some implementations may use <em>extrinsic</em> (proper) ordering, in which case rotations are performed
-			with respect to the <em>world</em> coordinate system, so that for order 'XYZ', the rotations
-			are around world-X, world-Y, and world-Z.<br /><br />
-
-			Converting between the two types is relatively straightforward, you just need to reverse the order
-			and the rotation, so that an intrinsic (three.js) Euler rotation of angles a, b, c about XYZ
-			will be equivalent to to an extrinsic Euler rotation of angles c, b, a about ZYX.<br /><br />
+			Three.js uses <em>intrinsic</em> Tait-Bryan angles. This means that rotations are performed with respect
+			to the <em>local</em> coordinate system. That is, for order 'XYZ', the rotation is first around the local-X
+			axis (which is the same as the world-X axis), then around local-Y (which may now be different from the
+			world Y-axis), then local-Z (which may be different from the world Z-axis).<br /><br />
 
 			If the order is changed, [page:.onChangeCallback onChangeCallback] will be called.
 		</div>

+ 16 - 34
docs/api/math/Plane.html

@@ -11,9 +11,8 @@
 		<h1>[name]</h1>
 
 		<div class="desc">
-			A two dimensional surface that extends infinitely in 3d space, defined by
-			a [link:https://en.wikipedia.org/wiki/Normal_(geometry) normal vector], and a
-			distance from the origin along the normal.
+			A two dimensional surface that extends infinitely in 3d space, represented in [link:http://mathworld.wolfram.com/HessianNormalForm.html Hessian normal form]
+			by a normal vector and a constant.
 		</div>
 
 
@@ -22,10 +21,8 @@
 
 		<h3>[name]( [page:Vector3 normal], [page:Float constant] )</h3>
 		<div>
-		[page:Vector3 normal] - (optional) a [page:Vector3] defining the direction of the
-		plane. Default is *(1, 0, 0)*.<br />
-		[page:Float constant] - (optional) the negative distance from the origin to the plane along
-		 the [page:Vector3 normal] vector. Default is *0*.
+		[page:Vector3 normal] - (optional) a [page:Vector3] defining the normal of the plane. Default is *(1, 0, 0)*.<br />
+		[page:Float constant] - (optional) the signed distance from the origin to the plane. Default is *0*.
 		</div>
 
 
@@ -68,10 +65,10 @@
 		</div>
 
 		<h3>[method:Float distanceToPoint]( [page:Vector3 point] )</h3>
-		<div>Returns the smallest distance from the [page:Vector3 point] to the plane.</div>
+		<div>Returns the signed distance from the [page:Vector3 point] to the plane.</div>
 
 		<h3>[method:Float distanceToSphere]( [page:Sphere sphere] )</h3>
-		<div>Returns the smallest distance from the [page:Sphere sphere] to the plane.</div>
+		<div>Returns the signed distance from the [page:Sphere sphere] to the plane.</div>
 
 		<h3>[method:Boolean equals]( [page:Plane plane] )</h3>
 		<div>
@@ -113,8 +110,7 @@
 
 		<h3>[method:Plane negate]()</h3>
 		<div>
-		Negates both the normal vector and constant, effectively mirroring the plane across
-		the origin.
+		Negates both the normal vector and the constant.
 		</div>
 
 		<h3>[method:Plane normalize]()</h3>
@@ -123,32 +119,19 @@
 			value accordingly.
 		</div>
 
-		<h3>[method:Vector3 orthoPoint]( [page:Vector3 point], [page:Vector3 optionalTarget] )</h3>
-		<div>
-		[page:Vector3 point] - [page:Vector3] <br />
-		[page:Vector3 optionalTarget] - (optional) if specified, the result will be copied
-		into this [page:Vector3], otherwise a new [page:Vector3] will be created.<br /><br />
-
-		Returns a vector in the same direction as the Plane's normal, but with magnitude
-		equal to the passed point's original distance to the plane.
-		</div>
-
 		<h3>[method:Vector3 projectPoint]( [page:Vector3 point], [page:Vector3 optionalTarget] )</h3>
 		<div>
 		[page:Vector3 point] - the [page:Vector3] to project onto the plane.<br />
 		[page:Vector3 optionalTarget] - (optional) if specified, the result will be copied into this [page:Vector3],
 		otherwise a new [page:Vector3] will be created.<br /><br />
 
-		Projects a [page:Vector3 point] onto the plane. The projected point is the closest
-		 point on the plane to the passed point, so a line drawn from the projected point
-		 and the passed point would be orthogonal to the plane.
+		Projects a [page:Vector3 point] onto the plane.
 		</div>
 
 		<h3>[method:Plane set]( [page:Vector3 normal], [page:Float constant] )</h3>
 		<div>
-			[page:Vector3 normal] -  a [page:Vector3] defining the direction of the	plane.<br />
-			[page:Float constant] - (optional) the negative distance from the origin to the plane along
-			 the [page:Vector3 normal] vector. Default is *0*.<br /><br />
+			[page:Vector3 normal] - a [page:Vector3] defining the normal of the plane.<br />
+			[page:Float constant] - the signed distance from the origin to the plane. Default is *0*.<br /><br />
 
 			 Sets the plane's [page:.normal normal] and [page:.constant constant] properties.
 		</div>
@@ -160,7 +143,7 @@
 		[page:Float z] - z value of the normal vector.<br />
 		[page:Float w] - the value of the plane's [page:.constant constant] property.<br /><br />
 
-		Set the individual components that make up the plane.
+		Set the individual components that define the plane.
 		</div>
 
 		<h3>[method:Plane setFromCoplanarPoints]( [page:Vector3 a], [page:Vector3 b], [page:Vector3 c] )</h3>
@@ -169,13 +152,13 @@
 		 [page:Vector3 a] - second point on the plane.<br />
 		 [page:Vector3 a] - third point on the plane.<br /><br />
 
-		Defines the plane based on the 3 provided points. The winding order is counter
-		clockwise, and determines which direction the [page:.normal normal] will point.
+		Defines the plane based on the 3 provided points. The winding order is assumed to be counter-clockwise,
+		and determines the direction of the [page:.normal normal].
 		</div>
 
 		<h3>[method:Plane setFromNormalAndCoplanarPoint]( [page:Vector3 normal], [page:Vector3 point] ) [page:Vector3 this]</h3>
 		<div>
-		[page:Vector3 normal] - a [page:Vector3] defining the direction of the plane.<br />
+		[page:Vector3 normal] - a [page:Vector3] defining the normal of the plane.<br />
 		[page:Vector3 point] - [page:Vector3]<br /><br />
 
 		Sets the plane's properties as defined by a [page:Vector3 normal] and an arbitrary coplanar [page:Vector3 point].
@@ -185,9 +168,8 @@
 		<div>
 		[page:Vector3 offset] - the amount to move the plane by.<br /><br />
 
-		Translates the plane the distance defined by the [page:Vector3 offset] vector.
-		Note that this only affects	the constant (distance from origin) and will not affect
-		the normal vector.
+		Translates the plane by the distance defined by the [page:Vector3 offset] vector.
+		Note that this only affects the plane constant and will not affect the normal vector.
 		</div>
 
 		<h2>Source</h2>

+ 9 - 0
docs/api/math/Vector4.html

@@ -110,6 +110,15 @@ var d = a.dot( b );
 		If this vector's x, y, z or w value is less than the min vector's x, y, z or w value, it is replaced by the corresponding value.
 		</div>
 
+		<h3>[method:Vector4 clampLength]( [page:Float min], [page:Float max] )</h3>
+		<div>
+		[page:Float min] - the minimum value the length will be clamped to <br />
+		[page:Float max] - the maximum value the length will be clamped to<br /><br />
+
+		If this vector's length is greater than the max value, it is replaced by the max value. <br /><br />
+		If this vector's length is less than the min value, it is replaced by the min value.
+		</div>
+
 		<h3>[method:Vector4 clampScalar]( [page:Float min], [page:Float max] )</h3>
 		<div>
 		[page:Float min] - the minimum value the components will be clamped to <br />

+ 1 - 1
docs/api/objects/Group.html

@@ -28,7 +28,7 @@
 		cubeA.position.set( 100, 100, 0 );
 
 		var cubeB = new THREE.Mesh( geometry, material );
-		cubeA.position.set( -100, -100, 0 );
+		cubeB.position.set( -100, -100, 0 );
 
 		//create a group and add the two cubes
 		//These cubes can now be rotated / scaled etc as a group

+ 3 - 0
docs/api/renderers/WebGLRenderer.html

@@ -353,6 +353,9 @@
 		<h3>[method:Number getMaxAnisotropy]()</h3>
 		<div>This returns the anisotropy level of the textures.</div>
 
+		<h3>[method:Object getDrawingBufferSize]()</h3>
+		<div>Returns an object containing the width and height of the renderer's drawing buffer, in pixels.</div>
+
 		<h3>[method:number getPixelRatio]()</h3>
 		<div>Returns current device pixel ratio used.</div>
 

+ 1 - 1
examples/css3d_sandbox.html

@@ -66,7 +66,7 @@
 					var element = document.createElement( 'div' );
 					element.style.width = '100px';
 					element.style.height = '100px';
-					element.style.opacity = 0.5;
+					element.style.opacity = ( i < 5 ) ? 0.5 : 1;
 					element.style.background = new THREE.Color( Math.random() * 0xffffff ).getStyle();
 
 					var object = new THREE.CSS3DObject( element );

+ 2 - 0
examples/files.js

@@ -111,6 +111,7 @@ var files = {
 		"webgl_loader_pcd",
 		"webgl_loader_pdb",
 		"webgl_loader_ply",
+		"webgl_loader_prwm",
 		"webgl_loader_ttf",
 		"webgl_loader_sea3d",
 		"webgl_loader_sea3d_hierarchy",
@@ -245,6 +246,7 @@ var files = {
 		"webgl_simple_gi",
 		"webgl_skinning_simple",
 		"webgl_sprites",
+		"webgl_sprites_nodes",
 		"webgl_terrain_dynamic",
 		"webgl_test_memory",
 		"webgl_test_memory2",

+ 8 - 7
examples/js/GPUParticleSystem.js

@@ -461,13 +461,14 @@ THREE.GPUParticleContainer = function( maxParticles, particleSystem ) {
 				sizeAttribute.updateRange.offset = 0;
 				lifeTimeAttribute.updateRange.offset = 0;
 
-				positionStartAttribute.updateRange.count = positionStartAttribute.count;
-				startTimeAttribute.updateRange.count = startTimeAttribute.count;
-				velocityAttribute.updateRange.count = velocityAttribute.count;
-				turbulenceAttribute.updateRange.count = turbulenceAttribute.count;
-				colorAttribute.updateRange.count = colorAttribute.count;
-				sizeAttribute.updateRange.count = sizeAttribute.count;
-				lifeTimeAttribute.updateRange.count = lifeTimeAttribute.count;
+				// Use -1 to update the entire buffer, see #11476
+				positionStartAttribute.updateRange.count = -1;
+				startTimeAttribute.updateRange.count = -1;
+				velocityAttribute.updateRange.count = -1;
+				turbulenceAttribute.updateRange.count = -1;
+				colorAttribute.updateRange.count = -1;
+				sizeAttribute.updateRange.count = -1;
+				lifeTimeAttribute.updateRange.count = -1;
 
 			}
 

+ 25 - 15
examples/js/Mirror.js

@@ -27,10 +27,13 @@ THREE.Mirror = function ( width, height, options ) {
 	var lookAtPosition = new THREE.Vector3( 0, 0, - 1 );
 	var clipPlane = new THREE.Vector4();
 
+	var view = new THREE.Vector3();
+	var target = new THREE.Vector3();
+	var q = new THREE.Vector4();
+
 	var textureMatrix = new THREE.Matrix4();
 
 	var mirrorCamera = new THREE.PerspectiveCamera();
-	mirrorCamera.matrixAutoUpdate = true;
 
 	var parameters = {
 		minFilter: THREE.LinearFilter,
@@ -106,11 +109,6 @@ THREE.Mirror = function ( width, height, options ) {
 
 	function updateTextureMatrix( camera ) {
 
-		camera.updateMatrixWorld();
-
-		mirrorCamera.copy( camera );
-		mirrorCamera.updateProjectionMatrix();
-
 		scope.updateMatrixWorld();
 
 		mirrorWorldPosition.setFromMatrixPosition( scope.matrixWorld );
@@ -121,7 +119,7 @@ THREE.Mirror = function ( width, height, options ) {
 		normal.set( 0, 0, 1 );
 		normal.applyMatrix4( rotationMatrix );
 
-		var view = mirrorWorldPosition.clone().sub( cameraWorldPosition );
+		view.subVectors( mirrorWorldPosition, cameraWorldPosition );
 		view.reflect( normal ).negate();
 		view.add( mirrorWorldPosition );
 
@@ -131,7 +129,7 @@ THREE.Mirror = function ( width, height, options ) {
 		lookAtPosition.applyMatrix4( rotationMatrix );
 		lookAtPosition.add( cameraWorldPosition );
 
-		var target = mirrorWorldPosition.clone().sub( lookAtPosition );
+		target.subVectors( mirrorWorldPosition, lookAtPosition );
 		target.reflect( normal ).negate();
 		target.add( mirrorWorldPosition );
 
@@ -141,8 +139,11 @@ THREE.Mirror = function ( width, height, options ) {
 		mirrorCamera.up.reflect( normal ).negate();
 		mirrorCamera.lookAt( target );
 
-		mirrorCamera.updateProjectionMatrix();
+		mirrorCamera.near = camera.near;
+		mirrorCamera.far = camera.far;
+
 		mirrorCamera.updateMatrixWorld();
+		mirrorCamera.updateProjectionMatrix();
 
 		// Update the texture matrix
 		textureMatrix.set(
@@ -161,7 +162,6 @@ THREE.Mirror = function ( width, height, options ) {
 
 		clipPlane.set( mirrorPlane.normal.x, mirrorPlane.normal.y, mirrorPlane.normal.z, mirrorPlane.constant );
 
-		var q = new THREE.Vector4();
 		var projectionMatrix = mirrorCamera.projectionMatrix;
 
 		q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
@@ -170,13 +170,13 @@ THREE.Mirror = function ( width, height, options ) {
 		q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];
 
 		// Calculate the scaled plane vector
-		var c = clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) );
+		clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) );
 
 		// Replacing the third row of the projection matrix
-		projectionMatrix.elements[ 2 ] = c.x;
-		projectionMatrix.elements[ 6 ] = c.y;
-		projectionMatrix.elements[ 10 ] = c.z + 1.0 - clipBias;
-		projectionMatrix.elements[ 14 ] = c.w;
+		projectionMatrix.elements[ 2 ] = clipPlane.x;
+		projectionMatrix.elements[ 6 ] = clipPlane.y;
+		projectionMatrix.elements[ 10 ] = clipPlane.z + 1.0 - clipBias;
+		projectionMatrix.elements[ 14 ] = clipPlane.w;
 
 	}
 
@@ -188,7 +188,17 @@ THREE.Mirror = function ( width, height, options ) {
 
 		var currentRenderTarget = renderer.getRenderTarget();
 
+		var currentVrEnabled = renderer.vr.enabled;
+		var currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;
+
+		renderer.vr.enabled = false; // Avoid camera modification and recursion
+		renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
+
 		renderer.render( scene, mirrorCamera, renderTarget, true );
+
+		renderer.vr.enabled = currentVrEnabled;
+		renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
+
 		renderer.setRenderTarget( currentRenderTarget );
 
 		scope.visible = true;

+ 2 - 0
examples/js/controls/OrbitControls.js

@@ -888,6 +888,8 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function onContextMenu( event ) {
 
+		if ( scope.enabled === false ) return;
+
 		event.preventDefault();
 
 	}

+ 2 - 0
examples/js/controls/TrackballControls.js

@@ -579,6 +579,8 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 	function contextmenu( event ) {
 
+		if ( _this.enabled === false ) return;
+
 		event.preventDefault();
 
 	}

+ 4 - 11
examples/js/effects/OutlineEffect.js

@@ -93,27 +93,20 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 	var vertexShaderChunk2 = [
 
 		"#if ! defined( LAMBERT ) && ! defined( PHONG ) && ! defined( TOON ) && ! defined( PHYSICAL )",
-
 		"	#ifndef USE_ENVMAP",
 		"		vec3 objectNormal = normalize( normal );",
-
-		"		#ifdef FLIP_SIDED",
-		"			objectNormal = -objectNormal;",
-		"		#endif",
-
 		"	#endif",
+		"#endif",
 
+		"#ifdef FLIP_SIDED",
+		"	objectNormal = -objectNormal;",
 		"#endif",
 
 		"#ifdef DECLARE_TRANSFORMED",
 		"	vec3 transformed = vec3( position );",
 		"#endif",
 
-		"#ifdef USE_SKINNING",
-		"	gl_Position = calculateOutline( gl_Position, objectNormal, skinned );",
-		"#else",
-		"	gl_Position = calculateOutline( gl_Position, objectNormal, vec4( transformed, 1.0 ) );",
-		"#endif",
+		"gl_Position = calculateOutline( gl_Position, objectNormal, vec4( transformed, 1.0 ) );",
 
 		"#include <fog_vertex>"
 

+ 151 - 34
examples/js/loaders/ColladaLoader2.js

@@ -432,8 +432,10 @@ THREE.ColladaLoader.prototype = {
 
 			var keyframes = prepareAnimationData( data, defaultMatrix );
 
+			if ( node.type !== 'JOINT' ) console.warn( 'THREE.ColladaLoader: Animation data for invalid node with ID "%s" found. The loader only supports animation of bones (skeletal animation).', node.id );
+
 			var animation = {
-				name: '.bones[' + node.sid + ']',
+				name: '.skeleton.bones[' + node.sid + ']',
 				keyframes: keyframes
 			}
 
@@ -864,7 +866,7 @@ THREE.ColladaLoader.prototype = {
 			var BONE_LIMIT = 4;
 
 			var build = {
-				bones: {},
+				joints: [], // this must be an array to preserve the joint order
 				indices: {
 					array: [],
 					stride: BONE_LIMIT
@@ -949,7 +951,7 @@ THREE.ColladaLoader.prototype = {
 				var name = jointSource.array[ i ];
 				var boneInverse = new THREE.Matrix4().fromArray( inverseSource.array, i * inverseSource.stride ).transpose();
 
-				build.bones[ name ] = boneInverse;
+				build.joints.push( { name: name, boneInverse: boneInverse } );
 
 			}
 
@@ -1219,7 +1221,9 @@ THREE.ColladaLoader.prototype = {
 
 		function parseEffectParameterTexture( xml ) {
 
-			var data = {};
+			var data = {
+				technique: {}
+			};
 
 			for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
 
@@ -1230,7 +1234,7 @@ THREE.ColladaLoader.prototype = {
 				switch ( child.nodeName ) {
 
 					case 'extra':
-						data = parseEffectParameterTextureExtra( child );
+						parseEffectParameterTextureExtra( child, data );
 						break;
 
 				}
@@ -1241,9 +1245,7 @@ THREE.ColladaLoader.prototype = {
 
 		}
 
-		function parseEffectParameterTextureExtra( xml ) {
-
-			var data = {};
+		function parseEffectParameterTextureExtra( xml, data ) {
 
 			for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
 
@@ -1254,20 +1256,16 @@ THREE.ColladaLoader.prototype = {
 				switch ( child.nodeName ) {
 
 					case 'technique':
-						data[ child.nodeName ] = parseEffectParameterTextureExtraTechnique( child );
+						parseEffectParameterTextureExtraTechnique( child, data );
 						break;
 
 				}
 
 			}
 
-			return data;
-
 		}
 
-		function parseEffectParameterTextureExtraTechnique( xml ) {
-
-			var data = {};
+		function parseEffectParameterTextureExtraTechnique( xml, data ) {
 
 			for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
 
@@ -1281,20 +1279,34 @@ THREE.ColladaLoader.prototype = {
 					case 'repeatV':
 					case 'offsetU':
 					case 'offsetV':
-						data[ child.nodeName ] = parseFloat( child.textContent );
+						data.technique[ child.nodeName ] = parseFloat( child.textContent );
 						break;
 
 					case 'wrapU':
 					case 'wrapV':
-						data[ child.nodeName ] = parseInt( child.textContent );
+
+						// some files have values for wrapU/wrapV which become NaN via parseInt
+
+						if ( child.textContent.toUpperCase() === 'TRUE' ) {
+
+							data.technique[ child.nodeName ] = 1;
+
+						} else if ( child.textContent.toUpperCase() === 'FALSE' ) {
+
+							data.technique[ child.nodeName ] = 0;
+
+						} else {
+
+							data.technique[ child.nodeName ] = parseInt( child.textContent );
+
+						}
+
 						break;
 
 				}
 
 			}
 
-			return data;
-
 		}
 
 		function buildEffect( data ) {
@@ -1415,8 +1427,8 @@ THREE.ColladaLoader.prototype = {
 						if ( parameter.texture ) material.map = getTexture( parameter.texture );
 						break;
 					case 'specular':
-						if ( parameter.color && material.specular )
-							material.specular.fromArray( parameter.color );
+						if ( parameter.color && material.specular ) material.specular.fromArray( parameter.color );
+						if ( parameter.texture ) material.specularMap = getTexture( parameter.texture );
 						break;
 					case 'shininess':
 						if ( parameter.float && material.shininess )
@@ -2191,7 +2203,8 @@ THREE.ColladaLoader.prototype = {
 
 			var data = {
 				id: parseId( xml.getAttribute( 'url' ) ),
-				materials: {}
+				materials: {},
+				skeletons: []
 			};
 
 			for ( var i = 0; i < xml.childNodes.length; i ++ ) {
@@ -2216,7 +2229,7 @@ THREE.ColladaLoader.prototype = {
 						break;
 
 					case 'skeleton':
-						data.skeleton = parseId( child.textContent );;
+						data.skeletons.push( parseId( child.textContent ) );
 						break;
 
 					default:
@@ -2230,24 +2243,128 @@ THREE.ColladaLoader.prototype = {
 
 		}
 
-		function getSkeleton( root, controller ) {
+		function getSkeleton( skeletons, joints, skinnedMesh ) {
+
+			var boneData = [];
+			var sortedBoneData = [];
+
+			var i, j, data;
+
+			// a skeleton can have multiple root bones. collada expresses this
+			// situtation with multiple "skeleton" tags per controller instance
+
+			for ( i = 0; i < skeletons.length; i ++ ) {
+
+				var skeleton = skeletons[ i ];
+				var root = getNode( skeleton );
+
+				// bone hierarchy is a child of the skinned mesh
+
+				skinnedMesh.add( root );
+
+				// setup bone data for a single bone hierarchy
+
+				buildBoneHierarchy( root, joints, boneData );
+
+			}
+
+			// sort bone data (the order is defined in the corresponding controller)
+
+			for ( i = 0; i < joints.length; i ++ ) {
+
+				for ( j = 0; j < boneData.length; j ++ ) {
+
+					data = boneData[ j ];
+
+					if ( data.bone.name === joints[ i ].name ) {
+
+						sortedBoneData[ i ] = data;
+						data.processed = true;
+						break;
+
+					}
+
+				}
+
+			}
+
+			// add unprocessed bone data at the end of the list
+
+			for ( i = 0; i < boneData.length; i ++ ) {
+
+				data = boneData[ i ];
+
+				if ( data.processed === false ) {
+
+					sortedBoneData.push( data );
+					data.processed = true;
+
+				}
+
+			}
+
+			// setup arrays for skeleton creation
+
+			var bones = [];
+			var boneInverses = [];
+
+			for ( i = 0; i < sortedBoneData.length; i ++ ) {
+
+				data = sortedBoneData[ i ];
+
+				bones.push( data.bone );
+				boneInverses.push( data.boneInverse );
+
+			}
+
+			return new THREE.Skeleton( bones, boneInverses );
+
+		}
+
+		function buildBoneHierarchy( root, joints, boneData ) {
 
-			var boneArray = [];
-			var boneInverseArray = [];
+			// setup bone data from visual scene
 
 			root.traverse( function( object ) {
 
 				if ( object.isBone === true ) {
 
-					boneArray.push( object );
-					boneInverseArray.push( controller.skin.bones[ object.name ] );
+					var boneInverse;
+
+					// retrieve the boneInverse from the controller data
+
+					for ( var i = 0; i < joints.length; i ++ ) {
+
+						var joint = joints[ i ];
+
+						if ( joint.name === object.name ) {
+
+							boneInverse = joint.boneInverse;
+							break;
+
+						}
+
+					}
+
+					if ( boneInverse === undefined ) {
+
+						// Unfortunately, there can be joints in the visual scene that are not part of the
+						// corresponding controller. In this case, we have to create a dummy boneInverse matrix
+						// for the respective bone. This bone won't affect any vertices, because there are no skin indices
+						// and weights defined for it. But we still have to add the bone to the sorted bone list in order to
+						// ensure a correct animation of the model.
+
+						 boneInverse = new THREE.Matrix4();
+						 console.warn( 'THREE.ColladaLoader: Missing data for bone: %s.', object.name );
+
+					}
+
+					boneData.push( { bone: object, boneInverse: boneInverse, processed: false } );
 
 				}
 
 			} );
 
-			return new THREE.Skeleton( boneArray, boneInverseArray );
-
 		}
 
 		function buildNode( data ) {
@@ -2265,7 +2382,7 @@ THREE.ColladaLoader.prototype = {
 
 			for ( var i = 0, l = nodes.length; i < l; i ++ ) {
 
-				objects.push( getNode( nodes[ i ] ).clone() );
+				objects.push( getNode( nodes[ i ] ) );
 
 			}
 
@@ -2283,13 +2400,13 @@ THREE.ColladaLoader.prototype = {
 				var materials = resolveMaterialBinding( geometry.materialKeys, instance.materials );
 				var object = getObject( geometry, materials );
 
-				var node = getNode( instance.skeleton );
-				var skeleton = getSkeleton( node, controller );
+				var skeletons = instance.skeletons;
+				var joints = controller.skin.joints;
+
+				var skeleton = getSkeleton( skeletons, joints, object );
 
 				object.bind( skeleton, controller.skin.bindMatrix );
 				object.normalizeSkinWeights();
-				object.bones = skeleton.bones; // this is necessary for property binding
-				object.add( node ); // bone hierarchy is a child of the skinned mesh
 
 				objects.push( object );
 

+ 77 - 18
examples/js/loaders/FBXLoader.js

@@ -738,8 +738,38 @@
 
 		}
 
+		var weightTable = {};
+
+		if ( deformer ) {
+
+			var subDeformers = deformer.map;
+
+			for ( var key in subDeformers ) {
+
+				var subDeformer = subDeformers[ key ];
+				var indices = subDeformer.indices;
+
+				for ( var j = 0; j < indices.length; j ++ ) {
+
+					var index = indices[ j ];
+					var weight = subDeformer.weights[ j ];
+
+					if ( weightTable[ index ] === undefined ) weightTable[ index ] = [];
+
+					weightTable[ index ].push( {
+						id: subDeformer.index,
+						weight: weight
+					} );
+
+				}
+
+			}
+
+		}
+
 		var faceVertexBuffer = [];
 		var polygonIndex = 0;
+		var displayedWeightsWarning = false;
 
 		for ( var polygonVertexIndex = 0; polygonVertexIndex < indexBuffer.length; polygonVertexIndex ++ ) {
 
@@ -763,25 +793,14 @@
 
 			if ( deformer ) {
 
-				var subDeformers = deformer.map;
-
-				for ( var key in subDeformers ) {
+				if ( weightTable[ vertexIndex ] !== undefined ) {
 
-					var subDeformer = subDeformers[ key ];
-					var indices = subDeformer.indices;
+					var array = weightTable[ vertexIndex ];
 
-					for ( var j = 0; j < indices.length; j ++ ) {
+					for ( var j = 0, jl = array.length; j < jl; j ++ ) {
 
-						var index = indices[ j ];
-
-						if ( index === vertexIndex ) {
-
-							weights.push( subDeformer.weights[ j ] );
-							weightIndices.push( subDeformer.index );
-
-							break;
-
-						}
+						weights.push( array[ j ].weight );
+						weightIndices.push( array[ j ].id );
 
 					}
 
@@ -789,7 +808,12 @@
 
 				if ( weights.length > 4 ) {
 
-					console.warn( 'FBXLoader: Vertex has more than 4 skinning weights assigned to vertex.  Deleting additional weights.' );
+					if ( ! displayedWeightsWarning ) {
+
+						console.warn( 'FBXLoader: Vertex has more than 4 skinning weights assigned to vertex.  Deleting additional weights.' );
+						displayedWeightsWarning = true;
+
+					}
 
 					var WIndex = [ 0, 0, 0, 0 ];
 					var Weight = [ 0, 0, 0, 0 ];
@@ -2154,6 +2178,41 @@
 			if ( curveNode.attr === 'R' ) {
 
 				var curves = curveNode.curves;
+
+				// Seems like some FBX files have AnimationCurveNode
+				// which doesn't have any connected AnimationCurve.
+				// Setting animation parameter for them here.
+
+				if ( curves.x === null ) {
+
+					curves.x = {
+						version: null,
+						times: [ 0.0 ],
+						values: [ 0.0 ]
+					};
+
+				}
+
+				if ( curves.y === null ) {
+
+					curves.y = {
+						version: null,
+						times: [ 0.0 ],
+						values: [ 0.0 ]
+					};
+
+				}
+
+				if ( curves.z === null ) {
+
+					curves.z = {
+						version: null,
+						times: [ 0.0 ],
+						values: [ 0.0 ]
+					};
+
+				}
+
 				curves.x.values = curves.x.values.map( degreeToRadian );
 				curves.y.values = curves.y.values.map( degreeToRadian );
 				curves.z.values = curves.z.values.map( degreeToRadian );
@@ -4270,7 +4329,7 @@
 
 					if ( window.Zlib === undefined ) {
 
-						throw new Error( 'FBXLoader: Import inflate.min.js from https://github.com/imaya/zlib.js' );
+						throw new Error( 'FBXLoader: External library Inflate.min.js required, obtain or import from https://github.com/imaya/zlib.js' );
 
 					}
 

+ 66 - 31
examples/js/loaders/GLTF2Loader.js

@@ -336,6 +336,36 @@ THREE.GLTF2Loader = ( function () {
 
 			if ( lightNode ) {
 
+				if ( light.constantAttenuation !== undefined ) {
+
+					lightNode.intensity = light.constantAttenuation;
+
+				}
+
+				if ( light.linearAttenuation !== undefined ) {
+
+					lightNode.distance = 1 / light.linearAttenuation;
+
+				}
+
+				if ( light.quadraticAttenuation !== undefined ) {
+
+					lightNode.decay = light.quadraticAttenuation;
+
+				}
+
+				if ( light.fallOffAngle !== undefined ) {
+
+					lightNode.angle = light.fallOffAngle;
+
+				}
+
+				if ( light.fallOffExponent !== undefined ) {
+
+					console.warn( 'GLTF2Loader: light.fallOffExponent not currently supported.' );
+
+				}
+
 				lightNode.name = light.name || ( 'light_' + lightId );
 				this.lights[ lightId ] = lightNode;
 
@@ -412,6 +442,7 @@ THREE.GLTF2Loader = ( function () {
 		if ( materialValues.diffuseFactor !== undefined ) {
 
 			materialParams.color = new THREE.Color().fromArray( materialValues.diffuseFactor );
+			materialParams.opacity = materialValues.diffuseFactor[ 3 ];
 
 		}
 
@@ -1781,17 +1812,17 @@ THREE.GLTF2Loader = ( function () {
 				// For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.
 				var elementBytes = TypedArray.BYTES_PER_ELEMENT;
 				var itemBytes = elementBytes * itemSize;
-
+				var byteStride = json.bufferViews[accessor.bufferView].byteStride;	
 				var array;
 
 				// The buffer is not interleaved if the stride is the item size in bytes.
-				if ( accessor.byteStride && accessor.byteStride !== itemBytes ) {
+				if ( byteStride && byteStride !== itemBytes ) {
 
 					// Use the full buffer if it's interleaved.
 					array = new TypedArray( arraybuffer );
 
 					// Integer parameters to IB/IBA are in array elements, not bytes.
-					var ib = new THREE.InterleavedBuffer( array, accessor.byteStride / elementBytes );
+					var ib = new THREE.InterleavedBuffer( array, byteStride / elementBytes );
 
 					return new THREE.InterleavedBufferAttribute( ib, itemSize, accessor.byteOffset / elementBytes );
 
@@ -1957,14 +1988,6 @@ THREE.GLTF2Loader = ( function () {
 
 						materialParams.map = dependencies.textures[ metallicRoughness.baseColorTexture.index ];
 
-						var alphaMode = metallicRoughness.baseColorTexture.alphaMode || ALPHA_MODES.OPAQUE;
-
-						if ( alphaMode !== ALPHA_MODES.OPAQUE ) {
-
-							materialParams.transparent = true;
-
-						}
-
 					}
 
 					materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0;
@@ -1990,7 +2013,9 @@ THREE.GLTF2Loader = ( function () {
 
 				}
 
-				if ( materialParams.opacity !== undefined && materialParams.opacity < 1.0 ) {
+				var alphaMode = material.alphaMode || ALPHA_MODES.OPAQUE;
+
+				if ( alphaMode !== ALPHA_MODES.OPAQUE ) {
 
 					materialParams.transparent = true;
 
@@ -2531,28 +2556,30 @@ THREE.GLTF2Loader = ( function () {
 		var extensions = this.extensions;
 		var scope = this;
 
-		return _each( json.nodes, function ( node ) {
+		var nodes = json.nodes || [];
+		var skins = json.skins || [];
 
-			var matrix = new THREE.Matrix4();
+		// Nothing in the node definition indicates whether it is a Bone or an
+		// Object3D. Use the skins' joint references to mark bones.
+		skins.forEach( function ( skin ) {
 
-			var _node;
+			skin.joints.forEach( function ( id ) {
 
-			if ( node.jointName ) {
+				nodes[ id ].isBone = true;
 
-				_node = new THREE.Bone();
-				_node.name = node.name !== undefined ? node.name : node.jointName;
-				_node.jointName = node.jointName;
+			} );
 
-			} else {
+		} );
 
-				_node = new THREE.Object3D();
-				if ( node.name !== undefined ) _node.name = node.name;
+		return _each( json.nodes, function ( node ) {
 
-			}
+			var matrix = new THREE.Matrix4();
+
+			var _node = node.isBone === true ? new THREE.Bone() : new THREE.Object3D();
 
-			if ( _node.name !== undefined ) {
+			if ( node.name !== undefined ) {
 
-				_node.name = THREE.PropertyBinding.sanitizeNodeName( _node.name );
+				_node.name = THREE.PropertyBinding.sanitizeNodeName( node.name );
 
 			}
 
@@ -2765,13 +2792,11 @@ THREE.GLTF2Loader = ( function () {
 					}
 
 					if ( node.extensions
-							 && node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ]
-							 && node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].light ) {
+							 && node.extensions[ EXTENSIONS.KHR_LIGHTS ]
+							 && node.extensions[ EXTENSIONS.KHR_LIGHTS ].light !== undefined ) {
 
-						var extensionLights = extensions[ EXTENSIONS.KHR_LIGHTS ].lights;
-						var light = extensionLights[ node.extensions[ EXTENSIONS.KHR_LIGHTS ].light ];
-
-						_node.add( light );
+						var lights = extensions[ EXTENSIONS.KHR_LIGHTS ].lights;
+						_node.add( lights[ node.extensions[ EXTENSIONS.KHR_LIGHTS ].light ] );
 
 					}
 
@@ -2857,6 +2882,16 @@ THREE.GLTF2Loader = ( function () {
 
 				} );
 
+				// Ambient lighting, if present, is always attached to the scene root.
+				if ( scene.extensions
+							 && scene.extensions[ EXTENSIONS.KHR_LIGHTS ]
+							 && scene.extensions[ EXTENSIONS.KHR_LIGHTS ].light !== undefined ) {
+
+					var lights = extensions[ EXTENSIONS.KHR_LIGHTS ].lights;
+					_scene.add( lights[ scene.extensions[ EXTENSIONS.KHR_LIGHTS ].light ] );
+
+				}
+
 				return _scene;
 
 			} );

+ 1 - 1
examples/js/loaders/GLTFLoader.js

@@ -666,7 +666,7 @@ THREE.GLTFLoader = ( function () {
 
 		if ( window.TextDecoder !== undefined ) {
 
-			//return new TextDecoder().decode( array );
+			return new TextDecoder().decode( array );
 
 		}
 

+ 293 - 0
examples/js/loaders/PRWMLoader.js

@@ -0,0 +1,293 @@
+/**
+ * @author Kevin Chapelier / https://github.com/kchapelier
+ * See https://github.com/kchapelier/PRWM for more informations about this file format
+ */
+
+( function ( THREE ) {
+
+	"use strict";
+
+	var bigEndianPlatform = null;
+
+	/**
+	 * Check if the endianness of the platform is big-endian (most significant bit first)
+	 * @returns {boolean} True if big-endian, false if little-endian
+	 */
+	function isBigEndianPlatform() {
+
+		if ( bigEndianPlatform === null ) {
+
+			var buffer = new ArrayBuffer( 2 ),
+				uint8Array = new Uint8Array( buffer ),
+				uint16Array = new Uint16Array( buffer );
+
+			uint8Array[ 0 ] = 0xAA; // set first byte
+			uint8Array[ 1 ] = 0xBB; // set second byte
+			bigEndianPlatform = ( uint16Array[ 0 ] === 0xAABB );
+
+		}
+
+		return bigEndianPlatform;
+
+	}
+
+	// match the values defined in the spec to the TypedArray types
+	var InvertedEncodingTypes = [
+		null,
+		Float32Array,
+		null,
+		Int8Array,
+		Int16Array,
+		null,
+		Int32Array,
+		Uint8Array,
+		Uint16Array,
+		null,
+		Uint32Array
+	];
+
+	// define the method to use on a DataView, corresponding the TypedArray type
+	var getMethods = {
+		Uint16Array: 'getUint16',
+		Uint32Array: 'getUint32',
+		Int16Array: 'getInt16',
+		Int32Array: 'getInt32',
+		Float32Array: 'getFloat32',
+		Float64Array: 'getFloat64'
+	};
+
+
+	function copyFromBuffer( sourceArrayBuffer, viewType, position, length, fromBigEndian ) {
+
+		var bytesPerElement = viewType.BYTES_PER_ELEMENT,
+			result;
+
+		if ( fromBigEndian === isBigEndianPlatform() || bytesPerElement === 1 ) {
+
+			result = new viewType( sourceArrayBuffer, position, length );
+
+		} else {
+
+			var readView = new DataView( sourceArrayBuffer, position, length * bytesPerElement ),
+				getMethod = getMethods[ viewType.name ],
+				littleEndian = ! fromBigEndian,
+				i = 0;
+
+			result = new viewType( length );
+
+			for ( ; i < length; i ++ ) {
+
+				result[ i ] = readView[ getMethod ]( i * bytesPerElement, littleEndian );
+
+			}
+
+		}
+
+		return result;
+
+	}
+
+
+	function decodePrwm( buffer ) {
+
+		var array = new Uint8Array( buffer ),
+			version = array[ 0 ],
+			flags = array[ 1 ],
+			indexedGeometry = !! ( flags >> 7 & 0x01 ),
+			indicesType = flags >> 6 & 0x01,
+			bigEndian = ( flags >> 5 & 0x01 ) === 1,
+			attributesNumber = flags & 0x1F,
+			valuesNumber = 0,
+			indicesNumber = 0;
+
+		if ( bigEndian ) {
+
+			valuesNumber = ( array[ 2 ] << 16 ) + ( array[ 3 ] << 8 ) + array[ 4 ];
+			indicesNumber = ( array[ 5 ] << 16 ) + ( array[ 6 ] << 8 ) + array[ 7 ];
+
+		} else {
+
+			valuesNumber = array[ 2 ] + ( array[ 3 ] << 8 ) + ( array[ 4 ] << 16 );
+			indicesNumber = array[ 5 ] + ( array[ 6 ] << 8 ) + ( array[ 7 ] << 16 );
+
+		}
+
+		/** PRELIMINARY CHECKS **/
+
+		if ( version === 0 ) {
+
+			throw new Error( 'PRWM decoder: Invalid format version: 0' );
+
+		} else if ( version !== 1 ) {
+
+			throw new Error( 'PRWM decoder: Unsupported format version: ' + version );
+
+		}
+
+		if ( ! indexedGeometry ) {
+
+			if ( indicesType !== 0 ) {
+
+				throw new Error( 'PRWM decoder: Indices type must be set to 0 for non-indexed geometries' );
+
+			} else if ( indicesNumber !== 0 ) {
+
+				throw new Error( 'PRWM decoder: Number of indices must be set to 0 for non-indexed geometries' );
+
+			}
+
+		}
+
+		/** PARSING **/
+
+		var pos = 8;
+
+		var attributes = {},
+			attributeName,
+			char,
+			attributeType,
+			attributeNormalized,
+			cardinality,
+			encodingType,
+			arrayType,
+			values,
+			indices,
+			i;
+
+		for ( i = 0; i < attributesNumber; i ++ ) {
+
+			attributeName = '';
+
+			while ( pos < array.length ) {
+
+				char = array[ pos ];
+				pos ++;
+
+				if ( char === 0 ) {
+
+					break;
+
+				} else {
+
+					attributeName += String.fromCharCode( char );
+
+				}
+
+			}
+
+			flags = array[ pos ];
+
+			attributeType = flags >> 7 & 0x01;
+			attributeNormalized = !! ( flags >> 6 & 0x01 );
+			cardinality = ( flags >> 4 & 0x03 ) + 1;
+			encodingType = flags & 0x0F;
+			arrayType = InvertedEncodingTypes[ encodingType ];
+
+			pos ++;
+
+			// padding to next multiple of 4
+			pos = Math.ceil( pos / 4 ) * 4;
+
+			values = copyFromBuffer( buffer, arrayType, pos, cardinality * valuesNumber, bigEndian );
+
+			pos += arrayType.BYTES_PER_ELEMENT * cardinality * valuesNumber;
+
+			attributes[ attributeName ] = {
+				type: attributeType,
+				cardinality: cardinality,
+				values: values
+			};
+
+		}
+
+		pos = Math.ceil( pos / 4 ) * 4;
+
+		indices = null;
+
+		if ( indexedGeometry ) {
+
+			indices = copyFromBuffer(
+				buffer,
+				indicesType === 1 ? Uint32Array : Uint16Array,
+				pos,
+				indicesNumber,
+				bigEndian
+			);
+
+		}
+
+		return {
+			version: version,
+			attributes: attributes,
+			indices: indices
+		};
+
+	}
+
+	// Define the public interface
+
+	THREE.PRWMLoader = function PRWMLoader( manager ) {
+
+		this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+
+	};
+
+	THREE.PRWMLoader.prototype = {
+
+		constructor: THREE.PRWMLoader,
+
+		load: function ( url, onLoad, onProgress, onError ) {
+
+			var scope = this;
+
+			var loader = new THREE.FileLoader( scope.manager );
+			loader.setResponseType( 'arraybuffer' );
+
+			url = url.replace( /\*/g, isBigEndianPlatform() ? 'be' : 'le' );
+
+			loader.load( url, function ( arrayBuffer ) {
+
+				onLoad( scope.parse( arrayBuffer ) );
+
+			}, onProgress, onError );
+
+		},
+
+		parse: function ( arrayBuffer ) {
+
+			console.time( 'PRWMLoader' );
+
+			var data = decodePrwm( arrayBuffer ),
+				attributesKey = Object.keys( data.attributes ),
+				bufferGeometry = new THREE.BufferGeometry(),
+				attribute,
+				i;
+
+			for ( i = 0; i < attributesKey.length; i ++ ) {
+
+				attribute = data.attributes[ attributesKey[ i ] ];
+				bufferGeometry.addAttribute( attributesKey[ i ], new THREE.BufferAttribute( attribute.values, attribute.cardinality, attribute.normalized ) );
+
+			}
+
+			if ( data.indices !== null ) {
+
+				bufferGeometry.setIndex( new THREE.BufferAttribute( data.indices, 1 ) );
+
+			}
+
+			console.timeEnd( 'PRWMLoader' );
+
+			return bufferGeometry;
+
+		}
+
+	};
+
+	THREE.PRWMLoader.isBigEndianPlatform = function () {
+
+		return isBigEndianPlatform();
+
+	};
+
+} )( THREE );

+ 52 - 53
examples/js/nodes/materials/PhongNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.PhongNode = function() {
+THREE.PhongNode = function () {
 
 	THREE.GLNode.call( this );
 
@@ -15,7 +15,7 @@ THREE.PhongNode = function() {
 THREE.PhongNode.prototype = Object.create( THREE.GLNode.prototype );
 THREE.PhongNode.prototype.constructor = THREE.PhongNode;
 
-THREE.PhongNode.prototype.build = function( builder ) {
+THREE.PhongNode.prototype.build = function ( builder ) {
 
 	var material = builder.material;
 	var code;
@@ -27,7 +27,7 @@ THREE.PhongNode.prototype.build = function( builder ) {
 
 	if ( builder.isShader( 'vertex' ) ) {
 
-		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache : 'transform' } ) : undefined;
+		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache: 'transform' } ) : undefined;
 
 		material.mergeUniform( THREE.UniformsUtils.merge( [
 
@@ -45,21 +45,20 @@ THREE.PhongNode.prototype.build = function( builder ) {
 
 			"#endif",
 
-			THREE.ShaderChunk[ "common" ],
-			THREE.ShaderChunk[ "fog_parse_vertex" ],
-			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
-			THREE.ShaderChunk[ "skinning_pars_vertex" ],
-			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
-			THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ]
-
+			"#include <common>",
+			"#include <fog_pars_vertex>",
+			"#include <morphtarget_pars_vertex>",
+			"#include <skinning_pars_vertex>",
+			"#include <shadowmap_pars_vertex>",
+			"#include <logdepthbuf_pars_vertex>"
 		].join( "\n" ) );
 
 		var output = [
-				THREE.ShaderChunk[ "beginnormal_vertex" ],
-				THREE.ShaderChunk[ "morphnormal_vertex" ],
-				THREE.ShaderChunk[ "skinbase_vertex" ],
-				THREE.ShaderChunk[ "skinnormal_vertex" ],
-				THREE.ShaderChunk[ "defaultnormal_vertex" ],
+			"#include <beginnormal_vertex>",
+			"#include <morphnormal_vertex>",
+			"#include <skinbase_vertex>",
+			"#include <skinnormal_vertex>",
+			"#include <defaultnormal_vertex>",
 
 			"#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED
 
@@ -67,8 +66,7 @@ THREE.PhongNode.prototype.build = function( builder ) {
 
 			"#endif",
 
-				THREE.ShaderChunk[ "begin_vertex" ],
-				THREE.ShaderChunk[ "fog_vertex" ]
+			"#include <begin_vertex>"
 		];
 
 		if ( transform ) {
@@ -81,15 +79,16 @@ THREE.PhongNode.prototype.build = function( builder ) {
 		}
 
 		output.push(
-				THREE.ShaderChunk[ "morphtarget_vertex" ],
-				THREE.ShaderChunk[ "skinning_vertex" ],
-				THREE.ShaderChunk[ "project_vertex" ],
-				THREE.ShaderChunk[ "logdepthbuf_vertex" ],
+			"	#include <morphtarget_vertex>",
+			"	#include <skinning_vertex>",
+			"	#include <project_vertex>",
+			"	#include <fog_vertex>",
+			"	#include <logdepthbuf_vertex>",
 
 			"	vViewPosition = - mvPosition.xyz;",
 
-				THREE.ShaderChunk[ "worldpos_vertex" ],
-				THREE.ShaderChunk[ "shadowmap_vertex" ]
+			"	#include <worldpos_vertex>",
+			"	#include <shadowmap_vertex>"
 		);
 
 		code = output.join( "\n" );
@@ -98,71 +97,71 @@ THREE.PhongNode.prototype.build = function( builder ) {
 
 		// parse all nodes to reuse generate codes
 
-		this.color.parse( builder, { slot : 'color' } );
+		this.color.parse( builder, { slot: 'color' } );
 		this.specular.parse( builder );
 		this.shininess.parse( builder );
 
 		if ( this.alpha ) this.alpha.parse( builder );
-		
+
 		if ( this.normal ) this.normal.parse( builder );
 		if ( this.normalScale && this.normal ) this.normalScale.parse( builder );
-		
-		if ( this.light ) this.light.parse( builder, { cache : 'light' } );
+
+		if ( this.light ) this.light.parse( builder, { cache: 'light' } );
 
 		if ( this.ao ) this.ao.parse( builder );
 		if ( this.ambient ) this.ambient.parse( builder );
 		if ( this.shadow ) this.shadow.parse( builder );
-		if ( this.emissive ) this.emissive.parse( builder, { slot : 'emissive' } );
+		if ( this.emissive ) this.emissive.parse( builder, { slot: 'emissive' } );
 
-		if ( this.environment ) this.environment.parse( builder, { slot : 'environment' } );
+		if ( this.environment ) this.environment.parse( builder, { slot: 'environment' } );
 		if ( this.environmentAlpha && this.environment ) this.environmentAlpha.parse( builder );
 
 		// build code
 
-		var color = this.color.buildCode( builder, 'c', { slot : 'color' } );
+		var color = this.color.buildCode( builder, 'c', { slot: 'color' } );
 		var specular = this.specular.buildCode( builder, 'c' );
 		var shininess = this.shininess.buildCode( builder, 'fv1' );
 
 		var alpha = this.alpha ? this.alpha.buildCode( builder, 'fv1' ) : undefined;
-		
+
 		var normal = this.normal ? this.normal.buildCode( builder, 'v3' ) : undefined;
 		var normalScale = this.normalScale && this.normal ? this.normalScale.buildCode( builder, 'v2' ) : undefined;
-		
-		var light = this.light ? this.light.buildCode( builder, 'v3', { cache : 'light' } ) : undefined;
+
+		var light = this.light ? this.light.buildCode( builder, 'v3', { cache: 'light' } ) : undefined;
 
 		var ao = this.ao ? this.ao.buildCode( builder, 'fv1' ) : undefined;
 		var ambient = this.ambient ? this.ambient.buildCode( builder, 'c' ) : undefined;
 		var shadow = this.shadow ? this.shadow.buildCode( builder, 'c' ) : undefined;
-		var emissive = this.emissive ? this.emissive.buildCode( builder, 'c', { slot : 'emissive' } ) : undefined;
+		var emissive = this.emissive ? this.emissive.buildCode( builder, 'c', { slot: 'emissive' } ) : undefined;
 
-		var environment = this.environment ? this.environment.buildCode( builder, 'c', { slot : 'environment' } ) : undefined;
+		var environment = this.environment ? this.environment.buildCode( builder, 'c', { slot: 'environment' } ) : undefined;
 		var environmentAlpha = this.environmentAlpha && this.environment ? this.environmentAlpha.buildCode( builder, 'fv1' ) : undefined;
 
 		material.requestAttribs.transparent = alpha != undefined;
 
 		material.addFragmentPars( [
-			THREE.ShaderChunk[ "common" ],
-			THREE.ShaderChunk[ "fog_pars_fragment" ],
-			THREE.ShaderChunk[ "bsdfs" ],
-			THREE.ShaderChunk[ "lights_pars" ],
-			THREE.ShaderChunk[ "lights_phong_pars_fragment" ],
-			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
-			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ]
+			"#include <common>",
+			"#include <fog_pars_fragment>",
+			"#include <bsdfs>",
+			"#include <lights_pars>",
+			"#include <lights_phong_pars_fragment>",
+			"#include <shadowmap_pars_fragment>",
+			"#include <logdepthbuf_pars_fragment>"
 		].join( "\n" ) );
 
 		var output = [
-				// prevent undeclared normal
-				THREE.ShaderChunk[ "normal_flip" ],
-				THREE.ShaderChunk[ "normal_fragment" ],
+			// prevent undeclared normal
+			"#include <normal_flip>",
+			"#include <normal_fragment>",
 
-				// prevent undeclared material
+			// prevent undeclared material
 			"	BlinnPhongMaterial material;",
 
-				color.code,
+			color.code,
 			"	vec3 diffuseColor = " + color.result + ";",
 			"	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
 
-				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
+			"#include <logdepthbuf_fragment>",
 
 			specular.code,
 			"	vec3 specular = " + specular.result + ";",
@@ -209,7 +208,7 @@ THREE.PhongNode.prototype.build = function( builder ) {
 			'material.specularShininess = shininess;',
 			'material.specularStrength = specularStrength;',
 
-			THREE.ShaderChunk[ "lights_template" ]
+			"#include <lights_template>"
 		);
 
 		if ( light ) {
@@ -297,10 +296,10 @@ THREE.PhongNode.prototype.build = function( builder ) {
 		}
 
 		output.push(
-			THREE.ShaderChunk[ "premultiplied_alpha_fragment" ],
-			THREE.ShaderChunk[ "tonemapping_fragment" ],
-			THREE.ShaderChunk[ "encodings_fragment" ],
-			THREE.ShaderChunk[ "fog_fragment" ]
+			"#include <premultiplied_alpha_fragment>",
+			"#include <tonemapping_fragment>",
+			"#include <encodings_fragment>",
+			"#include <fog_fragment>"
 		);
 
 		code = output.join( "\n" );

+ 139 - 0
examples/js/nodes/materials/SpriteNode.js

@@ -0,0 +1,139 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+THREE.SpriteNode = function () {
+
+	THREE.GLNode.call( this );
+
+	this.color = new THREE.ColorNode( 0xEEEEEE );
+	this.spherical = true;
+
+};
+
+THREE.SpriteNode.prototype = Object.create( THREE.GLNode.prototype );
+THREE.SpriteNode.prototype.constructor = THREE.SpriteNode;
+
+THREE.SpriteNode.prototype.build = function ( builder ) {
+
+	var material = builder.material;
+	var output, code;
+
+	material.define( 'SPRITE' );
+
+	material.requestAttribs.light = false;
+	material.requestAttribs.transparent = this.alpha != undefined;
+
+	if ( builder.isShader( 'vertex' ) ) {
+
+		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache: 'transform' } ) : undefined;
+
+		material.mergeUniform( THREE.UniformsUtils.merge( [
+			THREE.UniformsLib[ "fog" ]
+		] ) );
+
+		material.addVertexPars( [
+			"#include <fog_pars_vertex>"
+		].join( "\n" ) );
+
+		output = [
+			"#include <begin_vertex>"
+		];
+
+		if ( transform ) {
+
+			output.push(
+				transform.code,
+				"transformed = " + transform.result + ";"
+			);
+
+		}
+
+		output.push(
+			"#include <project_vertex>",
+			"#include <fog_vertex>",
+
+			'mat4 modelViewMtx = modelViewMatrix;',
+			'mat4 modelMtx = modelMatrix;',
+
+			// ignore position from modelMatrix (use vary position)
+			'modelMtx[3][0] = 0.0;',
+			'modelMtx[3][1] = 0.0;',
+			'modelMtx[3][2] = 0.0;'
+		);
+
+		if ( ! this.spherical ) {
+
+			output.push(
+				'modelMtx[1][1] = 1.0;'
+			);
+
+		}
+
+		output.push(
+			// http://www.geeks3d.com/20140807/billboarding-vertex-shader-glsl/
+			// First colunm.
+			'modelViewMtx[0][0] = 1.0;',
+			'modelViewMtx[0][1] = 0.0;',
+			'modelViewMtx[0][2] = 0.0;'
+		);
+
+		if ( this.spherical ) {
+
+			output.push(
+				// Second colunm.
+				'modelViewMtx[1][0] = 0.0;',
+				'modelViewMtx[1][1] = 1.0;',
+				'modelViewMtx[1][2] = 0.0;'
+			);
+
+		}
+
+		output.push(
+			// Thrid colunm.
+			'modelViewMtx[2][0] = 0.0;',
+			'modelViewMtx[2][1] = 0.0;',
+			'modelViewMtx[2][2] = 1.0;',
+
+			// apply
+			'gl_Position = projectionMatrix * modelViewMtx * modelMtx * vec4( transformed, 1.0 );'
+		);
+
+	} else {
+
+		material.addFragmentPars( [
+			"#include <fog_pars_fragment>",
+		].join( "\n" ) );
+
+		// parse all nodes to reuse generate codes
+
+		this.color.parse( builder, { slot: 'color' } );
+		if ( this.alpha ) this.alpha.parse( builder );
+
+		// build code
+
+		var color = this.color.buildCode( builder, 'c', { slot: 'color' } );
+		var alpha = this.alpha ? this.alpha.buildCode( builder, 'fv1' ) : undefined;
+
+		output = [ color.code ];
+
+		if ( alpha ) {
+
+			output.push(
+				alpha.code,
+				"gl_FragColor = vec4( " + color.result + ", " + alpha.result + " );"
+			);
+
+		} else {
+
+			output.push( "gl_FragColor = vec4( " + color.result + ", 1.0 );" );
+
+		}
+
+		output.push( "#include <fog_fragment>" );
+
+	}
+
+	return output.join( "\n" );
+
+};

+ 17 - 0
examples/js/nodes/materials/SpriteNodeMaterial.js

@@ -0,0 +1,17 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+THREE.SpriteNodeMaterial = function () {
+
+	this.node = new THREE.SpriteNode();
+
+	THREE.NodeMaterial.call( this, this.node, this.node );
+
+};
+
+THREE.SpriteNodeMaterial.prototype = Object.create( THREE.NodeMaterial.prototype );
+THREE.SpriteNodeMaterial.prototype.constructor = THREE.SpriteNodeMaterial;
+
+THREE.NodeMaterial.addShortcuts( THREE.SpriteNodeMaterial.prototype, 'node',
+[ 'color', 'alpha', 'transform', 'spherical' ] );

+ 82 - 78
examples/js/nodes/materials/StandardNode.js

@@ -2,7 +2,7 @@
  * @author sunag / http://www.sunag.com.br/
  */
 
-THREE.StandardNode = function() {
+THREE.StandardNode = function () {
 
 	THREE.GLNode.call( this );
 
@@ -15,14 +15,14 @@ THREE.StandardNode = function() {
 THREE.StandardNode.prototype = Object.create( THREE.GLNode.prototype );
 THREE.StandardNode.prototype.constructor = THREE.StandardNode;
 
-THREE.StandardNode.prototype.build = function( builder ) {
+THREE.StandardNode.prototype.build = function ( builder ) {
 
 	var material = builder.material;
 	var code;
 
 	material.define( 'PHYSICAL' );
 
-	if ( !this.clearCoat && !this.clearCoatRoughness ) material.define( 'STANDARD' );
+	if ( ! this.clearCoat && ! this.clearCoatRoughness ) material.define( 'STANDARD' );
 
 	material.define( 'ALPHATEST', '0.0' );
 
@@ -32,7 +32,7 @@ THREE.StandardNode.prototype.build = function( builder ) {
 
 	if ( builder.isShader( 'vertex' ) ) {
 
-		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache : 'transform' } ) : undefined;
+		var transform = this.transform ? this.transform.parseAndBuildCode( builder, 'v3', { cache: 'transform' } ) : undefined;
 
 		material.mergeUniform( THREE.UniformsUtils.merge( [
 
@@ -50,21 +50,24 @@ THREE.StandardNode.prototype.build = function( builder ) {
 
 			"#endif",
 
-			THREE.ShaderChunk[ "common" ],
-			THREE.ShaderChunk[ "fog_pars_vertex" ],
-			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
-			THREE.ShaderChunk[ "skinning_pars_vertex" ],
-			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
-			THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ]
+			"#include <common>",
+			"#include <fog_pars_vertex>",
+			"#include <morphtarget_pars_vertex>",
+			"#include <skinning_pars_vertex>",
+			"#include <shadowmap_pars_vertex>",
+			"#include <logdepthbuf_pars_vertex>"
 
 		].join( "\n" ) );
 
 		var output = [
-			THREE.ShaderChunk[ "beginnormal_vertex" ],
-			THREE.ShaderChunk[ "morphnormal_vertex" ],
-			THREE.ShaderChunk[ "skinbase_vertex" ],
-			THREE.ShaderChunk[ "skinnormal_vertex" ],
-			THREE.ShaderChunk[ "defaultnormal_vertex" ],
+			"#include <beginnormal_vertex>",
+			"#include <morphnormal_vertex>",
+			"#include <skinbase_vertex>",
+			"#include <skinnormal_vertex>",
+			"#include <defaultnormal_vertex>",
+			"#include <logdepthbuf_pars_vertex>",
+			"#include <logdepthbuf_pars_vertex>",
+			"#include <logdepthbuf_pars_vertex>",
 
 			"#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED
 
@@ -72,8 +75,7 @@ THREE.StandardNode.prototype.build = function( builder ) {
 
 			"#endif",
 
-			THREE.ShaderChunk[ "begin_vertex" ],
-			THREE.ShaderChunk[ "fog_vertex" ]        
+			"#include <begin_vertex>"
 		];
 
 		if ( transform ) {
@@ -86,15 +88,16 @@ THREE.StandardNode.prototype.build = function( builder ) {
 		}
 
 		output.push(
-			THREE.ShaderChunk[ "morphtarget_vertex" ],
-			THREE.ShaderChunk[ "skinning_vertex" ],
-			THREE.ShaderChunk[ "project_vertex" ],
-			THREE.ShaderChunk[ "logdepthbuf_vertex" ],
+			"#include <morphtarget_vertex>",
+			"#include <skinning_vertex>",
+			"#include <project_vertex>",
+			"#include <fog_vertex>",
+			"#include <logdepthbuf_vertex>",
 
 			"	vViewPosition = - mvPosition.xyz;",
 
-			THREE.ShaderChunk[ "worldpos_vertex" ],
-			THREE.ShaderChunk[ "shadowmap_vertex" ]
+			"#include <worldpos_vertex>",
+			"#include <shadowmap_vertex>"
 		);
 
 		code = output.join( "\n" );
@@ -104,64 +107,64 @@ THREE.StandardNode.prototype.build = function( builder ) {
 		// blur textures for PBR effect
 
 		var requires = {
-			bias : new THREE.RoughnessToBlinnExponentNode(),
-			offsetU : 0,
-			offsetV : 0
+			bias: new THREE.RoughnessToBlinnExponentNode(),
+			offsetU: 0,
+			offsetV: 0
 		};
 
-		var useClearCoat = !material.isDefined( 'STANDARD' );
-		
+		var useClearCoat = ! material.isDefined( 'STANDARD' );
+
 		// parse all nodes to reuse generate codes
 
-		this.color.parse( builder, { slot : 'color' } );
+		this.color.parse( builder, { slot: 'color' } );
 		this.roughness.parse( builder );
 		this.metalness.parse( builder );
 
 		if ( this.alpha ) this.alpha.parse( builder );
-		
+
 		if ( this.normal ) this.normal.parse( builder );
 		if ( this.normalScale && this.normal ) this.normalScale.parse( builder );
-		
-		if (this.clearCoat) this.clearCoat.parse( builder );
-		if (this.clearCoatRoughness) this.clearCoatRoughness.parse( builder );
-		
+
+		if ( this.clearCoat ) this.clearCoat.parse( builder );
+		if ( this.clearCoatRoughness ) this.clearCoatRoughness.parse( builder );
+
 		if ( this.reflectivity ) this.reflectivity.parse( builder );
 
-		if ( this.light ) this.light.parse( builder, { cache : 'light' } );
+		if ( this.light ) this.light.parse( builder, { cache: 'light' } );
 
 		if ( this.ao ) this.ao.parse( builder );
 		if ( this.ambient ) this.ambient.parse( builder );
 		if ( this.shadow ) this.shadow.parse( builder );
-		if ( this.emissive ) this.emissive.parse( builder, { slot : 'emissive' } );
+		if ( this.emissive ) this.emissive.parse( builder, { slot: 'emissive' } );
 
-		if ( this.environment ) this.environment.parse( builder, { cache : 'env', requires : requires, slot : 'environment' } ); // isolate environment from others inputs ( see TextureNode, CubeTextureNode )
+		if ( this.environment ) this.environment.parse( builder, { cache: 'env', requires: requires, slot: 'environment' } ); // isolate environment from others inputs ( see TextureNode, CubeTextureNode )
 
 		// build code
 
-		var color = this.color.buildCode( builder, 'c', { slot : 'color' } );
+		var color = this.color.buildCode( builder, 'c', { slot: 'color' } );
 		var roughness = this.roughness.buildCode( builder, 'fv1' );
 		var metalness = this.metalness.buildCode( builder, 'fv1' );
 
 		var alpha = this.alpha ? this.alpha.buildCode( builder, 'fv1' ) : undefined;
-		
+
 		var normal = this.normal ? this.normal.buildCode( builder, 'v3' ) : undefined;
 		var normalScale = this.normalScale && this.normal ? this.normalScale.buildCode( builder, 'v2' ) : undefined;
-		
+
 		var clearCoat = this.clearCoat ? this.clearCoat.buildCode( builder, 'fv1' ) : undefined;
 		var clearCoatRoughness = this.clearCoatRoughness ? this.clearCoatRoughness.buildCode( builder, 'fv1' ) : undefined;
-		
+
 		var reflectivity = this.reflectivity ? this.reflectivity.buildCode( builder, 'fv1' ) : undefined;
 
-		var light = this.light ? this.light.buildCode( builder, 'v3', { cache : 'light' } ) : undefined;
+		var light = this.light ? this.light.buildCode( builder, 'v3', { cache: 'light' } ) : undefined;
 
 		var ao = this.ao ? this.ao.buildCode( builder, 'fv1' ) : undefined;
 		var ambient = this.ambient ? this.ambient.buildCode( builder, 'c' ) : undefined;
 		var shadow = this.shadow ? this.shadow.buildCode( builder, 'c' ) : undefined;
-		var emissive = this.emissive ? this.emissive.buildCode( builder, 'c', { slot : 'emissive' } ) : undefined;
+		var emissive = this.emissive ? this.emissive.buildCode( builder, 'c', { slot: 'emissive' } ) : undefined;
 
-		var environment = this.environment ? this.environment.buildCode( builder, 'c', { cache : 'env', requires : requires, slot : 'environment' } ) : undefined;
+		var environment = this.environment ? this.environment.buildCode( builder, 'c', { cache: 'env', requires: requires, slot: 'environment' } ) : undefined;
 
-		var clearCoatEnv = useClearCoat && environment ? this.environment.buildCode( builder, 'c', { cache : 'clearCoat', requires : requires, slot : 'environment' } ) : undefined;
+		var clearCoatEnv = useClearCoat && environment ? this.environment.buildCode( builder, 'c', { cache: 'clearCoat', requires: requires, slot: 'environment' } ) : undefined;
 
 		material.requestAttribs.transparent = alpha != undefined;
 
@@ -175,29 +178,30 @@ THREE.StandardNode.prototype.build = function( builder ) {
 
 			"#endif",
 
-			THREE.ShaderChunk[ "common" ],
-			THREE.ShaderChunk[ "fog_pars_fragment" ],
-			THREE.ShaderChunk[ "bsdfs" ],
-			THREE.ShaderChunk[ "lights_pars" ],
-			THREE.ShaderChunk[ "lights_physical_pars_fragment" ],
-			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
-			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ]
+			"#include <common>",
+			"#include <fog_pars_fragment>",
+			"#include <bsdfs>",
+			"#include <lights_pars>",
+			"#include <lights_physical_pars_fragment>",
+			"#include <shadowmap_pars_fragment>",
+			"#include <logdepthbuf_pars_fragment>",
+			"#include <logdepthbuf_vertex>"
 		].join( "\n" ) );
 
 		var output = [
 				// prevent undeclared normal
-				THREE.ShaderChunk[ "normal_flip" ],
-				THREE.ShaderChunk[ "normal_fragment" ],
+			"	#include <normal_flip>",
+			"	#include <normal_fragment>",
 
 				// prevent undeclared material
 			"	PhysicalMaterial material;",
 			"	material.diffuseColor = vec3( 1.0 );",
 
-				color.code,
+			color.code,
 			"	vec3 diffuseColor = " + color.result + ";",
 			"	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
 
-				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
+			"#include <logdepthbuf_fragment>",
 
 			roughness.code,
 			"	float roughnessFactor = " + roughness.result + ";",
@@ -240,33 +244,33 @@ THREE.StandardNode.prototype.build = function( builder ) {
 			// accumulation
 			'material.specularRoughness = clamp( roughnessFactor, DEFAULT_SPECULAR_COEFFICIENT, 1.0 );' // disney's remapping of [ 0, 1 ] roughness to [ 0.001, 1 ]
 		);
-		
-		if (clearCoat) {
-			
+
+		if ( clearCoat ) {
+
 			output.push(
 				clearCoat.code,
 				'material.clearCoat = saturate( ' + clearCoat.result + ' );'
 			);
-			
-		} else if (useClearCoat) {
-			
+
+		} else if ( useClearCoat ) {
+
 			output.push( 'material.clearCoat = 0.0;' );
-			
+
 		}
-		
-		if (clearCoatRoughness) {
-			
+
+		if ( clearCoatRoughness ) {
+
 			output.push(
 				clearCoatRoughness.code,
 				'material.clearCoatRoughness = clamp( ' + clearCoatRoughness.result + ', DEFAULT_SPECULAR_COEFFICIENT, 1.0 );'
 			);
-			
-		} else if (useClearCoat) {
-			
+
+		} else if ( useClearCoat ) {
+
 			output.push( 'material.clearCoatRoughness = 0.0;' );
-			
+
 		}
-		
+
 		if ( reflectivity ) {
 
 			output.push(
@@ -283,7 +287,7 @@ THREE.StandardNode.prototype.build = function( builder ) {
 		}
 
 		output.push(
-			THREE.ShaderChunk[ "lights_template" ]
+			"#include <lights_template>"
 		);
 
 		if ( light ) {
@@ -347,7 +351,7 @@ THREE.StandardNode.prototype.build = function( builder ) {
 
 			output.push( environment.code );
 
-			if (clearCoatEnv) {
+			if ( clearCoatEnv ) {
 
 				output.push(
 					clearCoatEnv.code,
@@ -356,7 +360,7 @@ THREE.StandardNode.prototype.build = function( builder ) {
 
 			} else {
 
-				output.push("vec3 clearCoatRadiance = vec3( 0.0 );");
+				output.push( "vec3 clearCoatRadiance = vec3( 0.0 );" );
 
 			}
 
@@ -377,10 +381,10 @@ THREE.StandardNode.prototype.build = function( builder ) {
 		}
 
 		output.push(
-			THREE.ShaderChunk[ "premultiplied_alpha_fragment" ],
-			THREE.ShaderChunk[ "tonemapping_fragment" ],
-			THREE.ShaderChunk[ "encodings_fragment" ],
-			THREE.ShaderChunk[ "fog_fragment" ]
+			"#include <premultiplied_alpha_fragment>",
+			"#include <tonemapping_fragment>",
+			"#include <encodings_fragment>",
+			"#include <fog_fragment>"
 		);
 
 		code = output.join( "\n" );

+ 4 - 3
examples/js/nodes/utils/ResolutionNode.js

@@ -17,9 +17,10 @@ THREE.ResolutionNode.prototype.constructor = THREE.ResolutionNode;
 
 THREE.ResolutionNode.prototype.updateFrame = function( delta ) {
 
-	var size = this.renderer.getSize();
+	var size = this.renderer.getSize(),
+		pixelRatio = this.renderer.getPixelRatio();
 
-	this.x = size.width;
-	this.y = size.height;
+	this.x = size.width * pixelRatio;
+	this.y = size.height * pixelRatio;
 
 };

+ 48 - 0
examples/js/nodes/utils/UVTransformNode.js

@@ -0,0 +1,48 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+THREE.UVTransformNode = function () {
+
+	THREE.FunctionNode.call( this, "( uvTransform * vec4( uvNode, 0, 1 ) ).xy", "vec2" );
+
+	this.uv = new THREE.UVNode();
+	this.transform = new THREE.Matrix4Node();
+
+};
+
+THREE.UVTransformNode.prototype = Object.create( THREE.FunctionNode.prototype );
+THREE.UVTransformNode.prototype.constructor = THREE.UVTransformNode;
+
+THREE.UVTransformNode.prototype.generate = function ( builder, output ) {
+
+	this.keywords[ "uvNode" ] = this.uv;
+	this.keywords[ "uvTransform" ] = this.transform;
+
+	return THREE.FunctionNode.prototype.generate.call( this, builder, output );
+
+};
+
+THREE.UVTransformNode.prototype.compose = function () {
+
+	var defaultPivot = new THREE.Vector2( .5, .5 ),
+		tempVector = new THREE.Vector3(),
+		tempMatrix = new THREE.Matrix4();
+
+	return function compose( translate, rotate, scale, optionalCenter ) {
+
+		optionalCenter = optionalCenter !== undefined ? optionalCenter : defaultPivot;
+
+		var matrix = this.transform.value;
+
+		matrix.identity()
+			.setPosition( tempVector.set( - optionalCenter.x, - optionalCenter.y, 0 ) )
+			.premultiply( tempMatrix.makeRotationZ( rotate ) )
+			.multiply( tempMatrix.makeScale( scale.x, scale.y, 0 ) )
+			.multiply( tempMatrix.makeTranslation( translate.x, translate.y, 0 ) );
+
+		return this;
+
+	};
+
+}();

+ 52 - 52
examples/js/renderers/WebGLDeferredRenderer.js

@@ -1708,21 +1708,21 @@ THREE.ShaderDeferred = {
 			"varying vec3 vNormal;",
 			"varying vec4 vPosition;",
 
-			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
-			THREE.ShaderChunk[ "skinning_pars_vertex" ],
+			"#include <morphtarget_pars_vertex>",
+			"#include <skinning_pars_vertex>",
 
 			"void main() {",
 
-			THREE.ShaderChunk[ "begin_vertex" ],
-			THREE.ShaderChunk[ "beginnormal_vertex" ],
-			THREE.ShaderChunk[ "skinbase_vertex" ],
-			THREE.ShaderChunk[ "skinnormal_vertex" ],
-			THREE.ShaderChunk[ "defaultnormal_vertex" ],
-			THREE.ShaderChunk[ "morphtarget_vertex" ],
-			THREE.ShaderChunk[ "skinning_vertex" ],
-			THREE.ShaderChunk[ "project_vertex" ],
+			"#include <begin_vertex>",
+			"#include <beginnormal_vertex>",
+			"#include <skinbase_vertex>",
+			"#include <skinnormal_vertex>",
+			"#include <defaultnormal_vertex>",
+			"#include <morphtarget_vertex>",
+			"#include <skinning_vertex>",
+			"#include <project_vertex>",
 
-			"	vNormal = normalize( normalMatrix * objectNormal );",
+			"	vNormal = normalize( transformedNormal );",
 			"	vPosition = gl_Position;",
 
 			"}"
@@ -1765,21 +1765,21 @@ THREE.ShaderDeferred = {
 
 		vertexShader: [
 
-			THREE.ShaderChunk[ "uv_pars_vertex" ],
-			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
-			THREE.ShaderChunk[ "skinning_pars_vertex" ],
+			"#include <uv_pars_vertex>",
+			"#include <morphtarget_pars_vertex>",
+			"#include <skinning_pars_vertex>",
 
 			"void main() {",
 
-			THREE.ShaderChunk[ "uv_vertex" ],
-			THREE.ShaderChunk[ "begin_vertex" ],
-			THREE.ShaderChunk[ "beginnormal_vertex" ],
-			THREE.ShaderChunk[ "skinbase_vertex" ],
-			THREE.ShaderChunk[ "skinnormal_vertex" ],
-			THREE.ShaderChunk[ "defaultnormal_vertex" ],
-			THREE.ShaderChunk[ "morphtarget_vertex" ],
-			THREE.ShaderChunk[ "skinning_vertex" ],
-			THREE.ShaderChunk[ "project_vertex" ],
+			"#include <uv_vertex>",
+			"#include <begin_vertex>",
+			"#include <beginnormal_vertex>",
+			"#include <skinbase_vertex>",
+			"#include <skinnormal_vertex>",
+			"#include <defaultnormal_vertex>",
+			"#include <morphtarget_vertex>",
+			"#include <skinning_vertex>",
+			"#include <project_vertex>",
 
 			"}"
 
@@ -1792,8 +1792,8 @@ THREE.ShaderDeferred = {
 			"uniform vec3 specular;",
 			"uniform float shininess;",
 
-			THREE.ShaderChunk[ "uv_pars_fragment" ],
-			THREE.ShaderChunk[ "map_pars_fragment" ],
+			"#include <uv_pars_fragment>",
+			"#include <map_pars_fragment>",
 			THREE.DeferredShaderChunk[ "packVector3" ],
 
 			"void main() {",
@@ -1802,7 +1802,7 @@ THREE.ShaderDeferred = {
 			"	vec3 emissiveColor = emissive;",
 			"	vec3 specularColor = specular;",
 
-			THREE.ShaderChunk[ "map_fragment" ],
+			"#include <map_fragment>",
 			THREE.DeferredShaderChunk[ "packColor" ],
 
 			"	gl_FragColor = packedColor;",
@@ -2117,21 +2117,21 @@ THREE.ShaderDeferred = {
 			"varying vec3 vNormal;",
 			"varying vec4 vPosition;",
 
-			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
-			THREE.ShaderChunk[ "skinning_pars_vertex" ],
+			"#include <morphtarget_pars_vertex>",
+			"#include <skinning_pars_vertex>",
 
 			"void main() {",
 
-			THREE.ShaderChunk[ "begin_vertex" ],
-			THREE.ShaderChunk[ "beginnormal_vertex" ],
-			THREE.ShaderChunk[ "skinbase_vertex" ],
-			THREE.ShaderChunk[ "skinnormal_vertex" ],
-			THREE.ShaderChunk[ "defaultnormal_vertex" ],
-			THREE.ShaderChunk[ "morphtarget_vertex" ],
-			THREE.ShaderChunk[ "skinning_vertex" ],
-			THREE.ShaderChunk[ "project_vertex" ],
+			"#include <begin_vertex>",
+			"#include <beginnormal_vertex>",
+			"#include <skinbase_vertex>",
+			"#include <skinnormal_vertex>",
+			"#include <defaultnormal_vertex>",
+			"#include <morphtarget_vertex>",
+			"#include <skinning_vertex>",
+			"#include <project_vertex>",
 
-			"	vNormal = normalize( normalMatrix * objectNormal );",
+			"	vNormal = normalize( transformedNormal );",
 			"	vPosition = gl_Position;",
 
 			"}"
@@ -2420,21 +2420,21 @@ THREE.ShaderDeferred = {
 
 		vertexShader: [
 
-			THREE.ShaderChunk[ "uv_pars_vertex" ],
-			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
-			THREE.ShaderChunk[ "skinning_pars_vertex" ],
+			"#include <uv_pars_vertex>",
+			"#include <morphtarget_pars_vertex>",
+			"#include <skinning_pars_vertex>",
 
 			"void main() {",
 
-			THREE.ShaderChunk[ "uv_vertex" ],
-			THREE.ShaderChunk[ "begin_vertex" ],
-			THREE.ShaderChunk[ "beginnormal_vertex" ],
-			THREE.ShaderChunk[ "skinbase_vertex" ],
-			THREE.ShaderChunk[ "skinnormal_vertex" ],
-			THREE.ShaderChunk[ "defaultnormal_vertex" ],
-			THREE.ShaderChunk[ "morphtarget_vertex" ],
-			THREE.ShaderChunk[ "skinning_vertex" ],
-			THREE.ShaderChunk[ "project_vertex" ],
+			"#include <uv_vertex>",
+			"#include <begin_vertex>",
+			"#include <beginnormal_vertex>",
+			"#include <skinbase_vertex>",
+			"#include <skinnormal_vertex>",
+			"#include <defaultnormal_vertex>",
+			"#include <morphtarget_vertex>",
+			"#include <skinning_vertex>",
+			"#include <project_vertex>",
 
 			"}"
 
@@ -2452,8 +2452,8 @@ THREE.ShaderDeferred = {
 			"uniform float viewHeight;",
 			"uniform float viewWidth;",
 
-			THREE.ShaderChunk[ "uv_pars_fragment" ],
-			THREE.ShaderChunk[ "map_pars_fragment" ],
+			"#include <uv_pars_fragment>",
+			"#include <map_pars_fragment>",
 
 			THREE.DeferredShaderChunk[ "unpackFloat" ],
 
@@ -2467,7 +2467,7 @@ THREE.ShaderDeferred = {
 
 			"	vec4 light = texture2D( samplerLight, texCoord );",
 
-			THREE.ShaderChunk[ "map_fragment" ],
+			"#include <map_fragment>",
 
 			"	vec3 diffuseFinal = diffuseColor.rgb * light.rgb;",
 			"	vec3 emissiveFinal = emissiveColor;",

+ 0 - 153
examples/js/vr/WebVRCamera.js

@@ -1,153 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.WebVRCamera = function ( display, renderer ) {
-
-	var scope = this;
-
-	var frameData = null;
-
-	if ( 'VRFrameData' in window ) {
-
-		frameData = new window.VRFrameData();
-
-	}
-
-	var cameraL = new THREE.PerspectiveCamera();
-	cameraL.bounds = new THREE.Vector4( 0.0, 0.0, 0.5, 1.0 );
-	cameraL.layers.enable( 1 );
-
-	var cameraR = new THREE.PerspectiveCamera();
-	cameraR.bounds = new THREE.Vector4( 0.5, 0.0, 0.5, 1.0 );
-	cameraR.layers.enable( 2 );
-
-	var matrixWorldInverse = new THREE.Matrix4();
-
-	//
-
-	var currentSize, currentPixelRatio;
-
-	function onVRDisplayPresentChange() {
-
-		if ( display.isPresenting ) {
-
-			var eyeParameters = display.getEyeParameters( 'left' );
-			var renderWidth = eyeParameters.renderWidth;
-			var renderHeight = eyeParameters.renderHeight;
-
-			currentPixelRatio = renderer.getPixelRatio();
-			currentSize = renderer.getSize();
-
-			renderer.setPixelRatio( 1 );
-			renderer.setSize( renderWidth * 2, renderHeight, false );
-
-			scope.enabled = true;
-
-		} else if ( scope.enabled ) {
-
-			scope.enabled = false;
-
-			renderer.setPixelRatio( currentPixelRatio );
-			renderer.setSize( currentSize.width, currentSize.height, true );
-
-		}
-
-	}
-
-	window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );
-
-	//
-
-	THREE.ArrayCamera.call( this, [ cameraL, cameraR ] );
-
-	//
-
-	this.onBeforeRender = function () {
-
-		display.depthNear = scope.near;
-		display.depthFar = scope.far;
-
-		display.getFrameData( frameData );
-
-		//
-
-		var pose = frameData.pose;
-
-		if ( pose.orientation !== null ) {
-
-			scope.quaternion.fromArray( pose.orientation );
-
-		}
-
-		if ( pose.position !== null ) {
-
-			scope.position.fromArray( pose.position );
-
-		} else {
-
-			scope.position.set( 0, 0, 0 );
-
-		}
-
-		//
-
-		cameraL.matrixWorldInverse.fromArray( frameData.leftViewMatrix );
-		cameraR.matrixWorldInverse.fromArray( frameData.rightViewMatrix );
-
-		if ( scope.parent !== null ) {
-
-			matrixWorldInverse.getInverse( scope.parent.matrixWorld );
-
-			cameraL.matrixWorldInverse.multiply( matrixWorldInverse );
-			cameraR.matrixWorldInverse.multiply( matrixWorldInverse );
-
-		}
-
-		cameraL.projectionMatrix.fromArray( frameData.leftProjectionMatrix );
-		cameraR.projectionMatrix.fromArray( frameData.rightProjectionMatrix );
-
-		// HACK @mrdoob
-		// https://github.com/w3c/webvr/issues/203
-
-		scope.projectionMatrix.copy( cameraL.projectionMatrix );
-
-		//
-
-		var layers = display.getLayers();
-
-		if ( layers.length ) {
-
-			var layer = layers[ 0 ];
-
-			if ( layer.leftBounds !== null && layer.leftBounds.length === 4 ) {
-
-				cameraL.bounds.fromArray( layer.leftBounds );
-
-			}
-
-			if ( layer.rightBounds !== null && layer.rightBounds.length === 4 ) {
-
-				cameraR.bounds.fromArray( layer.rightBounds );
-
-			}
-
-		}
-
-	};
-
-	this.onAfterRender = function () {
-
-		if ( display.isPresenting ) display.submitFrame();
-
-	};
-
-};
-
-THREE.WebVRCamera.prototype = Object.assign( Object.create( THREE.ArrayCamera.prototype ), {
-
-	constructor: THREE.WebVRCamera,
-
-	isWebVRCamera: true
-
-} );

BIN
examples/models/prwm/faceted-nefertiti.be.prwm


BIN
examples/models/prwm/faceted-nefertiti.le.prwm


BIN
examples/models/prwm/smooth-suzanne.be.prwm


BIN
examples/models/prwm/smooth-suzanne.le.prwm


BIN
examples/models/prwm/vive-controller.be.prwm


BIN
examples/models/prwm/vive-controller.le.prwm


BIN
examples/textures/WalkingManSpriteSheet.png


+ 1 - 0
examples/webgl_clipping.html

@@ -106,6 +106,7 @@
 
 				renderer = new THREE.WebGLRenderer();
 				renderer.shadowMap.enabled = true;
+				renderer.shadowMap.renderSingleSided = false;
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				window.addEventListener( 'resize', onWindowResize, false );

+ 1 - 1
examples/webgl_gpgpu_water.html

@@ -182,9 +182,9 @@
 				vec3 transformed = vec3( position.x, position.y, heightValue );
 				//<begin_vertex>
 
-				#include <displacementmap_vertex>
 				#include <morphtarget_vertex>
 				#include <skinning_vertex>
+				#include <displacementmap_vertex>
 				#include <project_vertex>
 				#include <logdepthbuf_vertex>
 				#include <clipping_planes_vertex>

+ 7 - 2
examples/webgl_loader_imagebitmap.html

@@ -84,7 +84,7 @@
 
 				new THREE.ImageBitmapLoader()
 					.setOptions( { imageOrientation: 'none' } )
-					.load( 'textures/planets/earth_atmos_2048.jpg', function( imageBitmap ) {
+					.load( 'textures/planets/earth_atmos_2048.jpg?' + performance.now(), function( imageBitmap ) {
 
 						var tex = new THREE.CanvasTexture( imageBitmap );
 
@@ -106,6 +106,7 @@
 			function addImage () {
 
 				new THREE.ImageLoader()
+					.setCrossOrigin( '*' )
 					.load( 'textures/planets/earth_atmos_2048.jpg?' + performance.now(), function( image ) {
 							var tex = new THREE.CanvasTexture( image );
 							addCube( tex );
@@ -169,9 +170,13 @@
 				var clearBtn = document.getElementById( 'clear_btn' );
 				clearBtn.addEventListener( 'click', function( e ) {
 					while( cubes.children.length ) {
-						cubes.remove( cubes.children[ 0 ] );
+						var cube = cubes.children[ 0 ]
+						cubes.remove( cube );
+						cube.geometry.dispose();
+						cube.material.map.dispose();
 					}
 				})
+
 				// RENDERER
 
 				renderer = new THREE.WebGLRenderer( { antialias: true } );

+ 250 - 0
examples/webgl_loader_prwm.html

@@ -0,0 +1,250 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - loaders - PRWM loader</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			html, body {
+				padding:0;
+				margin:0;
+				background:#000000;
+			}
+
+			.models {
+				position:absolute;
+				top:10px;
+				left:12px;
+				z-index:2;
+				font-family: "Arial", "Helvetica Neue", "Helvetica", sans-serif;
+				font-size:13px;
+			}
+
+			.notes {
+				position:absolute;
+				left:12px;
+				bottom:10px;
+				z-index:2;
+				font-family: "Arial", "Helvetica Neue", "Helvetica", sans-serif;
+				font-size:13px;
+				text-align:left;
+				color:#FFFFFF;
+				max-width:300px;
+			}
+
+			.notes a, .notes a:visited {
+				color:#FFFFFF;
+			}
+
+			.models strong {
+				color:#FFFFFF;
+				text-transform: uppercase;
+			}
+
+			.models a, .models a:visited {
+				color:#FFFFFF;
+				margin-left:12px;
+				text-decoration: none;
+			}
+
+			.models a:hover, .models a:focus {
+				text-decoration: underline;
+			}
+		</style>
+	</head>
+
+	<body>
+
+
+		<div class="models">
+			<strong>Models</strong>
+			<a class="model" href="models/prwm/faceted-nefertiti.*.prwm">Faceted Nefertiti</a>
+			<a class="model" href="models/prwm/smooth-suzanne.*.prwm">Smooth Suzanne</a>
+			<a class="model" href="models/prwm/vive-controller.*.prwm">Vive Controller</a>
+		</div>
+		<div class="notes">
+			The parsing of PRWM file is especially fast when the endianness of the file is the same as the endianness
+			of the client platform. The loader will automatically replace the <strong>*</strong> in the model url
+			by either <strong>le</strong> or <strong>be</strong> depending on the client platform's endianness to
+			download the most appropriate file.<br><br>
+			This platform endianness is <strong id="endianness"></strong>.<br><br>
+			See your console for stats.<br><br>
+			<a href="https://github.com/kchapelier/PRWM" target="_blank">Specifications and implementations</a>
+		</div>
+
+		<script src="../build/three.js"></script>
+		<script src="js/loaders/PRWMLoader.js"></script>
+
+		<script>
+
+			var container;
+
+			var camera, scene, renderer;
+
+			var mouseX = 0, mouseY = 0;
+
+			var windowHalfX = window.innerWidth / 2;
+			var windowHalfY = window.innerHeight / 2;
+
+
+			init();
+			animate();
+
+
+			function init() {
+
+				document.getElementById( 'endianness' ).innerHTML = THREE.PRWMLoader.isBigEndianPlatform() ? 'big-endian' : 'little-endian';
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
+				camera.position.z = 250;
+
+				// scene
+
+				scene = new THREE.Scene();
+
+				var ambient = new THREE.AmbientLight( 0x101030 );
+				scene.add( ambient );
+
+				var directionalLight = new THREE.DirectionalLight( 0xffeedd );
+				directionalLight.position.set( 0, 0, 1 );
+				scene.add( directionalLight );
+
+				// model
+
+				var loader = new THREE.PRWMLoader();
+				var material = new THREE.MeshPhongMaterial( {} );
+				var busy = false;
+				var mesh = null;
+
+				var onProgress = function ( xhr ) {
+
+					if ( xhr.lengthComputable ) {
+
+						var percentComplete = xhr.loaded / xhr.total * 100;
+						console.log( Math.round( percentComplete, 2 ) + '% downloaded' );
+
+						if ( xhr.loaded === xhr.total ) {
+
+							console.log( 'File size: ' + ( xhr.total / 1024 ).toFixed( 2 ) + 'kB' );
+							console.timeEnd( 'Download' );
+
+						}
+
+					}
+
+				};
+
+				var onError = function ( xhr ) {
+
+					busy = false;
+
+				};
+
+				function loadGeometry( url ) {
+
+					if ( busy ) return;
+
+					busy = true;
+
+					if ( mesh !== null ) {
+
+						scene.remove( mesh );
+						mesh.geometry.dispose();
+
+					}
+
+					console.log( '-- Loading', url );
+					console.time( 'Download' );
+
+					loader.load( url, function ( geometry ) {
+
+						mesh = new THREE.Mesh( geometry, material );
+						mesh.scale.set( 50, 50, 50 );
+						scene.add( mesh );
+
+						console.log( geometry.index ? 'indexed geometry' : 'non-indexed geometry' );
+						console.log( '# of vertices: ' + geometry.attributes.position.count );
+						console.log( '# of polygons: ' + ( geometry.index ? geometry.index.count / 3 : geometry.attributes.position.count / 3 ) );
+						busy = false;
+
+					}, onProgress, onError );
+
+				}
+
+				//
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setPixelRatio( 1 );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				container.appendChild( renderer.domElement );
+
+				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+
+				//
+
+				document.querySelectorAll( 'a.model' ).forEach( function ( anchor ) {
+
+					anchor.addEventListener( 'click', function ( e ) {
+
+						e.preventDefault();
+
+						loadGeometry( anchor.href );
+
+					} );
+
+				} );
+
+				//
+
+				// * is automatically replaced by 'le' or 'be' depending on the client platform's endianness
+				loadGeometry( './models/prwm/smooth-suzanne.*.prwm' );
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function onWindowResize() {
+
+				windowHalfX = window.innerWidth / 2;
+				windowHalfY = window.innerHeight / 2;
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function onDocumentMouseMove( event ) {
+
+				mouseX = ( event.clientX - windowHalfX ) / 2;
+				mouseY = ( event.clientY - windowHalfY ) / 2;
+
+			}
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+				render();
+
+			}
+
+			function render() {
+
+				camera.position.x += ( mouseX - camera.position.x ) * .05;
+				camera.position.y += ( - mouseY - camera.position.y ) * .05;
+
+				camera.lookAt( scene.position );
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+	</body>
+</html>

File diff suppressed because it is too large
+ 249 - 181
examples/webgl_materials_nodes.html


+ 12 - 2
examples/webgl_mirror.html

@@ -88,11 +88,21 @@
 
 				// MIRROR planes
 
-				var groundMirror = new THREE.Mirror( 100, 100, { clipBias: 0.003, textureWidth: WIDTH, textureHeight: HEIGHT, color: 0x777777 } );
+				var groundMirror = new THREE.Mirror( 100, 100, {
+					clipBias: 0.003,
+					textureWidth: WIDTH * window.devicePixelRatio,
+					textureHeight: HEIGHT * window.devicePixelRatio,
+					color: 0x777777
+				} );
 				groundMirror.rotateX( - Math.PI / 2 );
 				scene.add( groundMirror );
 
-				var verticalMirror = new THREE.Mirror( 60, 60, { clipBias: 0.003, textureWidth: WIDTH, textureHeight: HEIGHT, color:0x889999 } );
+				var verticalMirror = new THREE.Mirror( 60, 60, {
+					clipBias: 0.003,
+					textureWidth: WIDTH * window.devicePixelRatio,
+					textureHeight: HEIGHT * window.devicePixelRatio,
+					color: 0x889999
+				} );
 				verticalMirror.position.y = 35;
 				verticalMirror.position.z = -45;
 				scene.add( verticalMirror );

+ 6 - 6
examples/webgl_panorama_equirectangular.html

@@ -141,11 +141,11 @@
 
 				isUserInteracting = true;
 
-				onPointerDownPointerX = event.clientX;
-				onPointerDownPointerY = event.clientY;
+				onMouseDownMouseX = event.clientX;
+				onMouseDownMouseY = event.clientY;
 
-				onPointerDownLon = lon;
-				onPointerDownLat = lat;
+				onMouseDownLon = lon;
+				onMouseDownLat = lat;
 
 			}
 
@@ -153,8 +153,8 @@
 
 				if ( isUserInteracting === true ) {
 
-					lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
-					lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
+					lon = ( onMouseDownMouseX - event.clientX ) * 0.1 + onMouseDownLon;
+					lat = ( event.clientY - onMouseDownMouseY ) * 0.1 + onMouseDownLat;
 
 				}
 

+ 2 - 20
examples/webgl_postprocessing_outline.html

@@ -1,5 +1,4 @@
 <!DOCTYPE html>
-
 <html lang="en">
 	<head>
 		<title>three.js webgl - post processing - Outline Pass</title>
@@ -311,25 +310,6 @@
 
 				window.addEventListener( 'resize', onWindowResize, false );
 
-				var moved = false;
-
-				controls.addEventListener( 'change', function() {
-
-					moved = true;
-
-				} );
-
-				window.addEventListener( 'mousedown', function () {
-
-					moved = false;
-
-				}, false );
-
-				window.addEventListener( 'mouseup', function() {
-					if(!moved)
-						checkIntersection();
-				} );
-
 				window.addEventListener( 'mousemove', onTouchMove );
 				window.addEventListener( 'touchmove', onTouchMove );
 
@@ -352,6 +332,8 @@
 					mouse.x = ( x / window.innerWidth ) * 2 - 1;
 					mouse.y = - ( y / window.innerHeight ) * 2 + 1;
 
+					checkIntersection();
+
 				}
 
 				function addSelectedObject(object) {

+ 74 - 5
examples/webgl_shadowmap_pointlight.html

@@ -51,7 +51,7 @@
 				scene = new THREE.Scene();
 				scene.add( new THREE.AmbientLight( 0x222233 ) );
 
-				// Lights
+				// lights
 
 				function createLight( color ) {
 
@@ -59,7 +59,6 @@
 					pointLight.castShadow = true;
 					pointLight.shadow.camera.near = 1;
 					pointLight.shadow.camera.far = 30;
-					// pointLight.shadowCameraVisible = true;
 					pointLight.shadow.bias = 0.01;
 
 					var geometry = new THREE.SphereGeometry( 0.3, 12, 6 );
@@ -67,7 +66,7 @@
 					var sphere = new THREE.Mesh( geometry, material );
 					pointLight.add( sphere );
 
-					return pointLight
+					return pointLight;
 
 				}
 
@@ -77,25 +76,62 @@
 				pointLight2 = createLight( 0xff0000 );
 				scene.add( pointLight2 );
 
+				//
+
 				var geometry = new THREE.TorusKnotGeometry( 14, 1, 150, 20 );
+
+				var texture = new THREE.CanvasTexture( generateTexture() );
+				texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
+				texture.repeat.set( 32, 1 );
+
 				var material = new THREE.MeshPhongMaterial( {
 					color: 0xff0000,
 					shininess: 100,
-					specular: 0x222222
+					specular: 0x222222,
+					alphaMap: texture, // alphaMap uses the g channel
+					alphaTest: 0.5,
+					transparent: true,
+					side: THREE.DoubleSide
 				} );
+
 				torusKnot = new THREE.Mesh( geometry, material );
 				torusKnot.position.set( 0, 5, 0 );
 				torusKnot.castShadow = true;
-				torusKnot.receiveShadow = true;
 				scene.add( torusKnot );
 
+				// custom distance material
+
+				var shader = THREE.ShaderLib[ "distanceRGBA" ];
+
+				var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
+				uniforms.alphaMap.value = material.alphaMap;
+				uniforms.offsetRepeat.value.set( texture.offset.x, texture.offset.y, texture.repeat.x, texture.repeat.y );
+
+				var distanceMaterial = new THREE.ShaderMaterial( {
+					defines: {
+						'USE_SHADOWMAP': '',
+						'USE_ALPHAMAP': '',
+						'ALPHATEST': material.alphaTest
+					},
+					uniforms: uniforms,
+					vertexShader: shader.vertexShader,
+					fragmentShader: shader.fragmentShader,
+					side: THREE.DoubleSide
+				} );
+
+				torusKnot.customDistanceMaterial = distanceMaterial;
+
+				//
+
 				var geometry = new THREE.BoxGeometry( 30, 30, 30 );
+
 				var material = new THREE.MeshPhongMaterial( {
 					color: 0xa0adaf,
 					shininess: 10,
 					specular: 0x111111,
 					side: THREE.BackSide
 				} );
+
 				var mesh = new THREE.Mesh( geometry, material );
 				mesh.position.y = 10;
 				mesh.receiveShadow = true;
@@ -108,6 +144,7 @@
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.shadowMap.enabled = true;
 				renderer.shadowMap.type = THREE.BasicShadowMap;
+				renderer.shadowMap.renderSingleSided = false; // must be set to false to honor double-sided materials
 				document.body.appendChild( renderer.domElement );
 
 				var controls = new THREE.OrbitControls( camera, renderer.domElement );
@@ -132,6 +169,38 @@
 
 			}
 
+			function generateTexture() {
+
+				var canvas = document.createElement( 'canvas' );
+				canvas.width = 256;
+				canvas.height = 256;
+
+				var context = canvas.getContext( '2d' );
+				var image = context.getImageData( 0, 0, 256, 256 );
+
+				var x = 0, y = 0, cvalue;
+
+				for ( var i = 0, j = 0, l = image.data.length; i < l; i += 4, j ++ ) {
+
+					x = j % 256;				// pixel col
+					y = ( x == 0 ) ? y + 1 : y;	// pixel row
+
+					// diagonal stripes
+					cvalue = Math.floor( ( x + y ) / 32 ) % 2;
+
+					image.data[ i + 0 ] = 255 * cvalue;
+					image.data[ i + 1 ] = 255 * cvalue;
+					image.data[ i + 2 ] = 255 * cvalue;
+					image.data[ i + 3 ] = 255;
+
+				}
+
+				context.putImageData( image, 0, 0 );
+
+				return canvas;
+
+			}
+
 			function animate() {
 
 				requestAnimationFrame( animate );

+ 281 - 0
examples/webgl_sprites_nodes.html

@@ -0,0 +1,281 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - sprites nodes</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 {
+				color: #fff;
+				font-family:Monospace;
+				font-size:13px;
+				margin: 0px;
+				text-align:center;
+				overflow: hidden;
+			}
+
+			#info {
+				color: #fff;
+				position: absolute;
+				top: 10px;
+				width: 100%;
+				text-align: center;
+				display:block;
+			}
+
+			a { color: white }
+		</style>
+	</head>
+	<body>
+
+		<div id="container"></div>
+		<div id="info">
+			<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - Node-Based Sprites
+		</div>
+
+		<script src="../build/three.js"></script>
+
+		<script src='js/geometries/TeapotBufferGeometry.js'></script>
+		<script src="js/controls/OrbitControls.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
+
+		<!-- NodeLibrary -->
+		<script src="js/nodes/GLNode.js"></script>
+		<script src="js/nodes/RawNode.js"></script>
+		<script src="js/nodes/TempNode.js"></script>
+		<script src="js/nodes/InputNode.js"></script>
+		<script src="js/nodes/ConstNode.js"></script>
+		<script src="js/nodes/VarNode.js"></script>
+		<script src="js/nodes/FunctionNode.js"></script>
+		<script src="js/nodes/FunctionCallNode.js"></script>
+		<script src="js/nodes/AttributeNode.js"></script>
+		<script src="js/nodes/NodeBuilder.js"></script>
+		<script src="js/nodes/NodeLib.js"></script>
+		<script src="js/nodes/NodeMaterial.js"></script>
+
+		<!-- Accessors -->
+		<script src="js/nodes/accessors/PositionNode.js"></script>
+		<script src="js/nodes/accessors/NormalNode.js"></script>
+		<script src="js/nodes/accessors/UVNode.js"></script>
+		<script src="js/nodes/accessors/ScreenUVNode.js"></script>
+		<script src="js/nodes/accessors/ColorsNode.js"></script>
+		<script src="js/nodes/accessors/CameraNode.js"></script>
+		<script src="js/nodes/accessors/ReflectNode.js"></script>
+		<script src="js/nodes/accessors/LightNode.js"></script>
+
+		<!-- Inputs -->
+		<script src="js/nodes/inputs/IntNode.js"></script>
+		<script src="js/nodes/inputs/FloatNode.js"></script>
+		<script src="js/nodes/inputs/ColorNode.js"></script>
+		<script src="js/nodes/inputs/Vector2Node.js"></script>
+		<script src="js/nodes/inputs/Vector3Node.js"></script>
+		<script src="js/nodes/inputs/Vector4Node.js"></script>
+		<script src="js/nodes/inputs/TextureNode.js"></script>
+		<script src="js/nodes/inputs/Matrix4Node.js"></script>
+		<script src="js/nodes/inputs/CubeTextureNode.js"></script>
+
+		<!-- Math -->
+		<script src="js/nodes/math/Math1Node.js"></script>
+		<script src="js/nodes/math/Math2Node.js"></script>
+		<script src="js/nodes/math/Math3Node.js"></script>
+		<script src="js/nodes/math/OperatorNode.js"></script>
+
+		<!-- Utils -->
+		<script src="js/nodes/utils/SwitchNode.js"></script>
+		<script src="js/nodes/utils/JoinNode.js"></script>
+		<script src="js/nodes/utils/TimerNode.js"></script>
+		<script src="js/nodes/utils/RoughnessToBlinnExponentNode.js"></script>
+		<script src="js/nodes/utils/VelocityNode.js"></script>
+		<script src="js/nodes/utils/LuminanceNode.js"></script>
+		<script src="js/nodes/utils/ColorAdjustmentNode.js"></script>
+		<script src="js/nodes/utils/NoiseNode.js"></script>
+		<script src="js/nodes/utils/ResolutionNode.js"></script>
+		<script src="js/nodes/utils/BumpNode.js"></script>
+		<script src="js/nodes/utils/BlurNode.js"></script>
+		<script src="js/nodes/utils/UVTransformNode.js"></script>
+
+		<!-- Sprite Material -->
+		<script src="js/nodes/materials/SpriteNode.js"></script>
+		<script src="js/nodes/materials/SpriteNodeMaterial.js"></script>
+		
+		<script>
+
+		var container = document.getElementById( 'container' );
+
+		var renderer, scene, camera, clock = new THREE.Clock(), fov = 50;
+		var plane, sprite1, sprite2, sprite3;
+		var controls;
+
+		window.addEventListener( 'load', init );
+
+		function init() {
+
+			//
+			// Renderer / Controls
+			//
+
+			renderer = new THREE.WebGLRenderer( { antialias: true } );
+			renderer.setPixelRatio( window.devicePixelRatio );
+			renderer.setSize( window.innerWidth, window.innerHeight );
+			container.appendChild( renderer.domElement );
+
+			scene = new THREE.Scene();
+			scene.fog = new THREE.Fog( 0x0000FF, 70, 150 );
+
+			camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 1000 );
+			camera.position.z = 100;
+			camera.target = new THREE.Vector3();
+
+			controls = new THREE.OrbitControls( camera, renderer.domElement );
+			controls.minDistance = 50;
+			controls.maxDistance = 200;
+
+			//
+			// SpriteNode
+			//
+
+			// use scale to adjuste the real sprite size
+			plane = new THREE.PlaneBufferGeometry( 1, 1 );
+
+			// https://openclipart.org/detail/239883/walking-man-sprite-sheet
+			var walkingManTexture = new THREE.TextureLoader().load( "textures/WalkingManSpriteSheet.png" );
+			walkingManTexture.wrapS = walkingManTexture.wrapT = THREE.RepeatWrapping;
+
+			// horizontal sprite-sheet animator
+
+			function createHorizontalSpriteSheetNode( hCount, speed ) {
+
+				var speed = new THREE.Vector2Node( speed, 0 ); // frame per second
+				var scale = new THREE.Vector2Node( 1 / hCount, 1 ); // 8 horizontal images in sprite-sheet
+
+				var uvTimer = new THREE.OperatorNode(
+					new THREE.TimerNode(),
+					speed,
+					THREE.OperatorNode.MUL
+				);
+
+				var uvIntegerTimer = new THREE.Math1Node(
+					uvTimer,
+					THREE.Math1Node.FLOOR
+				);
+
+				var uvFrameOffset = new THREE.OperatorNode(
+					uvIntegerTimer,
+					scale,
+					THREE.OperatorNode.MUL
+				);
+
+				var uvScale = new THREE.OperatorNode(
+					new THREE.UVNode(),
+					scale,
+					THREE.OperatorNode.MUL
+				);
+
+				var uvFrame = new THREE.OperatorNode(
+					uvScale,
+					uvFrameOffset,
+					THREE.OperatorNode.ADD
+				);
+
+				return uvFrame;
+
+			}
+
+			// sprites
+
+			var spriteWidth = 20,
+				spriteHeight = 20;
+
+			scene.add( sprite1 = new THREE.Mesh( plane, new THREE.SpriteNodeMaterial() ) );
+			sprite1.scale.x = spriteWidth;
+			sprite1.scale.y = spriteHeight;
+			sprite1.material.color = new THREE.TextureNode( walkingManTexture );
+			sprite1.material.color.coord = createHorizontalSpriteSheetNode( 8, 10 );
+			sprite1.material.build();
+
+			scene.add( sprite2 = new THREE.Mesh( plane, new THREE.SpriteNodeMaterial() ) );
+			sprite2.position.x = 30;
+			sprite2.scale.x = spriteWidth;
+			sprite2.scale.y = spriteHeight;
+			sprite2.material.color = new THREE.TextureNode( walkingManTexture );
+			sprite2.material.color.coord = createHorizontalSpriteSheetNode( 8, 30 );
+			sprite2.material.color = new THREE.Math1Node( sprite2.material.color, THREE.Math1Node.INVERT );
+			sprite2.material.spherical = false; // look at camera horizontally only, very used to vegetation
+			// horizontal zigzag sprite
+			sprite2.material.transform = new THREE.OperatorNode(
+				new THREE.OperatorNode( 
+					new THREE.Math1Node( new THREE.TimerNode( 0, 3 ), THREE.Math1Node.SIN ), // 3 is speed (time scale)
+					new THREE.Vector2Node( .3, 0 ), // horizontal scale (position)
+					THREE.OperatorNode.MUL
+				),
+				new THREE.PositionNode(),
+				THREE.OperatorNode.ADD
+			);
+			sprite2.material.build();
+
+			var sineWaveFunction = new THREE.FunctionNode( [
+				// https://stackoverflow.com/questions/36174431/how-to-make-a-wave-warp-effect-in-shader
+				"vec2 sineWave(vec2 uv, vec2 phase) {",
+				// wave distortion
+				"	float x = sin( 25.0*uv.y + 30.0*uv.x + 6.28*phase.x) * 0.01;",
+				"	float y = sin( 25.0*uv.y + 30.0*uv.x + 6.28*phase.y) * 0.03;",
+				"	return vec2(uv.x+x, uv.y+y);",
+				"}"
+			].join( "\n" ) );
+
+			scene.add( sprite3 = new THREE.Mesh( plane, new THREE.SpriteNodeMaterial() ) );
+			sprite3.position.x = - 30;
+			sprite3.scale.x = spriteWidth;
+			sprite3.scale.y = spriteHeight;
+			sprite3.material.fog = true;
+			sprite3.material.color = new THREE.TextureNode( walkingManTexture );
+			sprite3.material.color.coord = new THREE.FunctionCallNode( sineWaveFunction, {
+				"uv": createHorizontalSpriteSheetNode( 8, 0 ),
+				"phase": new THREE.TimerNode()
+			} );
+			sprite3.material.build();
+
+			//
+			// Events
+			//
+
+			window.addEventListener( 'resize', onWindowResize, false );
+
+			onWindowResize();
+			animate();
+
+		}
+
+		function onWindowResize() {
+
+			var width = window.innerWidth, height = window.innerHeight;
+
+			camera.aspect = width / height;
+			camera.updateProjectionMatrix();
+
+			renderer.setSize( width, height );
+
+		}
+
+		function animate() {
+
+			var delta = clock.getDelta();
+
+			// update material animation and/or gpu calcs (pre-renderer)
+			sprite1.material.updateFrame( delta );
+			sprite2.material.updateFrame( delta );
+			sprite3.material.updateFrame( delta );
+
+			// rotate sprite
+			sprite3.rotation.z -= Math.PI * .005;
+
+			renderer.render( scene, camera );
+
+			requestAnimationFrame( animate );
+
+		}
+
+		</script>
+
+	</body>
+</html>

+ 8 - 12
examples/webvr_cubes.html

@@ -4,8 +4,8 @@
 		<title>three.js webvr - cubes</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
-		<!-- Origin Trial Token, feature = WebVR, origin = https://threejs.org, expires = 2017-06-13 -->
-		<meta http-equiv="origin-trial" data-feature="WebVR" data-expires="2017-06-13" content="ApAQvHfiHMQB7SmRhfvCUX61adJaTA6pAu0Ry439jjeipa5lGm1RcTQynFoHGGcaSJkWfMOv7qK6pwSUb95ClQgAAABKeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJWUiIsImV4cGlyeSI6MTQ5NzMxMjAwMH0=">
+		<!-- Origin Trial Token, feature = WebVR (For Chrome M59+), origin = https://threejs.org, expires = 2017-07-28 -->
+		<meta http-equiv="origin-trial" data-feature="WebVR (For Chrome M59+)" data-expires="2017-07-28" content="Ave6CPNUgSwHb3vCbyd55P/R7pfkwNniUJsYfSoUqI+l1X1BIOt6HfriVP0g2hmaG7Pp3qaUXuXdZeqGBmoMKg8AAABNeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJWUjEuMSIsImV4cGlyeSI6MTUwMTI2NzQwNX0=">
 		<style>
 			body {
 				font-family: Monospace;
@@ -23,8 +23,6 @@
 
 		<script src="../build/three.js"></script>
 
-		<script src="js/controls/VRControls.js"></script>
-		<script src="js/effects/VREffect.js"></script>
 		<script src="js/vr/WebVR.js"></script>
 
 		<script>
@@ -41,7 +39,6 @@
 
 			var container;
 			var camera, scene, raycaster, renderer;
-			var effect, controls;
 
 			var room;
 			var isMouseDown = false;
@@ -129,11 +126,12 @@
 				renderer.sortObjects = false;
 				container.appendChild( renderer.domElement );
 
-				controls = new THREE.VRControls( camera );
-				effect = new THREE.VREffect( renderer );
+				renderer.vr.enabled = true;
 
 				WEBVR.getVRDisplay( function ( display ) {
 
+					renderer.vr.setDevice( display );
+
 					document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) );
 
 				} );
@@ -166,7 +164,7 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
-				effect.setSize( window.innerWidth, window.innerHeight );
+				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}
 
@@ -174,8 +172,7 @@
 
 			function animate() {
 
-				effect.requestAnimationFrame( animate );
-				render();
+				renderer.animate( render );
 
 			}
 
@@ -261,8 +258,7 @@
 
 				}
 
-				controls.update();
-				effect.render( scene, camera );
+				renderer.render( scene, camera );
 
 			}
 

+ 11 - 17
examples/webvr_daydream.html

@@ -4,8 +4,8 @@
 		<title>three.js webvr - daydream</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
-		<!-- Origin Trial Token, feature = WebVR, origin = https://threejs.org, expires = 2017-06-13 -->
-		<meta http-equiv="origin-trial" data-feature="WebVR" data-expires="2017-06-13" content="ApAQvHfiHMQB7SmRhfvCUX61adJaTA6pAu0Ry439jjeipa5lGm1RcTQynFoHGGcaSJkWfMOv7qK6pwSUb95ClQgAAABKeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJWUiIsImV4cGlyeSI6MTQ5NzMxMjAwMH0=">
+		<!-- Origin Trial Token, feature = WebVR (For Chrome M59+), origin = https://threejs.org, expires = 2017-07-28 -->
+		<meta http-equiv="origin-trial" data-feature="WebVR (For Chrome M59+)" data-expires="2017-07-28" content="Ave6CPNUgSwHb3vCbyd55P/R7pfkwNniUJsYfSoUqI+l1X1BIOt6HfriVP0g2hmaG7Pp3qaUXuXdZeqGBmoMKg8AAABNeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJWUjEuMSIsImV4cGlyeSI6MTUwMTI2NzQwNX0=">
 		<style>
 			body {
 				font-family: Monospace;
@@ -25,7 +25,6 @@
 
 		<script src="js/vr/DaydreamController.js"></script>
 		<script src="js/vr/WebVR.js"></script>
-		<script src="js/vr/WebVRCamera.js"></script>
 
 		<script>
 
@@ -41,7 +40,7 @@
 
 			var container;
 			var camera, scene, ray, raycaster, renderer;
-			var gamepad, vrdisplay;
+			var gamepad;
 
 			var room;
 
@@ -119,18 +118,14 @@
 				renderer.sortObjects = false;
 				container.appendChild( renderer.domElement );
 
-				//
-
-				WEBVR.getVRDisplay( function ( display ) {
-
-					if ( display !== undefined ) {
+				renderer.vr.enabled = true;
 
-						vrdisplay = display;
-						camera = new THREE.WebVRCamera( display, renderer );
+				//
 
-					}
+				WEBVR.getVRDisplay( function ( device ) {
 
-					document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) );
+					renderer.vr.setDevice( device );
+					document.body.appendChild( WEBVR.getButton( device, renderer.domElement ) );
 
 				} );
 
@@ -171,15 +166,14 @@
 
 			function animate() {
 
-				gamepad.update();
-				render();
-
-				( vrdisplay ? vrdisplay : window ).requestAnimationFrame( animate );
+				renderer.animate( render );
 
 			}
 
 			function render() {
 
+				gamepad.update();
+
 				var delta = clock.getDelta() * 60;
 
 				// find intersections

+ 16 - 15
examples/webvr_panorama.html

@@ -4,8 +4,8 @@
 		<title>three.js webvr - panorama</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
-		<!-- Origin Trial Token, feature = WebVR, origin = https://threejs.org, expires = 2017-06-13 -->
-		<meta http-equiv="origin-trial" data-feature="WebVR" data-expires="2017-06-13" content="ApAQvHfiHMQB7SmRhfvCUX61adJaTA6pAu0Ry439jjeipa5lGm1RcTQynFoHGGcaSJkWfMOv7qK6pwSUb95ClQgAAABKeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJWUiIsImV4cGlyeSI6MTQ5NzMxMjAwMH0=">
+		<!-- Origin Trial Token, feature = WebVR (For Chrome M59+), origin = https://threejs.org, expires = 2017-07-28 -->
+		<meta http-equiv="origin-trial" data-feature="WebVR (For Chrome M59+)" data-expires="2017-07-28" content="Ave6CPNUgSwHb3vCbyd55P/R7pfkwNniUJsYfSoUqI+l1X1BIOt6HfriVP0g2hmaG7Pp3qaUXuXdZeqGBmoMKg8AAABNeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJWUjEuMSIsImV4cGlyeSI6MTUwMTI2NzQwNX0=">
 		<style>
 			html, body {
 				background-color: #000;
@@ -19,8 +19,6 @@
 	<body>
 		<script src="../build/three.js"></script>
 
-		<script src="js/controls/VRControls.js"></script>
-		<script src="js/effects/VREffect.js"></script>
 		<script src="js/vr/WebVR.js"></script>
 
 		<script>
@@ -34,7 +32,6 @@
 		//
 
 		var camera;
-		var effect, controls;
 		var renderer;
 		var scene;
 
@@ -48,20 +45,22 @@
 			renderer.setSize( window.innerWidth, window.innerHeight );
 			document.body.appendChild( renderer.domElement );
 
+			renderer.vr.enabled = true;
+
 			scene = new THREE.Scene();
 
-			camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 0.1, 100 );
+			camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 1, 1000 );
 			camera.layers.enable( 1 );
 
-			controls = new THREE.VRControls( camera );
-			effect = new THREE.VREffect( renderer );
-
 			WEBVR.getVRDisplay( function ( display ) {
 
+				renderer.vr.setDevice( display );
+
 				document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) );
 
 			} );
 
+			var geometry = new THREE.CubeGeometry( 100, 100, 100 );
 			var textures = getTexturesFromAtlasFile( "textures/cube/sun_temple_stripe_stereo.jpg", 12 );
 
 			var materials = [];
@@ -72,7 +71,7 @@
 
 			}
 
-			var skyBox = new THREE.Mesh( new THREE.CubeGeometry( 1, 1, 1 ), new THREE.MeshFaceMaterial( materials ) );
+			var skyBox = new THREE.Mesh( geometry, materials );
 			skyBox.applyMatrix( new THREE.Matrix4().makeScale( 1, 1, - 1 ) );
 			skyBox.layers.set( 1 );
 			scene.add( skyBox );
@@ -86,7 +85,7 @@
 
 			}
 
-			var skyBoxR = new THREE.Mesh( new THREE.CubeGeometry( 1, 1, 1 ), new THREE.MeshFaceMaterial( materialsR ) );
+			var skyBoxR = new THREE.Mesh( geometry, materialsR );
 			skyBoxR.applyMatrix( new THREE.Matrix4().makeScale( 1, 1, - 1 ) );
 			skyBoxR.layers.set( 2 );
 			scene.add( skyBoxR );
@@ -137,17 +136,19 @@
 			camera.aspect = window.innerWidth / window.innerHeight;
 			camera.updateProjectionMatrix();
 
-			effect.setSize( window.innerWidth, window.innerHeight );
+			renderer.setSize( window.innerWidth, window.innerHeight );
 
 		}
 
 		function animate() {
 
-			controls.update();
+			renderer.animate( render );
+
+		}
 
-			effect.render( scene, camera );
+		function render() {
 
-			effect.requestAnimationFrame( animate );
+			renderer.render( scene, camera );
 
 		}
 

+ 15 - 17
examples/webvr_rollercoaster.html

@@ -4,8 +4,8 @@
 		<title>three.js webvr - roller coaster</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
-		<!-- Origin Trial Token, feature = WebVR, origin = https://threejs.org, expires = 2017-06-13 -->
-		<meta http-equiv="origin-trial" data-feature="WebVR" data-expires="2017-06-13" content="ApAQvHfiHMQB7SmRhfvCUX61adJaTA6pAu0Ry439jjeipa5lGm1RcTQynFoHGGcaSJkWfMOv7qK6pwSUb95ClQgAAABKeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJWUiIsImV4cGlyeSI6MTQ5NzMxMjAwMH0=">
+		<!-- Origin Trial Token, feature = WebVR (For Chrome M59+), origin = https://threejs.org, expires = 2017-07-28 -->
+		<meta http-equiv="origin-trial" data-feature="WebVR (For Chrome M59+)" data-expires="2017-07-28" content="Ave6CPNUgSwHb3vCbyd55P/R7pfkwNniUJsYfSoUqI+l1X1BIOt6HfriVP0g2hmaG7Pp3qaUXuXdZeqGBmoMKg8AAABNeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJWUjEuMSIsImV4cGlyeSI6MTUwMTI2NzQwNX0=">
 		<style>
 			body {
 				margin: 0px;
@@ -25,8 +25,6 @@
 
 		<script src="js/RollerCoaster.js"></script>
 
-		<script src="js/controls/VRControls.js"></script>
-		<script src="js/effects/VREffect.js"></script>
 		<script src="js/vr/WebVR.js"></script>
 
 		<script>
@@ -45,6 +43,8 @@
 			renderer.setSize( window.innerWidth, window.innerHeight );
 			document.body.appendChild( renderer.domElement );
 
+			renderer.vr.enabled = true;
+
 			var scene = new THREE.Scene();
 
 			var light = new THREE.HemisphereLight( 0xfff0f0, 0x606066 );
@@ -186,25 +186,26 @@
 
 			//
 
-			var controls = new THREE.VRControls( camera );
-			var effect = new THREE.VREffect( renderer );
-
 			WEBVR.getVRDisplay( function ( display ) {
 
+				renderer.vr.setDevice( display );
+
 				document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) );
 
 			} );
 
 			//
 
-			window.addEventListener( 'resize', function () {
+			window.addEventListener( 'resize', onWindowResize, false );
+
+			function onWindowResize() {
 
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
-				effect.setSize( window.innerWidth, window.innerHeight );
+				renderer.setSize( window.innerWidth, window.innerHeight );
 
-			}, false );
+			}
 
 			//
 
@@ -218,10 +219,9 @@
 
 			var prevTime = performance.now();
 
-			function animate( time ) {
-
-				effect.requestAnimationFrame( animate );
+			function render() {
 
+				var time = performance.now();
 				var delta = time - prevTime;
 
 				for ( var i = 0; i < funfairs.length; i ++ ) {
@@ -249,15 +249,13 @@
 
 				//
 
-				controls.update();
-
-				effect.render( scene, camera );
+				renderer.render( scene, camera );
 
 				prevTime = time;
 
 			}
 
-			effect.requestAnimationFrame( animate );
+			renderer.animate( render );
 
 		</script>
 

+ 13 - 15
examples/webvr_sandbox.html

@@ -4,8 +4,8 @@
 		<title>three.js webvr - sandbox</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
-		<!-- Origin Trial Token, feature = WebVR, origin = https://threejs.org, expires = 2017-06-13 -->
-		<meta http-equiv="origin-trial" data-feature="WebVR" data-expires="2017-06-13" content="ApAQvHfiHMQB7SmRhfvCUX61adJaTA6pAu0Ry439jjeipa5lGm1RcTQynFoHGGcaSJkWfMOv7qK6pwSUb95ClQgAAABKeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJWUiIsImV4cGlyeSI6MTQ5NzMxMjAwMH0=">
+		<!-- Origin Trial Token, feature = WebVR (For Chrome M59+), origin = https://threejs.org, expires = 2017-07-28 -->
+		<meta http-equiv="origin-trial" data-feature="WebVR (For Chrome M59+)" data-expires="2017-07-28" content="Ave6CPNUgSwHb3vCbyd55P/R7pfkwNniUJsYfSoUqI+l1X1BIOt6HfriVP0g2hmaG7Pp3qaUXuXdZeqGBmoMKg8AAABNeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJWUjEuMSIsImV4cGlyeSI6MTUwMTI2NzQwNX0=">
 		<style>
 			body {
 				margin: 0px;
@@ -17,8 +17,6 @@
 
 		<script src="../build/three.js"></script>
 
-		<script src="js/controls/VRControls.js"></script>
-		<script src="js/effects/VREffect.js"></script>
 		<script src="js/vr/WebVR.js"></script>
 
 		<script src="js/Mirror.js"></script>
@@ -34,7 +32,6 @@
 			//
 
 			var camera, scene, renderer;
-			var effect, controls;
 
 			var mirror;
 
@@ -90,7 +87,10 @@
 
 				//
 
-				mirror = new THREE.Mirror( 1.4, 1.4, { textureWidth: window.innerWidth, textureHeight: window.innerHeight } );
+				mirror = new THREE.Mirror( 1.4, 1.4, {
+					textureWidth: window.innerWidth * window.devicePixelRatio,
+					textureHeight: window.innerHeight * window.devicePixelRatio
+				} );
 				mirror.position.x = 1;
 				mirror.position.y = 0.5;
 				mirror.position.z = -3;
@@ -114,13 +114,14 @@
 				renderer.shadowMap.enabled = true;
 				document.body.appendChild( renderer.domElement );
 
-				//
+				renderer.vr.enabled = true;
 
-				controls = new THREE.VRControls( camera );
-				effect = new THREE.VREffect( renderer );
+				//
 
 				WEBVR.getVRDisplay( function ( display ) {
 
+					renderer.vr.setDevice( display );
+
 					document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) );
 
 				} );
@@ -136,14 +137,13 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
-				effect.setSize( window.innerWidth, window.innerHeight );
+				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}
 
 			function animate() {
 
-				effect.requestAnimationFrame( animate );
-				render();
+				renderer.animate( render );
 
 			}
 
@@ -154,9 +154,7 @@
 				mesh.rotation.x = time * 2;
 				mesh.rotation.y = time * 5;
 
-				controls.update();
-
-				effect.render( scene, camera );
+				renderer.render( scene, camera );
 
 			}
 

+ 9 - 18
examples/webvr_video.html

@@ -4,8 +4,8 @@
 		<title>three.js webvr - video</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
-		<!-- Origin Trial Token, feature = WebVR, origin = https://threejs.org, expires = 2017-06-13 -->
-		<meta http-equiv="origin-trial" data-feature="WebVR" data-expires="2017-06-13" content="ApAQvHfiHMQB7SmRhfvCUX61adJaTA6pAu0Ry439jjeipa5lGm1RcTQynFoHGGcaSJkWfMOv7qK6pwSUb95ClQgAAABKeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJWUiIsImV4cGlyeSI6MTQ5NzMxMjAwMH0=">
+		<!-- Origin Trial Token, feature = WebVR (For Chrome M59+), origin = https://threejs.org, expires = 2017-07-28 -->
+		<meta http-equiv="origin-trial" data-feature="WebVR (For Chrome M59+)" data-expires="2017-07-28" content="Ave6CPNUgSwHb3vCbyd55P/R7pfkwNniUJsYfSoUqI+l1X1BIOt6HfriVP0g2hmaG7Pp3qaUXuXdZeqGBmoMKg8AAABNeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJWUjEuMSIsImV4cGlyeSI6MTUwMTI2NzQwNX0=">
 		<style>
 			body {
 				font-family: Monospace;
@@ -34,8 +34,6 @@
 
 		<script src="../build/three.js"></script>
 
-		<script src="js/controls/VRControls.js"></script>
-		<script src="js/effects/VREffect.js"></script>
 		<script src="js/vr/WebVR.js"></script>
 
 		<script>
@@ -51,8 +49,6 @@
 			var camera, scene, renderer;
 			var video, texture;
 
-			var controls, effect;
-
 			init();
 			animate();
 
@@ -142,16 +138,14 @@
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );
 
-				//
-
-				controls = new THREE.VRControls( camera );
+				renderer.vr.enabled = true;
 
-				effect = new THREE.VREffect( renderer );
-				effect.scale = 0; // video doesn't need eye separation
-				effect.setSize( window.innerWidth, window.innerHeight );
+				//
 
 				WEBVR.getVRDisplay( function ( display ) {
 
+					renderer.vr.setDevice( display );
+
 					document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) );
 
 				} );
@@ -168,22 +162,19 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
-				effect.setSize( window.innerWidth, window.innerHeight );
+				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}
 
 			function animate() {
 
-				effect.requestAnimationFrame( animate );
-				render();
+				renderer.animate( render );
 
 			}
 
 			function render() {
 
-				controls.update();
-
-				effect.render( scene, camera );
+				renderer.render( scene, camera );
 
 			}
 

+ 11 - 17
examples/webvr_vive.html

@@ -21,8 +21,6 @@
 
 		<script src="../build/three.js"></script>
 
-		<script src="js/controls/VRControls.js"></script>
-		<script src="js/effects/VREffect.js"></script>
 		<script src="js/vr/ViveController.js"></script>
 		<script src="js/vr/WebVR.js"></script>
 
@@ -42,7 +40,6 @@
 
 			var container;
 			var camera, scene, renderer;
-			var effect, controls;
 			var controller1, controller2;
 
 			var room;
@@ -165,17 +162,17 @@
 				renderer.sortObjects = false;
 				container.appendChild( renderer.domElement );
 
-				controls = new THREE.VRControls( camera );
-				controls.standing = true;
+				renderer.vr.enabled = true;
+				renderer.vr.standing = true;
 
 				// controllers
 
 				controller1 = new THREE.ViveController( 0 );
-				controller1.standingMatrix = controls.getStandingMatrix();
+				controller1.standingMatrix = renderer.vr.getStandingMatrix();
 				scene.add( controller1 );
 
 				controller2 = new THREE.ViveController( 1 );
-				controller2.standingMatrix = controls.getStandingMatrix();
+				controller2.standingMatrix = renderer.vr.getStandingMatrix();
 				scene.add( controller2 );
 
 				var loader = new THREE.OBJLoader();
@@ -194,10 +191,10 @@
 
 				} );
 
-				effect = new THREE.VREffect( renderer );
-
 				WEBVR.getVRDisplay( function ( display ) {
 
+					renderer.vr.setDevice( display );
+
 					document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) );
 
 				} );
@@ -213,19 +210,18 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
-				effect.setSize( window.innerWidth, window.innerHeight );
+				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}
 
-			//
-
 			function animate() {
 
-				effect.requestAnimationFrame( animate );
-				render();
+				renderer.animate( render );
 
 			}
 
+			//
+
 			function render() {
 
 				var delta = clock.getDelta() * 60;
@@ -233,8 +229,6 @@
 				controller1.update();
 				controller2.update();
 
-				controls.update();
-
 				for ( var i = 0; i < room.children.length; i ++ ) {
 
 					var cube = room.children[ i ];
@@ -268,7 +262,7 @@
 
 				}
 
-				effect.render( scene, camera );
+				renderer.render( scene, camera );
 
 			}
 

+ 9 - 15
examples/webvr_vive_camerarig.html

@@ -21,8 +21,6 @@
 
 		<script src="../build/three.js"></script>
 
-		<script src="js/controls/VRControls.js"></script>
-		<script src="js/effects/VREffect.js"></script>
 		<script src="js/vr/ViveController.js"></script>
 		<script src="js/vr/WebVR.js"></script>
 
@@ -42,7 +40,6 @@
 
 			var container;
 			var cameraRig, camera, scene, renderer;
-			var effect, controls;
 			var controller1, controller2;
 			var scale = 1;
 			var dragging = {
@@ -174,19 +171,19 @@
 				renderer.sortObjects = false;
 				container.appendChild( renderer.domElement );
 
-				controls = new THREE.VRControls( camera );
-				controls.standing = true;
+				renderer.vr.enabled = true;
+				renderer.vr.standing = true;
 
 				// controllers
 
 				controller1 = new THREE.ViveController( 0 );
-				controller1.standingMatrix = controls.getStandingMatrix();
+				controller1.standingMatrix = renderer.vr.getStandingMatrix();
 				controller1.addEventListener( 'triggerdown', onTriggerDown );
 				controller1.addEventListener( 'triggerup', onTriggerUp );
 				cameraRig.add( controller1 );
 
 				controller2 = new THREE.ViveController( 1 );
-				controller2.standingMatrix = controls.getStandingMatrix();
+				controller2.standingMatrix = renderer.vr.getStandingMatrix();
 				controller2.addEventListener( 'triggerdown', onTriggerDown );
 				controller2.addEventListener( 'triggerup', onTriggerUp );
 				cameraRig.add( controller2 );
@@ -207,10 +204,10 @@
 
 				} );
 
-				effect = new THREE.VREffect( renderer );
-
 				WEBVR.getVRDisplay( function ( display ) {
 
+					renderer.vr.setDevice( display );
+
 					document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) );
 
 				} );
@@ -226,7 +223,7 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
-				effect.setSize( window.innerWidth, window.innerHeight );
+				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}
 
@@ -234,8 +231,7 @@
 
 			function animate() {
 
-				effect.requestAnimationFrame( animate );
-				render();
+				renderer.animate( render );
 
 			}
 
@@ -246,8 +242,6 @@
 				controller1.update();
 				controller2.update();
 
-				controls.update();
-
 				scaleUpdate();
 
 				for ( var i = 0; i < room.children.length; i ++ ) {
@@ -283,7 +277,7 @@
 
 				}
 
-				effect.render( scene, camera );
+				renderer.render( scene, camera );
 
 			}
 

+ 9 - 15
examples/webvr_vive_dragging.html

@@ -21,8 +21,6 @@
 
 		<script src="../build/three.js"></script>
 
-		<script src="js/controls/VRControls.js"></script>
-		<script src="js/effects/VREffect.js"></script>
 		<script src="js/vr/ViveController.js"></script>
 		<script src="js/vr/WebVR.js"></script>
 
@@ -40,7 +38,6 @@
 
 			var container;
 			var camera, scene, renderer;
-			var effect, controls;
 			var controller1, controller2;
 
 			var raycaster, intersected = [];
@@ -142,19 +139,19 @@
 				renderer.gammaOutput = true;
 				container.appendChild( renderer.domElement );
 
-				controls = new THREE.VRControls( camera );
-				controls.standing = true;
+				renderer.vr.enabled = true;
+				renderer.vr.standing = true;
 
 				// controllers
 
 				controller1 = new THREE.ViveController( 0 );
-				controller1.standingMatrix = controls.getStandingMatrix();
+				controller1.standingMatrix = renderer.vr.getStandingMatrix();
 				controller1.addEventListener( 'triggerdown', onTriggerDown );
 				controller1.addEventListener( 'triggerup', onTriggerUp );
 				scene.add( controller1 );
 
 				controller2 = new THREE.ViveController( 1 );
-				controller2.standingMatrix = controls.getStandingMatrix();
+				controller2.standingMatrix = renderer.vr.getStandingMatrix();
 				controller2.addEventListener( 'triggerdown', onTriggerDown );
 				controller2.addEventListener( 'triggerup', onTriggerUp );
 				scene.add( controller2 );
@@ -193,10 +190,10 @@
 
 				//
 
-				effect = new THREE.VREffect( renderer );
-
 				WEBVR.getVRDisplay( function ( display ) {
 
+					renderer.vr.setDevice( display );
+
 					document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) );
 
 				} );
@@ -212,7 +209,7 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
-				effect.setSize( window.innerWidth, window.innerHeight );
+				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}
 
@@ -312,8 +309,7 @@
 
 			function animate() {
 
-				effect.requestAnimationFrame( animate );
-				render();
+				renderer.animate( render );
 
 			}
 
@@ -322,14 +318,12 @@
 				controller1.update();
 				controller2.update();
 
-				controls.update();
-
 				cleanIntersected();
 
 				intersectObjects( controller1 );
 				intersectObjects( controller2 );
 
-				effect.render( scene, camera );
+				renderer.render( scene, camera );
 
 			}
 

+ 14 - 20
examples/webvr_vive_paint.html

@@ -21,8 +21,6 @@
 
 		<script src="../build/three.js"></script>
 
-		<script src="js/controls/VRControls.js"></script>
-		<script src="js/effects/VREffect.js"></script>
 		<script src="js/vr/ViveController.js"></script>
 		<script src="js/vr/PaintViveController.js"></script>
 		<script src="js/vr/WebVR.js"></script>
@@ -41,7 +39,6 @@
 
 			var container;
 			var camera, scene, renderer;
-			var effect, controls;
 			var controller1, controller2;
 
 			var line;
@@ -142,19 +139,19 @@
 				renderer.gammaOutput = true;
 				container.appendChild( renderer.domElement );
 
-				controls = new THREE.VRControls( camera );
-				controls.standing = true;
+				renderer.vr.enabled = true;
+				renderer.vr.standing = true;
 
 				// controllers
 
 				controller1 = new THREE.PaintViveController( 0 );
-				controller1.standingMatrix = controls.getStandingMatrix();
+				controller1.standingMatrix = renderer.vr.getStandingMatrix();
 				controller1.userData.points = [ new THREE.Vector3(), new THREE.Vector3() ];
 				controller1.userData.matrices = [ new THREE.Matrix4(), new THREE.Matrix4() ];
 				scene.add( controller1 );
 
 				controller2 = new THREE.PaintViveController( 1 );
-				controller2.standingMatrix = controls.getStandingMatrix();
+				controller2.standingMatrix = renderer.vr.getStandingMatrix();
 				controller2.userData.points = [ new THREE.Vector3(), new THREE.Vector3() ];
 				controller2.userData.matrices = [ new THREE.Matrix4(), new THREE.Matrix4() ];
 				scene.add( controller2 );
@@ -188,10 +185,10 @@
 
 				} );
 
-				effect = new THREE.VREffect( renderer );
-
 				WEBVR.getVRDisplay( function ( display ) {
 
+					renderer.vr.setDevice( display );
+
 					document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) );
 
 				} );
@@ -387,19 +384,12 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
-				effect.setSize( window.innerWidth, window.innerHeight );
+				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}
 
 			//
 
-			function animate() {
-
-				effect.requestAnimationFrame( animate );
-				render();
-
-			}
-
 			function handleController( controller ) {
 
 				controller.update();
@@ -435,9 +425,13 @@
 
 			}
 
-			function render() {
+			function animate() {
+
+				renderer.animate( render );
 
-				controls.update();
+			}
+
+			function render() {
 
 				var count = line.geometry.drawRange.count;
 
@@ -446,7 +440,7 @@
 
 				updateGeometry( count, line.geometry.drawRange.count );
 
-				effect.render( scene, camera );
+				renderer.render( scene, camera );
 
 			}
 

+ 9 - 15
examples/webvr_vive_sculpt.html

@@ -21,8 +21,6 @@
 
 		<script src="../build/three.js"></script>
 
-		<script src="js/controls/VRControls.js"></script>
-		<script src="js/effects/VREffect.js"></script>
 		<script src="js/vr/ViveController.js"></script>
 		<script src="js/vr/WebVR.js"></script>
 
@@ -41,7 +39,6 @@
 
 			var container;
 			var camera, scene, renderer;
-			var effect, controls;
 			var controller1, controller2;
 
 			var blob, vector;
@@ -124,17 +121,17 @@
 				renderer.gammaOutput = true;
 				container.appendChild( renderer.domElement );
 
-				controls = new THREE.VRControls( camera );
-				controls.standing = true;
+				renderer.vr.enabled = true;
+				renderer.vr.standing = true;
 
 				// controllers
 
 				controller1 = new THREE.ViveController( 0 );
-				controller1.standingMatrix = controls.getStandingMatrix();
+				controller1.standingMatrix = renderer.vr.getStandingMatrix();
 				scene.add( controller1 );
 
 				controller2 = new THREE.ViveController( 1 );
-				controller2.standingMatrix = controls.getStandingMatrix();
+				controller2.standingMatrix = renderer.vr.getStandingMatrix();
 				scene.add( controller2 );
 
 				var loader = new THREE.OBJLoader();
@@ -166,10 +163,10 @@
 
 				} );
 
-				effect = new THREE.VREffect( renderer );
-
 				WEBVR.getVRDisplay( function ( display ) {
 
+					renderer.vr.setDevice( display );
+
 					document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) );
 
 				} );
@@ -223,7 +220,7 @@
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 
-				effect.setSize( window.innerWidth, window.innerHeight );
+				renderer.setSize( window.innerWidth, window.innerHeight );
 
 			}
 
@@ -231,8 +228,7 @@
 
 			function animate() {
 
-				effect.requestAnimationFrame( animate );
-				render();
+				renderer.animate( render );
 
 			}
 
@@ -329,9 +325,7 @@
 
 				updateBlob();
 
-				controls.update();
-
-				effect.render( scene, camera );
+				renderer.render( scene, camera );
 
 			}
 

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "three",
-  "version": "0.85.2",
+  "version": "0.86.0",
   "description": "JavaScript 3D library",
   "main": "build/three.js",
   "repository": "mrdoob/three.js",

+ 2 - 0
src/Three.js

@@ -134,6 +134,8 @@ export { FaceNormalsHelper } from './helpers/FaceNormalsHelper.js';
 export { DirectionalLightHelper } from './helpers/DirectionalLightHelper.js';
 export { CameraHelper } from './helpers/CameraHelper.js';
 export { BoxHelper } from './helpers/BoxHelper.js';
+export { Box3Helper } from './helpers/Box3Helper.js';
+export { PlaneHelper } from './helpers/PlaneHelper.js';
 export { ArrowHelper } from './helpers/ArrowHelper.js';
 export { AxisHelper } from './helpers/AxisHelper.js';
 export { CatmullRomCurve3 } from './extras/curves/CatmullRomCurve3.js';

+ 1 - 1
src/constants.js

@@ -1,4 +1,4 @@
-export var REVISION = '86dev';
+export var REVISION = '87dev';
 export var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };
 export var CullFaceNone = 0;
 export var CullFaceBack = 1;

+ 5 - 5
src/helpers/AxisHelper.js

@@ -1,14 +1,14 @@
+/**
+ * @author sroucheray / http://sroucheray.org/
+ * @author mrdoob / http://mrdoob.com/
+ */
+
 import { LineSegments } from '../objects/LineSegments';
 import { VertexColors } from '../constants';
 import { LineBasicMaterial } from '../materials/LineBasicMaterial';
 import { Float32BufferAttribute } from '../core/BufferAttribute';
 import { BufferGeometry } from '../core/BufferGeometry';
 
-/**
- * @author sroucheray / http://sroucheray.org/
- * @author mrdoob / http://mrdoob.com/
- */
-
 function AxisHelper( size ) {
 
 	size = size || 1;

+ 55 - 0
src/helpers/Box3Helper.js

@@ -0,0 +1,55 @@
+/**
+ * @author WestLangley / http://github.com/WestLangley
+ */
+
+import { Box3 } from '../math/Box3';
+import { LineSegments } from '../objects/LineSegments';
+import { LineBasicMaterial } from '../materials/LineBasicMaterial';
+import { BufferAttribute } from '../core/BufferAttribute';
+import { Float32BufferAttribute } from '../core/BufferAttribute';
+import { BufferGeometry } from '../core/BufferGeometry';
+
+function Box3Helper( box, hex ) {
+
+	this.type = 'Box3Helper';
+
+	this.box = box;
+
+	var color = ( hex !== undefined ) ? hex : 0xffff00;
+
+	var indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
+
+	var positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ];
+
+	var geometry = new BufferGeometry();
+
+	geometry.setIndex( new BufferAttribute( indices, 1 ) );
+
+	geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
+
+	LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) );
+
+	this.geometry.computeBoundingSphere();
+
+	this.onBeforeRender();
+
+}
+
+Box3Helper.prototype = Object.create( LineSegments.prototype );
+Box3Helper.prototype.constructor = Box3Helper;
+
+Box3Helper.prototype.onBeforeRender = function () {
+
+	var box = this.box;
+
+	if ( box.isEmpty() ) return;
+
+	box.getCenter( this.position );
+
+	box.getSize( this.scale );
+
+	this.scale.multiplyScalar( 0.5 );
+
+};
+
+export { Box3Helper };

+ 5 - 5
src/helpers/BoxHelper.js

@@ -1,14 +1,14 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author Mugen87 / http://github.com/Mugen87
+ */
+
 import { Box3 } from '../math/Box3';
 import { LineSegments } from '../objects/LineSegments';
 import { LineBasicMaterial } from '../materials/LineBasicMaterial';
 import { BufferAttribute } from '../core/BufferAttribute';
 import { BufferGeometry } from '../core/BufferGeometry';
 
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author Mugen87 / http://github.com/Mugen87
- */
-
 function BoxHelper( object, color ) {
 
 	this.object = object;

+ 9 - 9
src/helpers/CameraHelper.js

@@ -1,12 +1,3 @@
-import { Camera } from '../cameras/Camera';
-import { Vector3 } from '../math/Vector3';
-import { LineSegments } from '../objects/LineSegments';
-import { Color } from '../math/Color';
-import { FaceColors } from '../constants';
-import { LineBasicMaterial } from '../materials/LineBasicMaterial';
-import { BufferGeometry } from '../core/BufferGeometry';
-import { Float32BufferAttribute } from '../core/BufferAttribute';
-
 /**
  * @author alteredq / http://alteredqualia.com/
  * @author Mugen87 / https://github.com/Mugen87
@@ -17,6 +8,15 @@ import { Float32BufferAttribute } from '../core/BufferAttribute';
  *		http://evanw.github.com/lightgl.js/tests/shadowmap.html
  */
 
+import { Camera } from '../cameras/Camera';
+import { Vector3 } from '../math/Vector3';
+import { LineSegments } from '../objects/LineSegments';
+import { Color } from '../math/Color';
+import { FaceColors } from '../constants';
+import { LineBasicMaterial } from '../materials/LineBasicMaterial';
+import { BufferGeometry } from '../core/BufferGeometry';
+import { Float32BufferAttribute } from '../core/BufferAttribute';
+
 function CameraHelper( camera ) {
 
 	var geometry = new BufferGeometry();

+ 6 - 6
src/helpers/DirectionalLightHelper.js

@@ -1,3 +1,9 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ * @author mrdoob / http://mrdoob.com/
+ * @author WestLangley / http://github.com/WestLangley
+ */
+
 import { Vector3 } from '../math/Vector3';
 import { Object3D } from '../core/Object3D';
 import { Line } from '../objects/Line';
@@ -5,12 +11,6 @@ import { Float32BufferAttribute } from '../core/BufferAttribute';
 import { BufferGeometry } from '../core/BufferGeometry';
 import { LineBasicMaterial } from '../materials/LineBasicMaterial';
 
-/**
- * @author alteredq / http://alteredqualia.com/
- * @author mrdoob / http://mrdoob.com/
- * @author WestLangley / http://github.com/WestLangley
- */
-
 function DirectionalLightHelper( light, size, color ) {
 
 	Object3D.call( this );

+ 5 - 5
src/helpers/FaceNormalsHelper.js

@@ -1,3 +1,8 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author WestLangley / http://github.com/WestLangley
+ */
+
 import { Matrix3 } from '../math/Matrix3';
 import { Vector3 } from '../math/Vector3';
 import { LineSegments } from '../objects/LineSegments';
@@ -5,11 +10,6 @@ import { LineBasicMaterial } from '../materials/LineBasicMaterial';
 import { Float32BufferAttribute } from '../core/BufferAttribute';
 import { BufferGeometry } from '../core/BufferGeometry';
 
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author WestLangley / http://github.com/WestLangley
-*/
-
 function FaceNormalsHelper( object, size, hex, linewidth ) {
 
 	// FaceNormalsHelper only supports THREE.Geometry

+ 4 - 4
src/helpers/GridHelper.js

@@ -1,3 +1,7 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
 import { LineSegments } from '../objects/LineSegments';
 import { VertexColors } from '../constants';
 import { LineBasicMaterial } from '../materials/LineBasicMaterial';
@@ -5,10 +9,6 @@ import { Float32BufferAttribute } from '../core/BufferAttribute';
 import { BufferGeometry } from '../core/BufferGeometry';
 import { Color } from '../math/Color';
 
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
 function GridHelper( size, divisions, color1, color2 ) {
 
 	size = size || 10;

+ 6 - 6
src/helpers/HemisphereLightHelper.js

@@ -1,3 +1,9 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ * @author mrdoob / http://mrdoob.com/
+ * @author Mugen87 / https://github.com/Mugen87
+ */
+
 import { Vector3 } from '../math/Vector3';
 import { Color } from '../math/Color';
 import { Object3D } from '../core/Object3D';
@@ -7,12 +13,6 @@ import { MeshBasicMaterial } from '../materials/MeshBasicMaterial';
 import { OctahedronBufferGeometry } from '../geometries/OctahedronGeometry';
 import { BufferAttribute } from '../core/BufferAttribute';
 
-/**
- * @author alteredq / http://alteredqualia.com/
- * @author mrdoob / http://mrdoob.com/
- * @author Mugen87 / https://github.com/Mugen87
- */
-
 function HemisphereLightHelper( light, size, color ) {
 
 	Object3D.call( this );

+ 60 - 0
src/helpers/PlaneHelper.js

@@ -0,0 +1,60 @@
+/**
+ * @author WestLangley / http://github.com/WestLangley
+ */
+ 
+import { Box3 } from '../math/Box3';
+import { Line } from '../objects/Line';
+import { LineBasicMaterial } from '../materials/LineBasicMaterial';
+import { Float32BufferAttribute } from '../core/BufferAttribute';
+import { BufferGeometry } from '../core/BufferGeometry';
+
+function PlaneHelper( plane, size, hex ) {
+
+	this.type = 'PlaneHelper';
+
+	this.plane = plane;
+
+	this.size = ( size === undefined ) ? 1 : size;
+
+	var color = ( hex !== undefined ) ? hex : 0xffff00;
+
+	var positions = [ 1, - 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 ];
+
+	var geometry = new BufferGeometry();
+	geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
+	geometry.computeBoundingSphere();
+
+	Line.call( this, geometry, new LineBasicMaterial( { color: color } ) );
+
+	//
+
+	var positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ];
+
+	var geometry2 = new BufferGeometry();
+	geometry2.addAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );
+	geometry2.computeBoundingSphere();
+
+	this.add( new THREE.Mesh( geometry2, new LineBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false } ) ) );
+
+	//
+
+	this.onBeforeRender();
+
+}
+
+PlaneHelper.prototype = Object.create( Line.prototype );
+PlaneHelper.prototype.constructor = PlaneHelper;
+
+PlaneHelper.prototype.onBeforeRender = function () {
+
+	var scale = - this.plane.constant;
+
+	if ( Math.abs( scale ) < 1e-8 ) scale = 1e-8; // sign does not matter
+
+	this.scale.set( 0.5 * this.size, 0.5 * this.size, scale );
+
+	this.lookAt( this.plane.normal );
+
+};
+
+export { PlaneHelper };

+ 4 - 4
src/helpers/PointLightHelper.js

@@ -1,12 +1,12 @@
-import { Mesh } from '../objects/Mesh';
-import { MeshBasicMaterial } from '../materials/MeshBasicMaterial';
-import { SphereBufferGeometry } from '../geometries/SphereGeometry';
-
 /**
  * @author alteredq / http://alteredqualia.com/
  * @author mrdoob / http://mrdoob.com/
  */
 
+import { Mesh } from '../objects/Mesh';
+import { MeshBasicMaterial } from '../materials/MeshBasicMaterial';
+import { SphereBufferGeometry } from '../geometries/SphereGeometry';
+
 function PointLightHelper( light, sphereSize, color ) {
 
 	this.light = light;

+ 6 - 6
src/helpers/PolarGridHelper.js

@@ -1,3 +1,9 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author Mugen87 / http://github.com/Mugen87
+ * @author Hectate / http://www.github.com/Hectate
+ */
+
 import { LineSegments } from '../objects/LineSegments';
 import { VertexColors } from '../constants';
 import { LineBasicMaterial } from '../materials/LineBasicMaterial';
@@ -5,12 +11,6 @@ import { Float32BufferAttribute } from '../core/BufferAttribute';
 import { BufferGeometry } from '../core/BufferGeometry';
 import { Color } from '../math/Color';
 
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author Mugen87 / http://github.com/Mugen87
- * @author Hectate / http://www.github.com/Hectate
- */
-
 function PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) {
 
 	radius = radius || 10;

+ 8 - 8
src/helpers/SkeletonHelper.js

@@ -1,3 +1,11 @@
+/**
+ * @author Sean Griffin / http://twitter.com/sgrif
+ * @author Michael Guerrero / http://realitymeltdown.com
+ * @author mrdoob / http://mrdoob.com/
+ * @author ikerr / http://verold.com
+ * @author Mugen87 / https://github.com/Mugen87
+ */
+
 import { LineSegments } from '../objects/LineSegments';
 import { Matrix4 } from '../math/Matrix4';
 import { VertexColors } from '../constants';
@@ -7,14 +15,6 @@ import { Vector3 } from '../math/Vector3';
 import { BufferGeometry } from '../core/BufferGeometry';
 import { Float32BufferAttribute } from '../core/BufferAttribute';
 
-/**
- * @author Sean Griffin / http://twitter.com/sgrif
- * @author Michael Guerrero / http://realitymeltdown.com
- * @author mrdoob / http://mrdoob.com/
- * @author ikerr / http://verold.com
- * @author Mugen87 / https://github.com/Mugen87
- */
-
 function getBoneList( object ) {
 
 	var boneList = [];

+ 6 - 6
src/helpers/SpotLightHelper.js

@@ -1,3 +1,9 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ * @author mrdoob / http://mrdoob.com/
+ * @author WestLangley / http://github.com/WestLangley
+ */
+
 import { Vector3 } from '../math/Vector3';
 import { Object3D } from '../core/Object3D';
 import { LineSegments } from '../objects/LineSegments';
@@ -5,12 +11,6 @@ import { LineBasicMaterial } from '../materials/LineBasicMaterial';
 import { Float32BufferAttribute } from '../core/BufferAttribute';
 import { BufferGeometry } from '../core/BufferGeometry';
 
-/**
- * @author alteredq / http://alteredqualia.com/
- * @author mrdoob / http://mrdoob.com/
- * @author WestLangley / http://github.com/WestLangley
-*/
-
 function SpotLightHelper( light, color ) {
 
 	Object3D.call( this );

+ 5 - 5
src/helpers/VertexNormalsHelper.js

@@ -1,3 +1,8 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author WestLangley / http://github.com/WestLangley
+ */
+
 import { Matrix3 } from '../math/Matrix3';
 import { Vector3 } from '../math/Vector3';
 import { LineSegments } from '../objects/LineSegments';
@@ -5,11 +10,6 @@ import { LineBasicMaterial } from '../materials/LineBasicMaterial';
 import { Float32BufferAttribute } from '../core/BufferAttribute';
 import { BufferGeometry } from '../core/BufferGeometry';
 
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author WestLangley / http://github.com/WestLangley
-*/
-
 function VertexNormalsHelper( object, size, hex, linewidth ) {
 
 	this.object = object;

+ 1 - 1
src/materials/MeshNormalMaterial.js

@@ -29,7 +29,7 @@ import { Vector2 } from '../math/Vector2';
 
 function MeshNormalMaterial( parameters ) {
 
-	Material.call( this, parameters );
+	Material.call( this );
 
 	this.type = 'MeshNormalMaterial';
 

+ 2 - 2
src/math/Matrix3.js

@@ -184,7 +184,7 @@ Object.assign( Matrix3.prototype, {
 
 		if ( matrix && matrix.isMatrix4 ) {
 
-			console.error( "THREE.Matrix3.getInverse no longer takes a Matrix4 argument." );
+			console.error( "THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument." );
 
 		}
 
@@ -203,7 +203,7 @@ Object.assign( Matrix3.prototype, {
 
 		if ( det === 0 ) {
 
-			var msg = "THREE.Matrix3.getInverse(): can't invert matrix, determinant is 0";
+			var msg = "THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0";
 
 			if ( throwOnDegenerate === true ) {
 

+ 14 - 4
src/math/Matrix4.js

@@ -154,7 +154,7 @@ Object.assign( Matrix4.prototype, {
 
 		if ( ! ( euler && euler.isEuler ) ) {
 
-			console.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
+			console.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
 
 		}
 
@@ -340,9 +340,19 @@ Object.assign( Matrix4.prototype, {
 
 			if ( x.lengthSq() === 0 ) {
 
-				// eye and target are in the same vertical
+				// up and z are parallel
 
-				z.z += 0.0001;
+				if ( Math.abs( up.z ) === 1 ) {
+
+					z.x += 0.0001;
+
+				} else {
+
+					z.z += 0.0001;
+
+				}
+
+				z.normalize();
 				x.crossVectors( up, z );
 
 			}
@@ -555,7 +565,7 @@ Object.assign( Matrix4.prototype, {
 
 		if ( det === 0 ) {
 
-			var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0";
+			var msg = "THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0";
 
 			if ( throwOnDegenerate === true ) {
 

+ 7 - 15
src/math/Plane.js

@@ -35,7 +35,7 @@ Object.assign( Plane.prototype, {
 	setFromNormalAndCoplanarPoint: function ( normal, point ) {
 
 		this.normal.copy( normal );
-		this.constant = - point.dot( this.normal );	// must be this.normal, not normal, as this.normal is normalized
+		this.constant = - point.dot( this.normal );
 
 		return this;
 
@@ -110,16 +110,9 @@ Object.assign( Plane.prototype, {
 
 	projectPoint: function ( point, optionalTarget ) {
 
-		return this.orthoPoint( point, optionalTarget ).sub( point ).negate();
-
-	},
-
-	orthoPoint: function ( point, optionalTarget ) {
-
-		var perpendicularMagnitude = this.distanceToPoint( point );
-
 		var result = optionalTarget || new Vector3();
-		return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude );
+
+		return result.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point );
 
 	},
 
@@ -189,6 +182,7 @@ Object.assign( Plane.prototype, {
 	coplanarPoint: function ( optionalTarget ) {
 
 		var result = optionalTarget || new Vector3();
+
 		return result.copy( this.normal ).multiplyScalar( - this.constant );
 
 	},
@@ -200,14 +194,12 @@ Object.assign( Plane.prototype, {
 
 		return function applyMatrix4( matrix, optionalNormalMatrix ) {
 
+			var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix );
+
 			var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix );
 
-			// transform normal based on theory here:
-			// http://www.songho.ca/opengl/gl_normaltransform.html
-			var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix );
 			var normal = this.normal.applyMatrix3( normalMatrix ).normalize();
 
-			// recalculate constant (like in setFromNormalAndCoplanarPoint)
 			this.constant = - referencePoint.dot( normal );
 
 			return this;
@@ -218,7 +210,7 @@ Object.assign( Plane.prototype, {
 
 	translate: function ( offset ) {
 
-		this.constant = this.constant - offset.dot( this.normal );
+		this.constant -= offset.dot( this.normal );
 
 		return this;
 

+ 4 - 4
src/math/Vector2.js

@@ -257,7 +257,7 @@ Object.assign( Vector2.prototype, {
 
 	clamp: function ( min, max ) {
 
-		// This function assumes min < max, if this assumption isn't true it will not operate correctly
+		// assumes min < max, componentwise
 
 		this.x = Math.max( min.x, Math.min( max.x, this.x ) );
 		this.y = Math.max( min.y, Math.min( max.y, this.y ) );
@@ -286,7 +286,7 @@ Object.assign( Vector2.prototype, {
 
 		var length = this.length();
 
-		return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length );
+		return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
 
 	},
 
@@ -361,7 +361,7 @@ Object.assign( Vector2.prototype, {
 
 	normalize: function () {
 
-		return this.divideScalar( this.length() );
+		return this.divideScalar( this.length() || 1 );
 
 	},
 
@@ -398,7 +398,7 @@ Object.assign( Vector2.prototype, {
 
 	setLength: function ( length ) {
 
-		return this.multiplyScalar( length / this.length() );
+		return this.normalize().multiplyScalar( length );
 
 	},
 

+ 17 - 11
src/math/Vector3.js

@@ -280,12 +280,13 @@ Object.assign( Vector3.prototype, {
 		var x = this.x, y = this.y, z = this.z;
 		var e = m.elements;
 
-		this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z + e[ 12 ];
-		this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z + e[ 13 ];
-		this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ];
-		var w =  e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ];
+		var w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
 
-		return this.divideScalar( w );
+		this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z + e[ 12 ] ) * w;
+		this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z + e[ 13 ] ) * w;
+		this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
+
+		return this;
 
 	},
 
@@ -391,7 +392,7 @@ Object.assign( Vector3.prototype, {
 
 	clamp: function ( min, max ) {
 
-		// This function assumes min < max, if this assumption isn't true it will not operate correctly
+		// assumes min < max, componentwise
 
 		this.x = Math.max( min.x, Math.min( max.x, this.x ) );
 		this.y = Math.max( min.y, Math.min( max.y, this.y ) );
@@ -421,7 +422,7 @@ Object.assign( Vector3.prototype, {
 
 		var length = this.length();
 
-		return this.multiplyScalar( Math.max( min, Math.min( max, length ) ) / length );
+		return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
 
 	},
 
@@ -503,13 +504,13 @@ Object.assign( Vector3.prototype, {
 
 	normalize: function () {
 
-		return this.divideScalar( this.length() );
+		return this.divideScalar( this.length() || 1 );
 
 	},
 
 	setLength: function ( length ) {
 
-		return this.multiplyScalar( length / this.length() );
+		return this.normalize().multiplyScalar( length );
 
 	},
 
@@ -652,7 +653,13 @@ Object.assign( Vector3.prototype, {
 
 	setFromMatrixPosition: function ( m ) {
 
-		return this.setFromMatrixColumn( m, 3 );
+		var e = m.elements;
+
+		this.x = e[ 12 ];
+		this.y = e[ 13 ];
+		this.z = e[ 14 ];
+
+		return this;
 
 	},
 
@@ -672,7 +679,6 @@ Object.assign( Vector3.prototype, {
 
 	setFromMatrixColumn: function ( m, index ) {
 
-
 		return this.fromArray( m.elements, index * 4 );
 
 	},

+ 19 - 5
src/math/Vector4.js

@@ -424,7 +424,7 @@ Object.assign( Vector4.prototype, {
 
 	clamp: function ( min, max ) {
 
-		// This function assumes min < max, if this assumption isn't true it will not operate correctly
+		// assumes min < max, componentwise
 
 		this.x = Math.max( min.x, Math.min( max.x, this.x ) );
 		this.y = Math.max( min.y, Math.min( max.y, this.y ) );
@@ -437,11 +437,17 @@ Object.assign( Vector4.prototype, {
 
 	clampScalar: function () {
 
-		var min = new Vector4();
-		var max = new Vector4();
+		var min, max;
 
 		return function clampScalar( minVal, maxVal ) {
 
+			if ( min === undefined ) {
+
+				min = new Vector4();
+				max = new Vector4();
+
+			}
+
 			min.set( minVal, minVal, minVal, minVal );
 			max.set( maxVal, maxVal, maxVal, maxVal );
 
@@ -451,6 +457,14 @@ Object.assign( Vector4.prototype, {
 
 	}(),
 
+	clampLength: function ( min, max ) {
+
+		var length = this.length();
+
+		return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
+
+	},
+
 	floor: function () {
 
 		this.x = Math.floor( this.x );
@@ -532,13 +546,13 @@ Object.assign( Vector4.prototype, {
 
 	normalize: function () {
 
-		return this.divideScalar( this.length() );
+		return this.divideScalar( this.length() || 1 );
 
 	},
 
 	setLength: function ( length ) {
 
-		return this.multiplyScalar( length / this.length() );
+		return this.normalize().multiplyScalar( length );
 
 	},
 

+ 3 - 4
src/objects/Mesh.js

@@ -147,10 +147,9 @@ Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		}
 
-		function checkIntersection( object, raycaster, ray, pA, pB, pC, point ) {
+		function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) {
 
 			var intersect;
-			var material = object.material;
 
 			if ( material.side === BackSide ) {
 
@@ -185,7 +184,7 @@ Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), {
 			vB.fromBufferAttribute( position, b );
 			vC.fromBufferAttribute( position, c );
 
-			var intersection = checkIntersection( object, raycaster, ray, vA, vB, vC, intersectionPoint );
+			var intersection = checkIntersection( object, object.material, raycaster, ray, vA, vB, vC, intersectionPoint );
 
 			if ( intersection ) {
 
@@ -348,7 +347,7 @@ Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 					}
 
-					intersection = checkIntersection( this, raycaster, ray, fvA, fvB, fvC, intersectionPoint );
+					intersection = checkIntersection( this, faceMaterial, raycaster, ray, fvA, fvB, fvC, intersectionPoint );
 
 					if ( intersection ) {
 

+ 98 - 141
src/renderers/WebGLRenderer.js

@@ -1,4 +1,4 @@
-import { REVISION, MaxEquation, MinEquation, RGB_ETC1_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT5_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT1_Format, RGB_S3TC_DXT1_Format, SrcAlphaSaturateFactor, OneMinusDstColorFactor, DstColorFactor, OneMinusDstAlphaFactor, DstAlphaFactor, OneMinusSrcAlphaFactor, SrcAlphaFactor, OneMinusSrcColorFactor, SrcColorFactor, OneFactor, ZeroFactor, ReverseSubtractEquation, SubtractEquation, AddEquation, DepthFormat, DepthStencilFormat, LuminanceAlphaFormat, LuminanceFormat, RGBAFormat, RGBFormat, AlphaFormat, HalfFloatType, FloatType, UnsignedIntType, IntType, UnsignedShortType, ShortType, ByteType, UnsignedInt248Type, UnsignedShort565Type, UnsignedShort5551Type, UnsignedShort4444Type, UnsignedByteType, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestFilter, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping, FrontFaceDirectionCW, NoBlending, BackSide, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, NoColors, FlatShading, LinearToneMapping } from '../constants';
+import { REVISION, MaxEquation, MinEquation, RGB_ETC1_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT5_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT1_Format, RGB_S3TC_DXT1_Format, SrcAlphaSaturateFactor, OneMinusDstColorFactor, DstColorFactor, OneMinusDstAlphaFactor, DstAlphaFactor, OneMinusSrcAlphaFactor, SrcAlphaFactor, OneMinusSrcColorFactor, SrcColorFactor, OneFactor, ZeroFactor, ReverseSubtractEquation, SubtractEquation, AddEquation, DepthFormat, DepthStencilFormat, LuminanceAlphaFormat, LuminanceFormat, RGBAFormat, RGBFormat, AlphaFormat, HalfFloatType, FloatType, UnsignedIntType, IntType, UnsignedShortType, ShortType, ByteType, UnsignedInt248Type, UnsignedShort565Type, UnsignedShort5551Type, UnsignedShort4444Type, UnsignedByteType, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestFilter, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping, FrontFaceDirectionCW, NoBlending, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, NoColors, FlatShading, LinearToneMapping } from '../constants';
 import { _Math } from '../math/Math';
 import { Matrix4 } from '../math/Matrix4';
 import { DataTexture } from '../textures/DataTexture';
@@ -9,14 +9,8 @@ import { ShaderLib } from './shaders/ShaderLib';
 import { LensFlarePlugin } from './webgl/plugins/LensFlarePlugin';
 import { SpritePlugin } from './webgl/plugins/SpritePlugin';
 import { WebGLShadowMap } from './webgl/WebGLShadowMap';
-import { ShaderMaterial } from '../materials/ShaderMaterial';
-import { Mesh } from '../objects/Mesh';
-import { BoxBufferGeometry } from '../geometries/BoxGeometry';
-import { PlaneBufferGeometry } from '../geometries/PlaneGeometry';
-import { MeshBasicMaterial } from '../materials/MeshBasicMaterial';
-import { PerspectiveCamera } from '../cameras/PerspectiveCamera';
-import { OrthographicCamera } from '../cameras/OrthographicCamera';
 import { WebGLAttributes } from './webgl/WebGLAttributes';
+import { WebGLBackground } from './webgl/WebGLBackground';
 import { WebGLRenderLists } from './webgl/WebGLRenderLists';
 import { WebGLIndexedBufferRenderer } from './webgl/WebGLIndexedBufferRenderer';
 import { WebGLBufferRenderer } from './webgl/WebGLBufferRenderer';
@@ -28,6 +22,7 @@ import { WebGLTextures } from './webgl/WebGLTextures';
 import { WebGLProperties } from './webgl/WebGLProperties';
 import { WebGLState } from './webgl/WebGLState';
 import { WebGLCapabilities } from './webgl/WebGLCapabilities';
+import { WebVRManager } from './webvr/WebVRManager';
 import { BufferGeometry } from '../core/BufferGeometry';
 import { WebGLExtensions } from './webgl/WebGLExtensions';
 import { Vector3 } from '../math/Vector3';
@@ -35,7 +30,6 @@ import { Vector3 } from '../math/Vector3';
 import { WebGLClipping } from './webgl/WebGLClipping';
 import { Frustum } from '../math/Frustum';
 import { Vector4 } from '../math/Vector4';
-import { Color } from '../math/Color';
 
 /**
  * @author supereggbert / http://www.paulbrunt.co.uk/
@@ -123,7 +117,9 @@ function WebGLRenderer( parameters ) {
 		_currentFramebuffer = null,
 		_currentMaterialId = - 1,
 		_currentGeometryProgram = '',
+
 		_currentCamera = null,
+		_currentArrayCamera = null,
 
 		_currentScissor = new Vector4(),
 		_currentScissorTest = null,
@@ -136,9 +132,6 @@ function WebGLRenderer( parameters ) {
 
 		//
 
-		_clearColor = new Color( 0x000000 ),
-		_clearAlpha = 0,
-
 		_width = _canvas.width,
 		_height = _canvas.height,
 
@@ -296,6 +289,9 @@ function WebGLRenderer( parameters ) {
 	var lightCache = new WebGLLights();
 	var renderLists = new WebGLRenderLists();
 
+	var background = new WebGLBackground( this, state, objects, _premultipliedAlpha );
+	var vr = new WebVRManager( this );
+
 	this.info.programs = programCache.programs;
 
 	var bufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender );
@@ -303,11 +299,6 @@ function WebGLRenderer( parameters ) {
 
 	//
 
-	var backgroundPlaneCamera, backgroundPlaneMesh;
-	var backgroundBoxCamera, backgroundBoxMesh;
-
-	//
-
 	function getTargetPixelRatio() {
 
 		return _currentRenderTarget === null ? _pixelRatio : 1;
@@ -321,8 +312,6 @@ function WebGLRenderer( parameters ) {
 		state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );
 		state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );
 
-		state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha );
-
 	}
 
 	function resetGLState() {
@@ -345,6 +334,7 @@ function WebGLRenderer( parameters ) {
 	this.properties = properties;
 	this.renderLists = renderLists;
 	this.state = state;
+	this.vr = vr;
 
 	// shadow map
 
@@ -418,6 +408,15 @@ function WebGLRenderer( parameters ) {
 
 	this.setSize = function ( width, height, updateStyle ) {
 
+		var device = vr.getDevice();
+
+		if ( device && device.isPresenting ) {
+
+			console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
+			return;
+
+		}
+
 		_width = width;
 		_height = height;
 
@@ -435,57 +434,55 @@ function WebGLRenderer( parameters ) {
 
 	};
 
-	this.setViewport = function ( x, y, width, height ) {
+	this.getDrawingBufferSize = function () {
 
-		_viewport.set( x, _height - y - height, width, height )
-		state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );
+		return {
+			width: _width * _pixelRatio,
+			height: _height * _pixelRatio
+		};
 
 	};
 
-	this.setScissor = function ( x, y, width, height ) {
+	this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
 
-		_scissor.set( x, _height - y - height, width, height )
-		state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );
+		_width = width;
+		_height = height;
 
-	};
+		_pixelRatio = pixelRatio;
 
-	this.setScissorTest = function ( boolean ) {
+		_canvas.width = width * pixelRatio;
+		_canvas.height = height * pixelRatio;
 
-		state.setScissorTest( _scissorTest = boolean );
+		this.setViewport( 0, 0, width, height );
 
 	};
 
-	// Clearing
-
-	this.getClearColor = function () {
+	this.setViewport = function ( x, y, width, height ) {
 
-		return _clearColor;
+		_viewport.set( x, _height - y - height, width, height )
+		state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );
 
 	};
 
-	this.setClearColor = function ( color, alpha ) {
-
-		_clearColor.set( color );
-
-		_clearAlpha = alpha !== undefined ? alpha : 1;
+	this.setScissor = function ( x, y, width, height ) {
 
-		state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha );
+		_scissor.set( x, _height - y - height, width, height )
+		state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );
 
 	};
 
-	this.getClearAlpha = function () {
+	this.setScissorTest = function ( boolean ) {
 
-		return _clearAlpha;
+		state.setScissorTest( _scissorTest = boolean );
 
 	};
 
-	this.setClearAlpha = function ( alpha ) {
-
-		_clearAlpha = alpha;
+	// Clearing
 
-		state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha );
-
-	};
+	this.getClearColor = background.getClearColor;
+	this.setClearColor = background.setClearColor;
+	this.getClearAlpha = background.getClearAlpha;
+	this.setClearAlpha = background.setClearAlpha;
 
 	this.clear = function ( color, depth, stencil ) {
 
@@ -1082,6 +1079,20 @@ function WebGLRenderer( parameters ) {
 
 	// Rendering
 
+	this.animate = function ( callback ) {
+
+		function onFrame() {
+
+			callback();
+
+			( vr.getDevice() || window ).requestAnimationFrame( onFrame );
+
+		}
+
+		( vr.getDevice() || window ).requestAnimationFrame( onFrame );
+
+	};
+
 	this.render = function ( scene, camera, renderTarget, forceClear ) {
 
 		if ( ! ( camera && camera.isCamera ) ) {
@@ -1103,10 +1114,14 @@ function WebGLRenderer( parameters ) {
 
 		// update camera matrices and frustum
 
-		camera.onBeforeRender( _this );
-
 		if ( camera.parent === null ) camera.updateMatrixWorld();
 
+		if ( vr.enabled ) {
+
+			camera = vr.getCamera( camera );
+
+		}
+
 		_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
 		_frustum.setFromMatrix( _projScreenMatrix );
 
@@ -1160,81 +1175,9 @@ function WebGLRenderer( parameters ) {
 
 		//
 
-		var background = scene.background;
-
-		if ( background === null ) {
-
-			state.buffers.color.setClear( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha, _premultipliedAlpha );
-
-		} else if ( background && background.isColor ) {
-
-			state.buffers.color.setClear( background.r, background.g, background.b, 1, _premultipliedAlpha );
-			forceClear = true;
-
-		}
-
-		if ( this.autoClear || forceClear ) {
-
-			this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil );
-
-		}
-
-		if ( background && background.isCubeTexture ) {
-
-			if ( backgroundBoxCamera === undefined ) {
+		background.render( scene, camera, forceClear );
 
-				backgroundBoxCamera = new PerspectiveCamera();
-
-				backgroundBoxMesh = new Mesh(
-					new BoxBufferGeometry( 5, 5, 5 ),
-					new ShaderMaterial( {
-						uniforms: ShaderLib.cube.uniforms,
-						vertexShader: ShaderLib.cube.vertexShader,
-						fragmentShader: ShaderLib.cube.fragmentShader,
-						side: BackSide,
-						depthTest: false,
-						depthWrite: false,
-						fog: false
-					} )
-				);
-
-			}
-
-			backgroundBoxCamera.projectionMatrix.copy( camera.projectionMatrix );
-
-			backgroundBoxCamera.matrixWorld.extractRotation( camera.matrixWorld );
-			backgroundBoxCamera.matrixWorldInverse.getInverse( backgroundBoxCamera.matrixWorld );
-
-
-			backgroundBoxMesh.material.uniforms[ "tCube" ].value = background;
-			backgroundBoxMesh.modelViewMatrix.multiplyMatrices( backgroundBoxCamera.matrixWorldInverse, backgroundBoxMesh.matrixWorld );
-
-			objects.update( backgroundBoxMesh );
-
-			_this.renderBufferDirect( backgroundBoxCamera, null, backgroundBoxMesh.geometry, backgroundBoxMesh.material, backgroundBoxMesh, null );
-
-		} else if ( background && background.isTexture ) {
-
-			if ( backgroundPlaneCamera === undefined ) {
-
-				backgroundPlaneCamera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
-
-				backgroundPlaneMesh = new Mesh(
-					new PlaneBufferGeometry( 2, 2 ),
-					new MeshBasicMaterial( { depthTest: false, depthWrite: false, fog: false } )
-				);
-
-			}
-
-			backgroundPlaneMesh.material.map = background;
-
-			objects.update( backgroundPlaneMesh );
-
-			_this.renderBufferDirect( backgroundPlaneCamera, null, backgroundPlaneMesh.geometry, backgroundPlaneMesh.material, backgroundPlaneMesh, null );
-
-		}
-
-		//
+		// render scene
 
 		var opaqueObjects = currentRenderList.opaque;
 		var transparentObjects = currentRenderList.transparent;
@@ -1283,7 +1226,11 @@ function WebGLRenderer( parameters ) {
 
 		}
 
-		camera.onAfterRender( _this );
+		if ( vr.enabled ) {
+
+			vr.submitFrame();
+
+		}
 
 		// _gl.finish();
 
@@ -1449,38 +1396,43 @@ function WebGLRenderer( parameters ) {
 			var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial;
 			var group = renderItem.group;
 
-			object.onBeforeRender( _this, scene, camera, geometry, material, group );
-
 			if ( camera.isArrayCamera ) {
 
+				_currentArrayCamera = camera;
+
 				var cameras = camera.cameras;
 
 				for ( var j = 0, jl = cameras.length; j < jl; j ++ ) {
 
 					var camera2 = cameras[ j ];
-					var bounds = camera2.bounds;
 
-					var x = bounds.x * _width;
-					var y = bounds.y * _height;
-					var width = bounds.z * _width;
-					var height = bounds.w * _height;
+					if ( object.layers.test( camera2.layers ) ) {
+
+						var bounds = camera2.bounds;
 
-					_this.setViewport( x, y, width, height );
-					_this.setScissor( x, y, width, height );
-					_this.setScissorTest( true );
+						var x = bounds.x * _width;
+						var y = bounds.y * _height;
+						var width = bounds.z * _width;
+						var height = bounds.w * _height;
 
-					renderObject( object, scene, camera2, geometry, material, group );
+						_this.setViewport( x, y, width, height );
+						_this.setScissor( x, y, width, height );
+						_this.setScissorTest( true );
+
+						renderObject( object, scene, camera2, geometry, material, group );
+
+					}
 
 				}
 
 			} else {
 
+				_currentArrayCamera = null;
+
 				renderObject( object, scene, camera, geometry, material, group );
 
 			}
 
-			object.onAfterRender( _this, scene, camera, geometry, material, group );
-
 		}
 
 	}
@@ -1490,6 +1442,8 @@ function WebGLRenderer( parameters ) {
 		object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
 		object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
 
+		object.onBeforeRender( _this, scene, camera, geometry, material, group );
+
 		if ( object.isImmediateRenderObject ) {
 
 			state.setMaterial( material );
@@ -1506,6 +1460,8 @@ function WebGLRenderer( parameters ) {
 
 		}
 
+		object.onAfterRender( _this, scene, camera, geometry, material, group );
+
 	}
 
 	function initMaterial( material, fog, object ) {
@@ -1750,10 +1706,11 @@ function WebGLRenderer( parameters ) {
 
 			}
 
+			// Avoid unneeded uniform updates per ArrayCamera's sub-camera
 
-			if ( camera !== _currentCamera ) {
+			if ( _currentCamera !== ( _currentArrayCamera || camera ) ) {
 
-				_currentCamera = camera;
+				_currentCamera = ( _currentArrayCamera || camera );
 
 				// lighting uniforms depend on the camera so enforce an update
 				// now, in case this material supports lights - or later, when
@@ -1794,9 +1751,6 @@ function WebGLRenderer( parameters ) {
 
 			}
 
-			p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
-			p_uniforms.setValue( _gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint );
-
 		}
 
 		// skinning uniforms must be set even if material didn't change
@@ -1856,6 +1810,9 @@ function WebGLRenderer( parameters ) {
 
 		if ( refreshMaterial ) {
 
+			p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
+			p_uniforms.setValue( _gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint );
+
 			if ( material.lights ) {
 
 				// the current material requires lighting info

+ 3 - 3
src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl

@@ -1,7 +1,7 @@
+vec3 transformedNormal = normalMatrix * objectNormal;
+
 #ifdef FLIP_SIDED
 
-	objectNormal = -objectNormal;
+	transformedNormal = - transformedNormal;
 
 #endif
-
-vec3 transformedNormal = normalMatrix * objectNormal;

+ 1 - 1
src/renderers/shaders/ShaderChunk/displacementmap_vertex.glsl

@@ -1,5 +1,5 @@
 #ifdef USE_DISPLACEMENTMAP
 
-	transformed += normal * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );
+	transformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );
 
 #endif

+ 1 - 9
src/renderers/shaders/ShaderChunk/project_vertex.glsl

@@ -1,11 +1,3 @@
-#ifdef USE_SKINNING
-
-	vec4 mvPosition = modelViewMatrix * skinned;
-
-#else
-
-	vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );
-
-#endif
+vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );
 
 gl_Position = projectionMatrix * mvPosition;

+ 6 - 4
src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl

@@ -59,6 +59,8 @@
 
 	float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {
 
+		float shadow = 1.0;
+
 		shadowCoord.xyz /= shadowCoord.w;
 		shadowCoord.z += shadowBias;
 
@@ -83,7 +85,7 @@
 			float dx1 = + texelSize.x * shadowRadius;
 			float dy1 = + texelSize.y * shadowRadius;
 
-			return (
+			shadow = (
 				texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +
 				texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +
 				texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +
@@ -104,7 +106,7 @@
 			float dx1 = + texelSize.x * shadowRadius;
 			float dy1 = + texelSize.y * shadowRadius;
 
-			return (
+			shadow = (
 				texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +
 				texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +
 				texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +
@@ -118,13 +120,13 @@
 
 		#else // no percentage-closer filtering:
 
-			return texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );
+			shadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );
 
 		#endif
 
 		}
 
-		return 1.0;
+		return shadow;
 
 	}
 

+ 2 - 1
src/renderers/shaders/ShaderChunk/skinning_vertex.glsl

@@ -7,6 +7,7 @@
 	skinned += boneMatY * skinVertex * skinWeight.y;
 	skinned += boneMatZ * skinVertex * skinWeight.z;
 	skinned += boneMatW * skinVertex * skinWeight.w;
-	skinned  = bindMatrixInverse * skinned;
+
+	transformed = ( bindMatrixInverse * skinned ).xyz;
 
 #endif

+ 1 - 9
src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl

@@ -1,13 +1,5 @@
 #if defined( USE_ENVMAP ) || defined( PHONG ) || defined( PHYSICAL ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )
 
-	#ifdef USE_SKINNING
-
-		vec4 worldPosition = modelMatrix * skinned;
-
-	#else
-
-		vec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );
-
-	#endif
+	vec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );
 
 #endif

+ 6 - 3
src/renderers/shaders/ShaderLib.js

@@ -190,9 +190,12 @@ var ShaderLib = {
 
 	distanceRGBA: {
 
-		uniforms: {
-			lightPos: { value: new Vector3() }
-		},
+		uniforms: UniformsUtils.merge( [
+			UniformsLib.common,
+			{
+				lightPos: { value: new Vector3() }
+			}
+		] ),
 
 		vertexShader: ShaderChunk.distanceRGBA_vert,
 		fragmentShader: ShaderChunk.distanceRGBA_frag

+ 9 - 1
src/renderers/shaders/ShaderLib/depth_vert.glsl

@@ -12,10 +12,18 @@ void main() {
 
 	#include <skinbase_vertex>
 
+	#ifdef USE_DISPLACEMENTMAP
+
+		#include <beginnormal_vertex>
+		#include <morphnormal_vertex>
+		#include <skinnormal_vertex>
+
+	#endif
+
 	#include <begin_vertex>
-	#include <displacementmap_vertex>
 	#include <morphtarget_vertex>
 	#include <skinning_vertex>
+	#include <displacementmap_vertex>
 	#include <project_vertex>
 	#include <logdepthbuf_vertex>
 	#include <clipping_planes_vertex>

+ 9 - 0
src/renderers/shaders/ShaderLib/distanceRGBA_frag.glsl

@@ -3,12 +3,21 @@ varying vec4 vWorldPosition;
 
 #include <common>
 #include <packing>
+#include <uv_pars_fragment>
+#include <map_pars_fragment>
+#include <alphamap_pars_fragment>
 #include <clipping_planes_pars_fragment>
 
 void main () {
 
 	#include <clipping_planes_fragment>
 
+	vec4 diffuseColor = vec4( 1.0 );
+
+	#include <map_fragment>
+	#include <alphamap_fragment>
+	#include <alphatest_fragment>
+
 	gl_FragColor = packDepthToRGBA( length( vWorldPosition.xyz - lightPos.xyz ) / 1000.0 );
 
 }

+ 3 - 0
src/renderers/shaders/ShaderLib/distanceRGBA_vert.glsl

@@ -1,12 +1,15 @@
 varying vec4 vWorldPosition;
 
 #include <common>
+#include <uv_pars_vertex>
 #include <morphtarget_pars_vertex>
 #include <skinning_pars_vertex>
 #include <clipping_planes_pars_vertex>
 
 void main() {
 
+	#include <uv_vertex>
+
 	#include <skinbase_vertex>
 	#include <begin_vertex>
 	#include <morphtarget_vertex>

+ 1 - 1
src/renderers/shaders/ShaderLib/meshphong_vert.glsl

@@ -40,9 +40,9 @@ void main() {
 #endif
 
 	#include <begin_vertex>
-	#include <displacementmap_vertex>
 	#include <morphtarget_vertex>
 	#include <skinning_vertex>
+	#include <displacementmap_vertex>
 	#include <project_vertex>
 	#include <logdepthbuf_vertex>
 	#include <clipping_planes_vertex>

+ 1 - 1
src/renderers/shaders/ShaderLib/meshphysical_vert.glsl

@@ -39,9 +39,9 @@ void main() {
 #endif
 
 	#include <begin_vertex>
-	#include <displacementmap_vertex>
 	#include <morphtarget_vertex>
 	#include <skinning_vertex>
+	#include <displacementmap_vertex>
 	#include <project_vertex>
 	#include <logdepthbuf_vertex>
 	#include <clipping_planes_vertex>

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