2
0
Эх сурвалжийг харах

Merge branch 'dev' of https://github.com/mrdoob/three.js into dev

Luis Blanco 6 жил өмнө
parent
commit
0c95418a3e
100 өөрчлөгдсөн 2039 нэмэгдсэн , 785 устгасан
  1. 1 1
      .github/ISSUE_TEMPLATE.md
  2. 0 1
      .npmignore
  3. 4 4
      build/three.js
  4. 360 358
      build/three.min.js
  5. 2 2
      build/three.module.js
  6. 5 0
      docs/api/en/animation/AnimationClip.html
  7. 5 0
      docs/api/en/animation/KeyframeTrack.html
  8. 1 1
      docs/api/en/audio/Audio.html
  9. 1 1
      docs/api/en/audio/AudioAnalyser.html
  10. 4 4
      docs/api/en/audio/AudioListener.html
  11. 2 2
      docs/api/en/audio/PositionalAudio.html
  12. 1 0
      docs/api/en/constants/Renderer.html
  13. 1 1
      docs/api/en/core/Object3D.html
  14. 4 1
      docs/api/en/extras/core/ShapePath.html
  15. 73 0
      docs/api/en/helpers/PositionalAudioHelper.html
  16. 7 0
      docs/api/en/materials/Material.html
  17. 2 2
      docs/api/en/objects/SkinnedMesh.html
  18. 63 20
      docs/api/en/renderers/WebGLRenderer.html
  19. 10 2
      docs/api/en/textures/DataTexture3D.html
  20. 3 0
      docs/api/zh/animation/AnimationClip.html
  21. 6 0
      docs/api/zh/animation/AnimationUtils.html
  22. 3 0
      docs/api/zh/animation/KeyframeTrack.html
  23. 1 1
      docs/api/zh/audio/Audio.html
  24. 1 1
      docs/api/zh/audio/AudioAnalyser.html
  25. 4 4
      docs/api/zh/audio/AudioListener.html
  26. 2 2
      docs/api/zh/audio/PositionalAudio.html
  27. 1 1
      docs/api/zh/core/Object3D.html
  28. 73 0
      docs/api/zh/helpers/PositionalAudioHelper.html
  29. 4 0
      docs/api/zh/materials/Material.html
  30. 1 1
      docs/api/zh/textures/Texture.html
  31. 1 0
      docs/examples/exporters/GLTFExporter.html
  32. 15 0
      docs/index.html
  33. 4 0
      docs/list.js
  34. 126 0
      docs/manual/en/introduction/How-to-dispose-of-objects.html
  35. 4 0
      docs/manual/en/introduction/Useful-links.html
  36. 6 6
      docs/manual/zh/introduction/Creating-a-scene.html
  37. 125 0
      docs/manual/zh/introduction/How-to-dispose-of-objects.html
  38. 2 2
      docs/manual/zh/introduction/How-to-run-things-locally.html
  39. 2 4
      editor/index.html
  40. 12 0
      editor/js/Editor.js
  41. 22 9
      editor/js/Loader.js
  42. 65 5
      editor/js/Sidebar.Animation.js
  43. 23 0
      editor/js/Viewport.js
  44. 5 5
      editor/js/libs/ui.js
  45. 1 0
      examples/files.js
  46. 8 2
      examples/js/GPUComputationRenderer.js
  47. 39 14
      examples/js/Ocean.js
  48. 11 2
      examples/js/cameras/CinematicCamera.js
  49. 87 45
      examples/js/controls/FirstPersonControls.js
  50. 24 5
      examples/js/controls/OrbitControls.js
  51. 0 14
      examples/js/controls/TransformControls.js
  52. 11 3
      examples/js/crossfade/scenes.js
  53. 4 2
      examples/js/crossfade/transition.js
  54. 13 2
      examples/js/effects/AnaglyphEffect.js
  55. 26 6
      examples/js/effects/OutlineEffect.js
  56. 9 2
      examples/js/effects/ParallaxBarrierEffect.js
  57. 2 1
      examples/js/effects/StereoEffect.js
  58. 10 5
      examples/js/exporters/ColladaExporter.js
  59. 280 25
      examples/js/exporters/GLTFExporter.js
  60. 7 3
      examples/js/loaders/AssimpJSONLoader.js
  61. 1 1
      examples/js/loaders/ColladaLoader.js
  62. 14 4
      examples/js/loaders/EquirectangularToCubeGenerator.js
  63. 2 1
      examples/js/loaders/FBXLoader.js
  64. 26 13
      examples/js/loaders/GLTFLoader.js
  65. 57 67
      examples/js/loaders/LDrawLoader.js
  66. 19 4
      examples/js/loaders/SVGLoader.js
  67. 4 2
      examples/js/loaders/TGALoader.js
  68. 23 19
      examples/js/loaders/deprecated/LegacyGLTFLoader.js
  69. 1 0
      examples/js/nodes/Nodes.js
  70. 2 0
      examples/js/nodes/THREE.Nodes.js
  71. 2 2
      examples/js/nodes/accessors/CameraNode.js
  72. 1 1
      examples/js/nodes/accessors/NormalNode.js
  73. 1 1
      examples/js/nodes/accessors/PositionNode.js
  74. 1 1
      examples/js/nodes/core/FunctionNode.js
  75. 12 4
      examples/js/nodes/core/InputNode.js
  76. 28 18
      examples/js/nodes/core/NodeBuilder.js
  77. 23 9
      examples/js/nodes/core/TempNode.js
  78. 51 0
      examples/js/nodes/inputs/BoolNode.js
  79. 6 2
      examples/js/nodes/inputs/RTTNode.js
  80. 1 1
      examples/js/nodes/inputs/ScreenNode.js
  81. 1 0
      examples/js/nodes/materials/PhongNodeMaterial.js
  82. 1 0
      examples/js/nodes/materials/SpriteNodeMaterial.js
  83. 1 0
      examples/js/nodes/materials/StandardNodeMaterial.js
  84. 21 2
      examples/js/nodes/materials/nodes/PhongNode.js
  85. 23 6
      examples/js/nodes/materials/nodes/SpriteNode.js
  86. 22 3
      examples/js/nodes/materials/nodes/StandardNode.js
  87. 35 16
      examples/js/nodes/math/CondNode.js
  88. 4 2
      examples/js/nodes/postprocessing/NodePostProcessing.js
  89. 2 2
      examples/js/nodes/utils/ColorSpaceNode.js
  90. 3 3
      examples/js/nodes/utils/TimerNode.js
  91. 1 1
      examples/js/nodes/utils/VelocityNode.js
  92. 12 6
      examples/js/objects/Fire.js
  93. 1 1
      examples/js/objects/Lensflare.js
  94. 5 2
      examples/js/objects/Reflector.js
  95. 5 2
      examples/js/objects/Refractor.js
  96. 3 1
      examples/js/objects/Water.js
  97. 2 1
      examples/js/pmrem/PMREMCubeUVPacker.js
  98. 3 1
      examples/js/pmrem/PMREMGenerator.js
  99. 14 6
      examples/js/postprocessing/AdaptiveToneMappingPass.js
  100. 16 8
      examples/js/postprocessing/AfterimagePass.js

+ 1 - 1
.github/ISSUE_TEMPLATE.md

@@ -19,7 +19,7 @@ Please also include a live example if possible. You can start from these templat
 ##### Three.js version
 ##### Three.js version
 
 
 - [ ] Dev
 - [ ] Dev
-- [ ] r100
+- [ ] r101
 - [ ] ...
 - [ ] ...
 
 
 ##### Browser
 ##### Browser

+ 0 - 1
.npmignore

@@ -1,6 +1,5 @@
 examples/*
 examples/*
 !examples/js/
 !examples/js/
-src/
 test/
 test/
 utils/
 utils/
 docs/
 docs/

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 4 - 4
build/three.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 360 - 358
build/three.min.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 2 - 2
build/three.module.js


+ 5 - 0
docs/api/en/animation/AnimationClip.html

@@ -66,6 +66,11 @@
 		<h2>Methods</h2>
 		<h2>Methods</h2>
 
 
 
 
+		<h3>[method:AnimationClip clone]()</h3>
+		<p>
+			Returns a copy of this clip.
+		</p>
+
 		<h3>[method:this optimize]()</h3>
 		<h3>[method:this optimize]()</h3>
 		<p>
 		<p>
 			Optimizes each track by removing equivalent sequential keys (which are common in morph target
 			Optimizes each track by removing equivalent sequential keys (which are common in morph target

+ 5 - 0
docs/api/en/animation/KeyframeTrack.html

@@ -160,6 +160,11 @@
 		<h2>Methods</h2>
 		<h2>Methods</h2>
 
 
 
 
+		<h3>[method:KeyframeTrack clone]()</h3>
+		<p>
+			Returns a copy of this track.
+		</p>
+
 		<h3>[method:null createInterpolant]()</h3>
 		<h3>[method:null createInterpolant]()</h3>
 		<p>
 		<p>
 			Creates a [page:LinearInterpolant LinearInterpolant], [page:CubicInterpolant CubicInterpolant]
 			Creates a [page:LinearInterpolant LinearInterpolant], [page:CubicInterpolant CubicInterpolant]

+ 1 - 1
docs/api/en/audio/Audio.html

@@ -22,7 +22,7 @@
 		<h2>Example</h2>
 		<h2>Example</h2>
 
 
 		<p>
 		<p>
-			[example:webaudio_sandbox webaudio / sandbox ]</br>
+			[example:webaudio_sandbox webaudio / sandbox ]<br />
 			[example:webaudio_visualizer webaudio / visualizer ]
 			[example:webaudio_visualizer webaudio / visualizer ]
 		</p>
 		</p>
 
 

+ 1 - 1
docs/api/en/audio/AudioAnalyser.html

@@ -22,7 +22,7 @@
 		<h2>Example</h2>
 		<h2>Example</h2>
 
 
 		<p>
 		<p>
-			[example:webaudio_sandbox webaudio / sandbox ]</br>
+			[example:webaudio_sandbox webaudio / sandbox ]<br />
 			[example:webaudio_visualizer webaudio / visualizer ]
 			[example:webaudio_visualizer webaudio / visualizer ]
 		</p>
 		</p>
 
 

+ 4 - 4
docs/api/en/audio/AudioListener.html

@@ -13,8 +13,8 @@
 		<h1>[name]</h1>
 		<h1>[name]</h1>
 
 
 		<p class="desc">
 		<p class="desc">
-			The [name] represents a virtual [link:https://developer.mozilla.org/de/docs/Web/API/AudioListener listener] of the all positional and non-positional audio effects in the scene.</br>
-			A three.js application usually creates a single instance of [name]. It is a mandatory construtor parameter for audios entities like [page:Audio Audio] and [page:PositionalAudio PositionalAudio].</br>
+			The [name] represents a virtual [link:https://developer.mozilla.org/de/docs/Web/API/AudioListener listener] of the all positional and non-positional audio effects in the scene.<br />
+			A three.js application usually creates a single instance of [name]. It is a mandatory construtor parameter for audios entities like [page:Audio Audio] and [page:PositionalAudio PositionalAudio].<br />
 			In most cases, the listener object is a child of the camera. So the 3D transformation of the camera represents the 3D transformation of the listener.
 			In most cases, the listener object is a child of the camera. So the 3D transformation of the camera represents the 3D transformation of the listener.
 		</p>
 		</p>
 
 
@@ -22,8 +22,8 @@
 		<h2>Example</h2>
 		<h2>Example</h2>
 
 
 		<p>
 		<p>
-			[example:webaudio_sandbox webaudio / sandbox ]</br>
-			[example:webaudio_timing webaudio / timing ]</br>
+			[example:webaudio_sandbox webaudio / sandbox ]<br />
+			[example:webaudio_timing webaudio / timing ]<br />
 			[example:webaudio_visualizer webaudio / visualizer ]
 			[example:webaudio_visualizer webaudio / visualizer ]
 		</p>
 		</p>
 
 

+ 2 - 2
docs/api/en/audio/PositionalAudio.html

@@ -22,8 +22,8 @@
 		<h2>Example</h2>
 		<h2>Example</h2>
 
 
 		<p>
 		<p>
-			[example:webaudio_orientation webaudio / orientation ]</br>
-			[example:webaudio_sandbox webaudio / sandbox ]</br>
+			[example:webaudio_orientation webaudio / orientation ]<br />
+			[example:webaudio_sandbox webaudio / sandbox ]<br />
 			[example:webaudio_timing webaudio / timing ]
 			[example:webaudio_timing webaudio / timing ]
 		</p>
 		</p>
 
 

+ 1 - 0
docs/api/en/constants/Renderer.html

@@ -55,6 +55,7 @@
 		THREE.ReinhardToneMapping
 		THREE.ReinhardToneMapping
 		THREE.Uncharted2ToneMapping
 		THREE.Uncharted2ToneMapping
 		THREE.CineonToneMapping
 		THREE.CineonToneMapping
+		THREE.ACESFilmicToneMapping
 		</code>
 		</code>
 		<p>
 		<p>
 		These define the WebGLRenderer's [page:WebGLRenderer.toneMapping toneMapping] property.
 		These define the WebGLRenderer's [page:WebGLRenderer.toneMapping toneMapping] property.

+ 1 - 1
docs/api/en/core/Object3D.html

@@ -292,7 +292,7 @@
 		Converts the vector from local space to world space.
 		Converts the vector from local space to world space.
 		</p>
 		</p>
 
 
-		<h3>[method:null lookAt]( [param:Vector3 vector] )</br>
+		<h3>[method:null lookAt]( [param:Vector3 vector] )<br />
 		[method:null lookAt]( [param:Float x], [param:Float y], [param:Float z] )</h3>
 		[method:null lookAt]( [param:Float x], [param:Float y], [param:Float z] )</h3>
 		<p>
 		<p>
 		vector - A vector representing a position in world space.<br /><br />
 		vector - A vector representing a position in world space.<br /><br />

+ 4 - 1
docs/api/en/extras/core/ShapePath.html

@@ -44,6 +44,9 @@
 		The current [page:Path] that is being generated.
 		The current [page:Path] that is being generated.
 		</p>
 		</p>
 
 
+		<h3>[property:Color color]</h3>
+		<p>[page:Color] of the shape, by default set to white (0xffffff).</p>
+
 		<h2>Methods</h2>
 		<h2>Methods</h2>
 
 
 		<h3>[method:null moveTo]( [param:Float x], [param:Float y] )</h3>
 		<h3>[method:null moveTo]( [param:Float x], [param:Float y] )</h3>
@@ -86,6 +89,6 @@
 
 
 		<h2>Source</h2>
 		<h2>Source</h2>
 
 
-		[link:https://github.com/mrdoob/three.js/blob/master/src/extras/core/Path.js src/extras/core/Path.js]
+		[link:https://github.com/mrdoob/three.js/blob/master/src/extras/core/ShapePath.js src/extras/core/ShapePath.js]
 	</body>
 	</body>
 </html>
 </html>

+ 73 - 0
docs/api/en/helpers/PositionalAudioHelper.html

@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:Object3D] &rarr;
+
+		<h1>[name]</h1>
+
+		<p class="desc">This helper displays the directional cone of a [page:PositionalAudio].</p>
+
+		<h2>Example</h2>
+
+		<div>[example:webaudio_orientation webaudio / orientation ]</div>
+
+		<h2>Code Example</h2>
+		<code>
+var positionalAudio = new THREE.PositionalAudio( listener );
+positionalAudio.setDirectionalCone( 180, 230, 0.1 );
+
+var helper = new PositionalAudioHelper( positionalAudio );
+positionalAudio.add( helper );
+		</code>
+
+
+		<h2>Constructor</h2>
+
+		<h3>[name]( [param:PositionalAudio audio], [param:Number range] )</h3>
+		<p>
+			[page:PositionalAudio audio] -- The [page:PositionalAudio] to be visualized. <br /><br/>
+
+			[page:Number range] -- (optional) The range of the directional cone. <br /><br/>
+
+			[page:Number divisionsInnerAngle] -- (optional) The amount of divisions of the inner part of the directional cone. <br /><br/>
+
+			[page:Number divisionsOuterAngle] -- (optional) The amount of divisions of the outer part of the directional cone. <br /><br/>
+		</p>
+
+
+		<h2>Properties</h2>
+		<p>See the base [page:Object3D] class for common properties.</p>
+
+		<h3>[property:PositionalAudio audio]</h3>
+		<p>[page:PositionalAudio] to be visualized.</p>
+
+		<h3>[property:Number range]</h3>
+		<p>The range of the directional cone.</p>
+
+		<h3>[property:Number divisionsInnerAngle]</h3>
+		<p>The amount of divisions of the inner part of the directional cone.</p>
+
+		<h3>[property:Number divisionsOuterAngle]</h3>
+		<p>The amount of divisions of the outer part of the directional cone.</p>
+
+		<h2>Methods</h2>
+		<p>See the base [page:Object3D] class for common methods.</p>
+
+		<h3>[method:null dispose]()</h3>
+		<p>Disposes of the helper.</p>
+
+		<h3>[method:null update]()</h3>
+		<p>Updates the helper.</p>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 7 - 0
docs/api/en/materials/Material.html

@@ -261,6 +261,13 @@
 		Other options are [page:Materials THREE.VertexColors] and [page:Materials THREE.FaceColors].
 		Other options are [page:Materials THREE.VertexColors] and [page:Materials THREE.FaceColors].
 		</p>
 		</p>
 
 
+		<h3>[property:Boolean vertexTangents]</h3>
+		<p>
+		Defines whether precomputed vertex tangents, which must be provided in a vec4 "tangent" attribute,
+		are used. When disabled, tangents are derived automatically. Using precomputed tangents will give
+		more accurate normal map details in some cases, such as with mirrored UVs. Default is false.
+		</p>
+
 		<h3>[property:Boolean visible]</h3>
 		<h3>[property:Boolean visible]</h3>
 		<p>
 		<p>
 		Defines whether this material is visible. Default is *true*.
 		Defines whether this material is visible. Default is *true*.

+ 2 - 2
docs/api/en/objects/SkinnedMesh.html

@@ -91,8 +91,8 @@
 		<h2>Constructor</h2>
 		<h2>Constructor</h2>
 		<h3>[name]( [param:BufferGeometry geometry], [param:Material material] )</h3>
 		<h3>[name]( [param:BufferGeometry geometry], [param:Material material] )</h3>
 		<p>
 		<p>
-    [page:Geometry geometry] - an instance of [page:BufferGeometry].<br />
-    [page:Material material] - (optional) an instance of [page:Material]. Default is a new [page:MeshBasicMaterial].
+		[page:Geometry geometry] - an instance of [page:BufferGeometry].<br />
+		[page:Material material] - (optional) an instance of [page:Material]. Default is a new [page:MeshBasicMaterial].
 		</p>
 		</p>
 
 
 
 

+ 63 - 20
docs/api/en/renderers/WebGLRenderer.html

@@ -348,37 +348,66 @@
 		<h3>[method:RenderTarget getRenderTarget]()</h3>
 		<h3>[method:RenderTarget getRenderTarget]()</h3>
 		<p>Returns the current RenderTarget, if any.</p>
 		<p>Returns the current RenderTarget, if any.</p>
 
 
-		<h3>[method:RenderTarget getCurrentViewport]()</h3>
-		<p>Returns the current viewport.</p>
+		<h3>[method:Vector4 getCurrentViewport]( [param:Vector4 target] )</h3>
+		<p>
+		[page:Vector4 target] — the result will be copied into this Vector4.<br /><br />
+
+		Returns the current viewport.
+		</p>
 
 
-		<h3>[method:Object getDrawingBufferSize]()</h3>
-		<p>Returns an object containing the width and height of the renderer's drawing buffer, in pixels.</p>
+		<h3>[method:Vector2 getDrawingBufferSize]( [param:Vector2 target] )</h3>
+		<p>
+		[page:Vector2 target] — the result will be copied into this Vector2.<br /><br />
+
+		Returns the width and height of the renderer's drawing buffer, in pixels.
+		</p>
 
 
 		<h3>[method:number getPixelRatio]()</h3>
 		<h3>[method:number getPixelRatio]()</h3>
 		<p>Returns current device pixel ratio used.</p>
 		<p>Returns current device pixel ratio used.</p>
 
 
-		<h3>[method:Object getSize]()</h3>
-		<p>Returns an object containing the width and height of the renderer's output canvas, in pixels.</p>
+		<h3>[method:Vector4 getScissor]( [param:Vector4 target] )</h3>
+		<p>
+		[page:Vector4 target] — the result will be copied into this Vector4.<br /><br />
+
+		Returns the scissor region.
+		</p>
+
+		<h3>[method:Boolean getScissorTest]()</h3>
+		<p>Returns *true* if scissor test is enabled; returns *false* otherwise.</p>
+
+		<h3>[method:Vector2 getSize]( [param:Vector2 target] )</h3>
+		<p>
+		[page:Vector2 target] — the result will be copied into this Vector2.<br /><br />
+
+		Returns the width and height of the renderer's output canvas, in pixels.
+		</p>
+
+		<h3>[method:Vector4 getViewport]( [param:Vector4 target] )</h3>
+		<p>
+		[page:Vector4 target] — the result will be copied into this Vector4.<br /><br />
+
+		Returns the viewport.
+		</p>
 
 
 		<h3>[method:null resetGLState]( )</h3>
 		<h3>[method:null resetGLState]( )</h3>
 		<p>Reset the GL state to default. Called internally if the WebGL context is lost.</p>
 		<p>Reset the GL state to default. Called internally if the WebGL context is lost.</p>
 
 
-		<h3>[method:null readRenderTargetPixels]( [param:WebGLRenderTarget renderTarget], [param:Float x], [param:Float y], [param:Float width], [param:Float height], buffer )</h3>
-		<p>Reads the pixel data from the renderTarget into the buffer you pass in. This is a wrapper around [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/readPixels WebGLRenderingContext.readPixels]().<br />
-		See the [example:webgl_interactive_cubes_gpu interactive / cubes / gpu] example.
+		<h3>[method:null readRenderTargetPixels]( [param:WebGLRenderTarget renderTarget], [param:Float x], [param:Float y], [param:Float width], [param:Float height], [param:TypedArray buffer] )</h3>
+		<p>buffer - Uint8Array is the only destination type supported in all cases, other types are renderTarget and platform dependent. See [link:https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.12 WebGL spec] for details.</p>
+		<p>Reads the pixel data from the renderTarget into the buffer you pass in. This is a wrapper around [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/readPixels WebGLRenderingContext.readPixels]().</p>
+		<p>See the [example:webgl_interactive_cubes_gpu interactive / cubes / gpu] example.
 		</p>
 		</p>
 
 
-		<h3>[method:null render]( [param:Scene scene], [param:Camera camera], [param:WebGLRenderTarget renderTarget], [param:Boolean forceClear] )</h3>
+
+		<h3>[method:null render]( [param:Scene scene], [param:Camera camera] )</h3>
 		<p>
 		<p>
 			Render a [page:Scene scene] using a [page:Camera camera].<br />
 			Render a [page:Scene scene] using a [page:Camera camera].<br />
 
 
-			The render is done to the [page:WebGLRenderTarget renderTarget] (if specified) or to the canvas as usual.<br />
-
-			If [page:Boolean forceClear] is *true*, the depth, stencil and color buffers will be cleared
-			before rendering even if the renderer's [page:WebGLRenderer.autoClear autoClear] property is false.<br />
+			The render is done to a previously specified [page:WebGLRenderTarget renderTarget] set by calling [page:WebGLRenderer.setRenderTarget .setRenderTarget] or to the canvas as usual.<br />
 
 
-			Even with forceClear set to true you can prevent certain buffers being cleared by setting
-			either the [page:WebGLRenderer.autoClearColor autoClearColor], [page:WebGLRenderer.autoClearStencil autoClearStencil] or [page:WebGLRenderer.autoClearDepth autoClearDepth] properties to false.
+			By default render buffers are cleared before rendering but you can prevent this by setting the property [page:WebGLRenderer.autoClear autoClear] to false.
+			If you want to prevent only certain buffers being cleared you can set either the [page:WebGLRenderer.autoClearColor autoClearColor], [page:WebGLRenderer.autoClearStencil autoClearStencil] or
+			[page:WebGLRenderer.autoClearDepth autoClearDepth] properties to false. To forcibly clear one ore more buffers call [page:WebGLRenderer.clear .clear].
 		</p>
 		</p>
 
 
 		<h3>[method:null renderBufferDirect]( [param:Camera camera], [param:Fog fog], [param:Geometry geometry], [param:Material material], [param:Object3D object], [param:Object group] )</h3>
 		<h3>[method:null renderBufferDirect]( [param:Camera camera], [param:Fog fog], [param:Geometry geometry], [param:Material material], [param:Object3D object], [param:Object group] )</h3>
@@ -411,9 +440,15 @@
 		This method sets the active rendertarget. If the parameter is omitted the canvas is set as the active rendertarget.
 		This method sets the active rendertarget. If the parameter is omitted the canvas is set as the active rendertarget.
 		</p>
 		</p>
 
 
-		<h3>[method:null setScissor]( [param:Integer x], [param:Integer y], [param:Integer width], [param:Integer height] )</h3>
+		<h3>[method:null setScissor]( [param:Integer x], [param:Integer y], [param:Integer width], [param:Integer height] )<br />
+		[method:null setScissor]( [param:Vector4 vector] )</h3>
+
 		<p>
 		<p>
-		Sets the scissor area from (x, y) to (x + width, y + height)
+		The x, y, width, and height parameters of the scissor region.<br />
+		Optionally, a 4-component vector specifying the parameters of the region.<br /><br />
+
+		Sets the scissor region from (x, y) to (x + width, y + height).<br />
+		(x, y) is the lower-left corner of the scissor region.
 		</p>
 		</p>
 
 
 		<h3>[method:null setScissorTest]( [param:Boolean boolean] )</h3>
 		<h3>[method:null setScissorTest]( [param:Boolean boolean] )</h3>
@@ -449,8 +484,16 @@
 		The slot number can be found as a value of the uniform of the sampler.
 		The slot number can be found as a value of the uniform of the sampler.
 		</p>
 		</p>
 
 
-		<h3>[method:null setViewport]( [param:Integer x], [param:Integer y], [param:Integer width], [param:Integer height] )</h3>
-		<p>Sets the viewport to render from (x, y) to (x + width, y + height).</p>
+		<h3>[method:null setViewport]( [param:Integer x], [param:Integer y], [param:Integer width], [param:Integer height] )<br />
+		[method:null setViewport]( [param:Vector4 vector] )</h3>
+
+		<p>
+		The x, y, width, and height parameters of the viewport.<br />
+		Optionally, a 4-component vector specifying the parameters of a viewport.<br /><br />
+
+		Sets the viewport to render from (x, y) to (x + width, y + height).<br />
+		(x, y) is the lower-left corner of the region.
+		</p>
 
 
 		<h2>Source</h2>
 		<h2>Source</h2>
 
 

+ 10 - 2
docs/api/en/textures/DataTexture3D.html

@@ -32,10 +32,18 @@
 		<div>[example:webgl2_materials_texture3d WebGL2 / materials / texture3d]</div>
 		<div>[example:webgl2_materials_texture3d WebGL2 / materials / texture3d]</div>
 		<div>[example:webgl2_materials_texture3d_volume WebGL2 / materials / texture3d / volume]</div>
 		<div>[example:webgl2_materials_texture3d_volume WebGL2 / materials / texture3d / volume]</div>
 
 
-		<h2>Properties</h2>
+    <h2>Properties</h2>
 
 
 		<p>
 		<p>
-		See the base [page:Texture Texture] class for common properties.
+    See the base [page:Texture Texture] class for common properties.
+    </p>
+
+    <h3>[property:number wrapR]</h3>
+		<p>
+		This defines how the texture is wrapped in the depth direction.<br />
+		The default is [page:Textures THREE.ClampToEdgeWrapping], where the edge is clamped to the outer edge texels.
+		The other two choices are [page:Textures THREE.RepeatWrapping] and [page:Textures THREE.MirroredRepeatWrapping].
+		See the [page:Textures texture constants] page for details.
 		</p>
 		</p>
 
 
 		<h2>Methods</h2>
 		<h2>Methods</h2>

+ 3 - 0
docs/api/zh/animation/AnimationClip.html

@@ -62,6 +62,9 @@
 		<h2>方法</h2>
 		<h2>方法</h2>
 
 
 
 
+		<h3>[method:AnimationClip clone]()</h3>
+		<p></p>
+
 		<h3>[method:this optimize]()</h3>
 		<h3>[method:this optimize]()</h3>
 		<p>
 		<p>
             通过移除等效的顺序键(在变形目标序列中很常见)来优化每一个轨道
             通过移除等效的顺序键(在变形目标序列中很常见)来优化每一个轨道

+ 6 - 0
docs/api/zh/animation/AnimationUtils.html

@@ -38,12 +38,18 @@
             返回一个数组,时间和值可以根据此数组排序。
             返回一个数组,时间和值可以根据此数组排序。
 		</p>
 		</p>
 
 
+		<h3>[method:Number insertKeyframe]( [param:KeyframeTrack track], [param:Number time] )</h3>
+		<p></p>
+
 		<h3>[method:Boolean isTypedArray]( object )</h3>
 		<h3>[method:Boolean isTypedArray]( object )</h3>
 		<p>
 		<p>
             如果该对象是类型化数组,返回*true*
             如果该对象是类型化数组,返回*true*
 
 
 		</p>
 		</p>
 
 
+		<h3>[method:AnimationClip mergeMorphTargetTracks]( [param:AnimationClip clip], [param:Object3D root] )</h3>
+		<p></p>
+
 		<h3>[method:Array sortedArray]( values, stride, order )</h3>
 		<h3>[method:Array sortedArray]( values, stride, order )</h3>
 		<p>
 		<p>
             将[page:AnimationUtils.getKeyframeOrder getKeyframeOrder]方法返回的数组排序。
             将[page:AnimationUtils.getKeyframeOrder getKeyframeOrder]方法返回的数组排序。

+ 3 - 0
docs/api/zh/animation/KeyframeTrack.html

@@ -137,6 +137,9 @@
 		<h2>方法</h2>
 		<h2>方法</h2>
 
 
 
 
+		<h3>[method:KeyframeTrack clone]()</h3>
+		<p></p>
+
 		<h3>[method:null createInterpolant]()</h3>
 		<h3>[method:null createInterpolant]()</h3>
 		<p>
 		<p>
 			根据传入构造器中的插值类型参数,创建线性插值([page:LinearInterpolant LinearInterpolant]),立方插值([page:CubicInterpolant CubicInterpolant])或离散插值
 			根据传入构造器中的插值类型参数,创建线性插值([page:LinearInterpolant LinearInterpolant]),立方插值([page:CubicInterpolant CubicInterpolant])或离散插值

+ 1 - 1
docs/api/zh/audio/Audio.html

@@ -22,7 +22,7 @@
 		<h2>例子</h2>
 		<h2>例子</h2>
 
 
 		<p>
 		<p>
-			[example:webaudio_sandbox webaudio / sandbox ]</br>
+			[example:webaudio_sandbox webaudio / sandbox ]<br />
 			[example:webaudio_visualizer webaudio / visualizer ]
 			[example:webaudio_visualizer webaudio / visualizer ]
 		</p>
 		</p>
 
 

+ 1 - 1
docs/api/zh/audio/AudioAnalyser.html

@@ -22,7 +22,7 @@
 		<h2>示例</h2>
 		<h2>示例</h2>
 
 
 		<p>
 		<p>
-			[example:webaudio_sandbox webaudio / sandbox ]</br>
+			[example:webaudio_sandbox webaudio / sandbox ]<br />
 			[example:webaudio_visualizer webaudio / visualizer ]
 			[example:webaudio_visualizer webaudio / visualizer ]
 		</p>
 		</p>
 
 

+ 4 - 4
docs/api/zh/audio/AudioListener.html

@@ -13,8 +13,8 @@
 		<h1>[name]</h1>
 		<h1>[name]</h1>
 
 
 		<p class="desc">
 		<p class="desc">
-			[name] 用一个虚拟的[link:https://developer.mozilla.org/de/docs/Web/API/AudioListener listener]表示在场景中所有的位置和非位置相关的音效.</br>
-			一个three.js程序通常创建一个[name]. 它是音频实体构造函数的必须参数,比如 [page:Audio Audio] and [page:PositionalAudio PositionalAudio].</br>
+			[name] 用一个虚拟的[link:https://developer.mozilla.org/de/docs/Web/API/AudioListener listener]表示在场景中所有的位置和非位置相关的音效.<br />
+			一个three.js程序通常创建一个[name]. 它是音频实体构造函数的必须参数,比如 [page:Audio Audio] and [page:PositionalAudio PositionalAudio].<br />
 			大多数情况下, listener对象是camera的子对象. Camera的3D变换表示了listener的3D变换.
 			大多数情况下, listener对象是camera的子对象. Camera的3D变换表示了listener的3D变换.
 		</p>
 		</p>
 
 
@@ -22,8 +22,8 @@
 		<h2>示例</h2>
 		<h2>示例</h2>
 
 
 		<p>
 		<p>
-			[example:webaudio_sandbox webaudio / sandbox ]</br>
-			[example:webaudio_timing webaudio / timing ]</br>
+			[example:webaudio_sandbox webaudio / sandbox ]<br />
+			[example:webaudio_timing webaudio / timing ]<br />
 			[example:webaudio_visualizer webaudio / visualizer ]
 			[example:webaudio_visualizer webaudio / visualizer ]
 		</p>
 		</p>
 
 

+ 2 - 2
docs/api/zh/audio/PositionalAudio.html

@@ -22,8 +22,8 @@
 		<h2>示例</h2>
 		<h2>示例</h2>
 
 
 		<p>
 		<p>
-			[example:webaudio_orientation webaudio / orientation ]</br>
-			[example:webaudio_sandbox webaudio / sandbox ]</br>
+			[example:webaudio_orientation webaudio / orientation ]<br />
+			[example:webaudio_sandbox webaudio / sandbox ]<br />
 			[example:webaudio_timing webaudio / timing ]
 			[example:webaudio_timing webaudio / timing ]
 		</p>
 		</p>
 
 

+ 1 - 1
docs/api/zh/core/Object3D.html

@@ -273,7 +273,7 @@
 		将局部空间向量转换为世界空间向量。
 		将局部空间向量转换为世界空间向量。
 	</p>
 	</p>
 
 
-	<h3>[method:null lookAt]( [param:Vector3 vector] )</br>
+	<h3>[method:null lookAt]( [param:Vector3 vector] )<br />
 		[method:null lookAt]( [param:Float x], [param:Float y], [param:Float z] )</h3>
 		[method:null lookAt]( [param:Float x], [param:Float y], [param:Float z] )</h3>
 	<p>
 	<p>
 		vector - 一个表示世界空间中位置的向量。<br /><br />
 		vector - 一个表示世界空间中位置的向量。<br /><br />

+ 73 - 0
docs/api/zh/helpers/PositionalAudioHelper.html

@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:Object3D] &rarr;
+
+		<h1>[name]</h1>
+
+		<p class="desc">这一辅助对象显示[page:PositionalAudio]的方向锥。</p>
+
+		<h2>示例</h2>
+
+		<div>[example:webaudio_orientation webaudio / orientation ]</div>
+
+		<h2>示例代码</h2>
+		<code>
+var positionalAudio = new THREE.PositionalAudio( listener );
+positionalAudio.setDirectionalCone( 180, 230, 0.1 );
+
+var helper = new PositionalAudioHelper( positionalAudio );
+positionalAudio.add( helper );
+		</code>
+
+
+		<h2>构造函数</h2>
+
+		<h3>[name]( [param:PositionalAudio audio], [param:Number range] )</h3>
+		<p>
+			[page:PositionalAudio audio] -- 将会被可视化的[page:PositionalAudio]。<br /><br/>
+
+			[page:Number range] -- (可选)方向锥的范围。<br /><br/>
+
+			[page:Number divisionsInnerAngle] -- (可选)方向锥内侧部分的分段数。<br /><br/>
+
+			[page:Number divisionsOuterAngle] -- (可选)方向锥外侧部分的分段数。<br /><br/>
+		</p>
+
+
+		<h2>属性</h2>
+		<p>请参阅其基类[page:Object3D]来了解共有属性。</p>
+
+		<h3>[property:PositionalAudio audio]</h3>
+		<p>将会被可视化的[page:PositionalAudio]。</p>
+
+		<h3>[property:Number range]</h3>
+		<p>方向锥的范围。</p>
+
+		<h3>[property:Number divisionsInnerAngle]</h3>
+		<p>方向锥内侧部分的分段数。</p>
+
+		<h3>[property:Number divisionsOuterAngle]</h3>
+		<p>方向锥外侧部分的分段数。</p>
+
+		<h2>方法</h2>
+		<p>请参阅其基类[page:Object3D]来了解共有方法。</p>
+
+		<h3>[method:null dispose]()</h3>
+		<p>废置这一辅助对象。</p>
+
+		<h3>[method:null update]()</h3>
+		<p>更新这一辅助对象。</p>
+
+		<h2>源代码</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 4 - 0
docs/api/zh/materials/Material.html

@@ -217,6 +217,10 @@
     其他选项有[page:Materials THREE.VertexColors] 和 [page:Materials THREE.FaceColors]。
     其他选项有[page:Materials THREE.VertexColors] 和 [page:Materials THREE.FaceColors]。
 </p>
 </p>
 
 
+<h3>[property:Boolean vertexTangents]</h3>
+<p> TODO.
+</p>
+
 <h3>[property:Boolean visible]</h3>
 <h3>[property:Boolean visible]</h3>
 <p> 此材质是否可见。默认为*true*。
 <p> 此材质是否可见。默认为*true*。
 </p>
 </p>

+ 1 - 1
docs/api/zh/textures/Texture.html

@@ -244,7 +244,7 @@
 
 
 		<h3>[method:null dispose]()</h3>
 		<h3>[method:null dispose]()</h3>
 		<p>
 		<p>
-			使用“dispose”事件类型调用[page:EventDispatcher EventDispatcher].dispatchEvent。
+			使用“废置”事件类型调用[page:EventDispatcher EventDispatcher].dispatchEvent。
 		</p>
 		</p>
 
 
 		<h3>[method:Vector2 transformUv]( [param:Vector2 uv] )</h3>
 		<h3>[method:Vector2 transformUv]( [param:Vector2 uv] )</h3>

+ 1 - 0
docs/examples/exporters/GLTFExporter.html

@@ -29,6 +29,7 @@
 		</p>
 		</p>
 
 
 		<ul>
 		<ul>
+			<li>KHR_lights_punctual</li>
 			<li>KHR_materials_unlit</li>
 			<li>KHR_materials_unlit</li>
 			<li>KHR_texture_transform</li>
 			<li>KHR_texture_transform</li>
 		</ul>
 		</ul>

+ 15 - 0
docs/index.html

@@ -69,6 +69,8 @@
 
 
 				language = value;
 				language = value;
 				createNavigation();
 				createNavigation();
+				updateFilter();
+				autoChangeUrlLanguage( language );
 
 
 			}
 			}
 
 
@@ -226,6 +228,19 @@
 
 
 			}
 			}
 
 
+			// Auto change language url. If a reader open a document in English, when he click "zh", the document he read will auto change into Chinese version
+
+			function autoChangeUrlLanguage( language ) {
+
+				var hash = location.hash;
+				if ( hash === '' ) return;
+				var docType = hash.substr( 0, hash.indexOf( '/' ) + 1 );
+				var docLink = hash.substr( hash.indexOf( '/' ) + 1 );
+				docLink = docLink.substr( docLink.indexOf( '/' ) );
+				location.href = docType + language + docLink;
+
+			}
+
 
 
 			// Filtering
 			// Filtering
 
 

+ 4 - 0
docs/list.js

@@ -22,6 +22,7 @@ var list = {
 
 
 			"Next Steps": {
 			"Next Steps": {
 				"How to update things": "manual/en/introduction/How-to-update-things",
 				"How to update things": "manual/en/introduction/How-to-update-things",
+				"How to dispose of objects": "manual/en/introduction/How-to-dispose-of-objects",
 				"How to create VR content": "manual/en/introduction/How-to-create-VR-content",
 				"How to create VR content": "manual/en/introduction/How-to-create-VR-content",
 				"Matrix transformations": "manual/en/introduction/Matrix-transformations",
 				"Matrix transformations": "manual/en/introduction/Matrix-transformations",
 				"Animation system": "manual/en/introduction/Animation-system"
 				"Animation system": "manual/en/introduction/Animation-system"
@@ -197,6 +198,7 @@ var list = {
 				"FaceNormalsHelper": "api/en/helpers/FaceNormalsHelper",
 				"FaceNormalsHelper": "api/en/helpers/FaceNormalsHelper",
 				"GridHelper": "api/en/helpers/GridHelper",
 				"GridHelper": "api/en/helpers/GridHelper",
 				"PolarGridHelper": "api/en/helpers/PolarGridHelper",
 				"PolarGridHelper": "api/en/helpers/PolarGridHelper",
+				"PositionalAudioHelper": "api/en/helpers/PositionalAudioHelper",
 				"HemisphereLightHelper": "api/en/helpers/HemisphereLightHelper",
 				"HemisphereLightHelper": "api/en/helpers/HemisphereLightHelper",
 				"PlaneHelper": "api/en/helpers/PlaneHelper",
 				"PlaneHelper": "api/en/helpers/PlaneHelper",
 				"PointLightHelper": "api/en/helpers/PointLightHelper",
 				"PointLightHelper": "api/en/helpers/PointLightHelper",
@@ -448,6 +450,7 @@ var list = {
 
 
 			"进阶": {
 			"进阶": {
 				"如何更新场景": "manual/zh/introduction/How-to-update-things",
 				"如何更新场景": "manual/zh/introduction/How-to-update-things",
+				"如何废置对象": "manual/zh/introduction/How-to-dispose-of-objects",
 				"如何创建VR内容": "manual/zh/introduction/How-to-create-VR-content",
 				"如何创建VR内容": "manual/zh/introduction/How-to-create-VR-content",
 				"矩阵变换": "manual/zh/introduction/Matrix-transformations",
 				"矩阵变换": "manual/zh/introduction/Matrix-transformations",
 				"动画系统": "manual/zh/introduction/Animation-system"
 				"动画系统": "manual/zh/introduction/Animation-system"
@@ -622,6 +625,7 @@ var list = {
 				"FaceNormalsHelper": "api/zh/helpers/FaceNormalsHelper",
 				"FaceNormalsHelper": "api/zh/helpers/FaceNormalsHelper",
 				"GridHelper": "api/zh/helpers/GridHelper",
 				"GridHelper": "api/zh/helpers/GridHelper",
 				"PolarGridHelper": "api/zh/helpers/PolarGridHelper",
 				"PolarGridHelper": "api/zh/helpers/PolarGridHelper",
+				"PositionalAudioHelper": "api/zh/helpers/PositionalAudioHelper",
 				"HemisphereLightHelper": "api/zh/helpers/HemisphereLightHelper",
 				"HemisphereLightHelper": "api/zh/helpers/HemisphereLightHelper",
 				"PlaneHelper": "api/zh/helpers/PlaneHelper",
 				"PlaneHelper": "api/zh/helpers/PlaneHelper",
 				"PointLightHelper": "api/zh/helpers/PointLightHelper",
 				"PointLightHelper": "api/zh/helpers/PointLightHelper",

+ 126 - 0
docs/manual/en/introduction/How-to-dispose-of-objects.html

@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+	<meta charset="utf-8">
+	<base href="../../../" />
+	<script src="list.js"></script>
+	<script src="page.js"></script>
+	<link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+	<h1>[name]</h1>
+	<br />
+
+	<p>
+		One important aspect in order to improve performance and avoid memory leaks in your application is the disposal of unused library entities.
+		Whenever you create an instance of a *three.js* type, you allocate a certain amount of memory. However, *three.js* creates for specific objects
+		like geometries or materials WebGL related entities like buffers or shader programs which are necessary for rendering. It's important to
+		highlight that these objects are not released automatically. Instead, the application has to use a special API in order to free such resources.
+		This guide provides a brief overview about how this API is used and what objects are relevant in this context.
+	</p>
+
+	<h2>Geometries</h2>
+
+	<p>
+		A geometry usually represents vertex information defined as a collection of attributes. *three.js* internally creates an object of type [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLBuffer WebGLBuffer]
+		for each attribute. These entities are only deleted if you call [page:BufferGeometry.dispose](). If a geometry becomes obsolete in your application,
+		execute the method to free all related resources.
+	</p>
+
+	<h2>Materials</h2>
+
+	<p>
+		A material defines how objects are rendered. *three.js* uses the information of a material definition in order to construct a shader program for rendering.
+		Shader programs can only be deleted if the respective material is disposed. For performance reasons, *three.js* tries to reuse existing
+		shader programs if possible. So a shader program is only deleted if all related materials are disposed. You can indicate the disposal of a material by
+		executing [page:Material.dispose]().
+	</p>
+
+	<h2>Textures</h2>
+
+	<p>
+		The disposal of a material has no effect on textures. They are handled separately since a single texture can be used by multiple materials at the same time.
+		Whenever you create an instance of [page:Texture], three.js internally creates an instance of [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture].
+		Similar to buffers, this object can only be deleted by calling [page:Texture.dispose]().
+	</p>
+
+	<h2>Render Targets</h2>
+
+	<p>
+		Objects of type [page:WebGLRenderTarget] not only allocate an instance of [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture] but also
+		[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLFramebuffer WebGLFramebuffer]s and [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderbuffer WebGLRenderbuffer]s
+		for realizing custom rendering destinations. These objects are only deallocated by executing [page:WebGLRenderTarget.dispose]().
+	</p>
+
+	<h2>Miscellaneous</h2>
+
+	<p>
+		There are other classes from the examples directory like controls or post processing passes which provide *dispose()* methods in order to remove internal event listeners
+		or render targets. In general, it's recommended to check the API or documentation of a class and watch for *dispose()*. If present, you should use it when cleaning things up.
+	</p>
+
+	<h2>FAQ</h2>
+
+	<h3>Why can't *three.js* dispose objects automatically?</h3>
+
+	<p>
+		This question was asked many times by the community so it's important to clarify this matter. Fact is that *three.js* does not know the lifetime or scope
+		of user-created entities like geometries or materials. This is the responsibility of the application. For example even if a material is currently not used for rendering,
+		it might base necessary for the next frame. So if the application decides that a certain object can be deleted, it has to	notify the engine via calling the respective
+		*dispose()* method.
+	</p>
+
+	<h3>Does removing a mesh from the scene also dispose its geometry and material?</h3>
+
+	<p>
+		No, you have to explicitly dispose the geometry and material via *dispose()*. Keep in mind that geometries and materials can be shared among 3D objects like meshes.
+	</p>
+
+	<h3>Does *three.js* provide information about the amount of cached objects?</h3>
+
+	<p>
+		Yes. It's possible to evaluate [page:WebGLRenderer.info], a special property of the renderer with a series of statistical information about the graphics board memory
+		and the rendering process. Among other things, it tells you have many textures, geometries and shader programs are internally stored. If you notice performance problems
+		in your application, it's a good idea to debug this property in order to easily identify a memory leak.
+	</p>
+
+	<p>
+		Internal resources for a texture are only allocated if the image has fully loaded. If you dispose a texture before the image was loaded,
+		nothing happens. No resources were allocated so there is also no need for clean up.
+	</p>
+
+	<h3>Why happens when you call *dispose()* on a texture but the image is not loaded yet?</h3>
+
+	<p>
+		Internal resources for a texture are only allocated if the image has fully loaded. If you dispose a texture before the image was loaded,
+		nothing happens. No resources were allocated so there is also no need for clean up.
+	</p>
+
+	<h3>What happens when I call *dispose()* and then use the respective object at a later point?</h3>
+
+	<p>
+		The deleted internal resources will be created again by the engine. So no runtime error will occur but you might notice a negative performance impact for the current frame,
+		especially when shader programs have to be compiled.
+	</p>
+
+	<h3>How should I manage *three.js* objects in my app? When do I know how to dispose things?</h3>
+
+	<p>
+		In general, there is no definite recommendation for this. It highly depends on the specific use case when calling *dispose()* is appropriate. It's important to highlight that
+		it's not always necessary to dispose objects all the time. A good example for this is a game which consists of multiple levels. A good place for object disposal is when
+		switching the level. The app could traverse through the old scene and dispose all obsolete materials, geometries and textures. As mentioned in the previous section, it does not
+		produce a runtime error if you dispose an object that is actually still in use. The worst thing that can happen is performance drop for a single frame.
+	</p>
+
+	<h2>Examples that demonstrate the usage of dispose()</h2>
+
+	<p>
+		[example:webgl_test_memory WebGL / test / memory]<br />
+		[example:webgl_test_memory2 WebGL / test / memory2]<br />
+	</p>
+
+</body>
+
+</html>

+ 4 - 0
docs/manual/en/introduction/Useful-links.html

@@ -125,6 +125,10 @@
 		<li>
 		<li>
 			[link:http://idflood.github.io/ThreeNodes.js/ ThreeNodes.js].
 			[link:http://idflood.github.io/ThreeNodes.js/ ThreeNodes.js].
 		</li>
 		</li>
+		<li>
+			<a href="https://marketplace.visualstudio.com/items?itemName=bierner.comment-tagged-templates" target="_blank">comment-tagged-templates</a> -
+			VSCode extension syntax highlighting for tagged template strings, like: glsl.js.
+		</li>
 	 </ul>
 	 </ul>
 
 
 	<h2>WebGL References</h2>
 	<h2>WebGL References</h2>

+ 6 - 6
docs/manual/zh/introduction/Creating-a-scene.html

@@ -10,11 +10,11 @@
 	<body>
 	<body>
 		<h1>创建一个场景([name])</h1><br />
 		<h1>创建一个场景([name])</h1><br />
 
 
-		<p>这一部分将对three.js来做一个简要的介绍。在这一部分里,我们将以搭建一个包含有旋转立方体的场景。在页面下方有一个已经完成的例子,当你遇到麻烦,或者需要帮助的时候,可以看一看。</p>
+		<p>这一部分将对three.js来做一个简要的介绍;我们将开始搭建一个场景,其中包含一个正在旋转的立方体。页面下方有一个已经完成的例子,当你遇到麻烦,或者需要帮助的时候,可以看一看。</p>
 
 
 		<h2>开始之前</h2>
 		<h2>开始之前</h2>
 		<p>
 		<p>
-			在开始使用three.js之前,你需要一个地方来显示它。将下列HTML代码保存为你电脑上的一个HTML文件,同时将[link:https://threejs.org/build/three.js three.js]复制到该HTML文件所在的目录下的js/目录下,然后在你的浏览器中打开这个HTML文件。
+			在开始使用three.js之前,你需要一个地方来显示它。将下列HTML代码保存为你电脑上的一个HTML文件,同时将[link:https://threejs.org/build/three.js three.js]复制到该HTML文件所在的目录下的js/目录下,然后在你的浏览器中打开这个HTML文件。
 		</p>
 		</p>
 		<code>
 		<code>
 		&lt;!DOCTYPE html&gt;
 		&lt;!DOCTYPE html&gt;
@@ -69,7 +69,7 @@
 
 
 		<p>最后,我们将<strong>renderer</strong>(渲染器)这个元素添加到我们的HTML文档中,这也就是渲染器使用&lt;canvas&gt;元素来将场景展现给我们。</p>
 		<p>最后,我们将<strong>renderer</strong>(渲染器)这个元素添加到我们的HTML文档中,这也就是渲染器使用&lt;canvas&gt;元素来将场景展现给我们。</p>
 
 
-		<p><em>“嗯,看起来很不错,那你说的那个立方体在哪儿?”</em>我们接下来来对它继续进行添加。</p>
+		<p><em>“嗯,看起来很不错,那你说的那个立方体在哪儿?”</em>接下来,我们就来对它继续进行添加。</p>
 
 
 		<code>
 		<code>
 		var geometry = new THREE.BoxGeometry( 1, 1, 1 );
 		var geometry = new THREE.BoxGeometry( 1, 1, 1 );
@@ -80,9 +80,9 @@
 		camera.position.z = 5;
 		camera.position.z = 5;
 		</code>
 		</code>
 
 
-		<p>要创建一个立方体,我们需要一个<strong>BoxGeometry</strong>(立方体)对象. 这个对象包含了一个立方体中所有的顶点(<strong>vertices</strong>)和面<strong>faces</strong>。未来我们将在这方面进行更多的探索。</p>
+		<p>要创建一个立方体,我们需要一个<strong>BoxGeometry</strong>(立方体)对象. 这个对象包含了一个立方体中所有的顶点(<strong>vertices</strong>)和面<strong>faces</strong>。未来我们将在这方面进行更多的探索。</p>
 
 
-		<p>接下来,对于这个立方体,我们需要给它一个材质,来让它有颜色。Three.js自带了几种材质,在这里我们使用的是<strong>MeshBasicMaterial</strong>。所有的材质是都一个将会被应用于立方体的属性对象。在这里为了简单起见,我们只设置一个color属性,值为<strong>0x00ff00</strong>,也就是绿色。这里所做的事情,就相当于是在CSS或者Photoshop中使用十六进制(<strong>hex colors</strong>)的颜色格式来设置颜色。</p>
+		<p>接下来,对于这个立方体,我们需要给它一个材质,来让它有颜色。Three.js自带了几种材质,在这里我们使用的是<strong>MeshBasicMaterial</strong>。所有的材质是都一个将会被应用于立方体的属性对象。在这里为了简单起见,我们只设置一个color属性,值为<strong>0x00ff00</strong>,也就是绿色。这里所做的事情,就相当于是在CSS或者Photoshop中使用十六进制(<strong>hex colors</strong>)的颜色格式来设置颜色。</p>
 
 
 		<p>第三步,我们需要一个<strong>Mesh</strong>(网格)。 网格是包含有一个几何体以及应用在在此几何体上的材质的对象,我们可以直接将网格对象放入到我们的场景中,并让它在场景中自由移动。</p>
 		<p>第三步,我们需要一个<strong>Mesh</strong>(网格)。 网格是包含有一个几何体以及应用在在此几何体上的材质的对象,我们可以直接将网格对象放入到我们的场景中,并让它在场景中自由移动。</p>
 
 
@@ -105,7 +105,7 @@
 		<h2>使立方体动起来</h2>
 		<h2>使立方体动起来</h2>
 
 
 		<p>
 		<p>
-			在开始之前,如果你已经将上面的代码写入到了你所创建的文件中,你应当已经可以看到一个绿色的立方体。让我们来做一些更加有趣的事——让它旋转起来。</p>
+			在开始之前,如果你已经将上面的代码写入到了你所创建的文件中,你应当已经可以看到一个绿色的立方体。让我们来做一些更加有趣的事 —— 让它旋转起来。</p>
 
 
 		<p>将下列代码添加到animate()函数中<strong>renderer.render</strong>调用的上方:</p>
 		<p>将下列代码添加到animate()函数中<strong>renderer.render</strong>调用的上方:</p>
 
 

+ 125 - 0
docs/manual/zh/introduction/How-to-dispose-of-objects.html

@@ -0,0 +1,125 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+	<meta charset="utf-8">
+	<base href="../../../" />
+	<script src="list.js"></script>
+	<script src="page.js"></script>
+	<link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+	<h1>如何废置对象([name])</h1>
+	<br />
+
+	<p>
+		为了提高性能,并避免应用程序中的内存泄露,一个重要的方面是废置未使用的类库实体。
+		每当你创建一个*three.js*中的实例时,都会分配一定数量的内存。然而,*three.js*会创建在渲染中所必需的特定对象,
+		例如几何体或材质,以及与WebGL相关的实体,例如buffers或着色器程序。
+		非常值得注意的是,这些对象并不会被自动释放;相反,应用程序必须使用特殊的API来释放这些资源。
+		本指南简要概述了这一API是如何使用的,以及哪些对象是和这一环境相关的。
+	</p>
+
+	<h2>几何体</h2>
+
+	<p>
+		几何体常用来表示定义为属性集合的顶点信息,*three.js*在内部为每一个属性创建一个[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLBuffer WebGLBuffer]类型的对象。
+		这些实体仅有在调用[page:BufferGeometry.dispose]()的时候才会被删除。
+		如果应用程序中的几何体已废弃,请执行该方法以释放所有相关资源。
+	</p>
+
+	<h2>材质</h2>
+
+	<p>
+		材质定义了物体将如何被渲染。*three.js*使用材质所定义的信息来构造一个着色器程序,以用于渲染。
+		着色器程序只有在相应材质被废置后才能被删除。由于性能的原因,*three.js*尽可能尝试复用已存在的着色器程序。
+		因此,着色器程序只有在所有相关材质被废置后才被删除。
+		你可以通过执行[page:Material.dispose]()方法来废置材质。
+	</p>
+
+	<h2>纹理</h2>
+
+	<p>
+		对材质的废置不会对纹理造成影响。它们是分离的,因此一个纹理可以同时被多个材质所使用。
+		每当你创建一个[page:Texture]实例的时候,three.js在内部会创建一个[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture]实例。
+		和buffer相似,该对象只能通过调用[page:Texture.dispose]()来删除。
+	</p>
+
+	<h2>渲染目标</h2>
+
+	<p>
+		[page:WebGLRenderTarget]类型的对象不仅分配了[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture]的实例,
+		还分配了[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLFramebuffer WebGLFramebuffer]和[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderbuffer WebGLRenderbuffer]来实现自定义渲染目标。
+		这些对象仅能通过执行[page:WebGLRenderTarget.dispose]()来解除分配。
+	</p>
+
+	<h2>杂项</h2>
+
+	<p>
+		有一些来自examples目录的类,例如控制器或者后期处理过程,提供了*dispose()*方法以用于移除内部事件监听器或渲染目标。
+		通常来讲,非常建议查阅类的API或者文档,并注意*dispose()*。如果存在的话,你应当在清理时使用它。
+	</p>
+
+	<h2>常见问题</h2>
+
+	<h3>为何*three.js*不能够自动废置对象?</h3>
+
+	<p>
+		这一问题在社区中多次被问到,因此澄清这件事情是十分有必要的。事实是,*three.js*并不知道用户所创建的实体(例如几何体或者材质)的生命周期或作用范围,这些是应用程序的责任。
+		比如说,即使一个材质当前没有被用于渲染,但它也可能是下一帧所必需的。
+		因此,如果应用程序决定某个对象可以被删除,则它必须通过调用对应的*dispose()*方法来通知引擎。
+	</p>
+
+	<h3>将一个mesh(网格)从场景中移除,是否也会废置它的geometry(几何体)和material(材质)?</h3>
+
+	<p>
+		并不会,你必须通过*dispose()*来明确地废置geometry(几何体)或material(材质)。
+		请记住,eometry(几何体)或material(材质)可以在3D物体之间(例如mesh(网格))被共享。
+	</p>
+
+	<h3>*three.js*是否会提供被缓存对象数量的相关信息?</h3>
+
+	<p>
+		是的,可以评估[page:WebGLRenderer.info] —— 渲染器中的一个特殊属性,具有一系列关于显存和渲染过程的统计信息。
+		除此之外,它还告诉你有多少纹理、几何体和着色器程序在内部存储。
+		如果你在你的应用程序中注意到了性能问题,一个较好的方法便是调试该属性,以便轻松识别内存泄漏。
+	</p>
+
+	<p>
+		对于纹理的内部资源仅在图像完全被加载后才会分配。如果你在图像被加载之前废置纹理,什么都不会发生。
+		没有资源被分配,因此也没有必要进行清理。
+	</p>
+
+	<h3>当你在纹理还没有被加载时,在纹理上调用*dispose()*,会发生什么?</h3>
+
+	<p>
+		对于纹理的内部资源仅在图像完全被加载后才会分配。如果你在图像被加载之前废置纹理,什么都不会发生。
+		没有资源被分配,因此也没有必要进行清理。
+	</p>
+
+	<h3>当我在调用*dispose()*之后,使用相应的对象会发生什么?</h3>
+
+	<p>
+		被删除掉的内部资源会被引擎重新创建,因此不会有运行时错误发生,但你可能会注意到这会对当前帧的性能有一些影响,特别是当着色器程序被编译的时候。
+	</p>
+
+	<h3>我如何在我的应用程序中管理*three.js*中的对象?我如何知道什么时候该废置事物?</h3>
+
+	<p>
+		一般来说,对此并没有明确的建议。调用*dispose()*什么时候合适,很大程度上取决于具体的用例。
+		必须指出的是,没有必要总是废置对象。一个较好的例子便是一个由多个关卡所组成的游戏。使用到对象废置的地方就是当切换关卡的时候。
+		应用程序可以通过较老的场景,并废置所有过时的材质、几何体和纹理贴图。
+		正如在前面的章节中所提到,如果你废置一个仍然在使用的对象,并不会导致运行时错误。可能发生的最糟糕的事情便是单帧的性能会下降。
+	</p>
+
+	<h2>演示dispose()使用方法的示例</h2>
+
+	<p>
+		[example:webgl_test_memory WebGL / test / memory]<br />
+		[example:webgl_test_memory2 WebGL / test / memory2]<br />
+	</p>
+
+</body>
+
+</html>

+ 2 - 2
docs/manual/zh/introduction/How-to-run-things-locally.html

@@ -25,10 +25,10 @@
 
 
 			<ol>
 			<ol>
 				<li>
 				<li>
-                    在浏览器中改变本地文件的安全策略,这将使你可以通过<code>file:///yourFile.html</code>来直接运行*本地文件系统*中的文件。
+                    在浏览器中改变本地文件的安全策略,这将使你可以通过<code>file:///yourFile.html</code>来直接运行本地文件系统中的文件。
 				</li>
 				</li>
 				<li>
 				<li>
-                    从本地的服务器运行文件,这可以让你通过<code>http://localhost/yourFile.html</code>来访问运行在*本地服务器*上的文件。
+                    从本地的服务器运行文件,这可以让你通过<code>http://localhost/yourFile.html</code>来访问运行在本地服务器上的文件。
 				</li>
 				</li>
 			</ol>
 			</ol>
 
 

+ 2 - 4
editor/index.html

@@ -4,10 +4,8 @@
 		<title>three.js / editor</title>
 		<title>three.js / editor</title>
 		<meta charset="utf-8">
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-		<!-- Origin Trial Token, feature = WebXR Device API (For Chrome M69+), origin = https://threejs.org, expires = 2019-01-23 -->
-		<meta http-equiv="origin-trial" data-feature="WebXR Device API (For Chrome M69+)" data-expires="2019-01-23" content="ApibcCZfaeEIkwpe6CSIKZXC8ODly5nYX+QlUSgwhUUlMN1/Ko7dr5XUwZDFl9SiEGtOFFe2csLwnNg33ZBh+QMAAABTeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJYUkRldmljZU02OSIsImV4cGlyeSI6MTU0ODIwMTU5OX0=">
-		<!-- Origin Trial Token, feature = WebXR Gamepad Support, origin = https://threejs.org, expires = 2019-01-23 -->
-		<meta http-equiv="origin-trial" data-feature="WebXR Gamepad Support" data-expires="2019-01-23" content="Agt5pp1xG96NMH+7RdcD7jvbkJiJTagqfKtC+28x/TBeQSh4tF7ad7uXL9Clqbts0vivamPTTkRkNdyfJtEezQ4AAABYeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJYUkdhbWVwYWRTdXBwb3J0IiwiZXhwaXJ5IjoxNTQ4MjAxNTk5fQ==">
+		<!-- Origin Trial Token, feature = WebXR Device API (For Chrome M69+), origin = https://threejs.org, expires = 2019-03-06 -->
+		<meta http-equiv="origin-trial" data-feature="WebXR Device API (For Chrome M69+)" data-expires="2019-03-06" content="AvDjbxYpoTgOL1PS0JEra7KFCehfTlKnXpU/ORSwNdCQ35cX70cTUkXOnQ26A5XJi3eXHSKpBPchdt5lbcxDuAIAAABTeyJvcmlnaW4iOiJodHRwczovL3RocmVlanMub3JnOjQ0MyIsImZlYXR1cmUiOiJXZWJYUkRldmljZU02OSIsImV4cGlyeSI6MTU1MTgzMDM5OX0=">
 	</head>
 	</head>
 	<body ontouchstart="">
 	<body ontouchstart="">
 		<link href="css/main.css" rel="stylesheet" />
 		<link href="css/main.css" rel="stylesheet" />

+ 12 - 0
editor/js/Editor.js

@@ -93,6 +93,9 @@ var Editor = function () {
 	this.textures = {};
 	this.textures = {};
 	this.scripts = {};
 	this.scripts = {};
 
 
+	this.animations = {};
+	this.animationMixer = new THREE.AnimationMixer( this.scene );
+
 	this.selected = null;
 	this.selected = null;
 	this.helpers = {};
 	this.helpers = {};
 
 
@@ -239,6 +242,12 @@ Editor.prototype = {
 
 
 	},
 	},
 
 
+	addAnimation: function ( object, animations ) {
+
+		this.animations[ object.uuid ] = animations;
+
+	},
+
 	//
 	//
 
 
 	addHelper: function () {
 	addHelper: function () {
@@ -459,6 +468,9 @@ Editor.prototype = {
 		this.materials = {};
 		this.materials = {};
 		this.textures = {};
 		this.textures = {};
 		this.scripts = {};
 		this.scripts = {};
+		
+		this.animations = {};
+		this.animationMixer.stopAllAction();
 
 
 		this.deselect();
 		this.deselect();
 
 

+ 22 - 9
editor/js/Loader.js

@@ -34,7 +34,7 @@ var Loader = function ( editor ) {
 
 
 			for ( var i = 0; i < files.length; i ++ ) {
 			for ( var i = 0; i < files.length; i ++ ) {
 
 
-				scope.loadFile( files[ i ], manager ) ;
+				scope.loadFile( files[ i ], manager );
 
 
 			}
 			}
 
 
@@ -150,7 +150,7 @@ var Loader = function ( editor ) {
 					stream.offset = 0;
 					stream.offset = 0;
 
 
 					var loader = new THREE.CTMLoader();
 					var loader = new THREE.CTMLoader();
-					loader.createModel( new CTM.File( stream ), function( geometry ) {
+					loader.createModel( new CTM.File( stream ), function ( geometry ) {
 
 
 						geometry.sourceType = "ctm";
 						geometry.sourceType = "ctm";
 						geometry.sourceFile = file.name;
 						geometry.sourceFile = file.name;
@@ -215,8 +215,11 @@ var Loader = function ( editor ) {
 					loader.setDRACOLoader( new THREE.DRACOLoader() );
 					loader.setDRACOLoader( new THREE.DRACOLoader() );
 					loader.parse( contents, '', function ( result ) {
 					loader.parse( contents, '', function ( result ) {
 
 
-						result.scene.name = filename;
-						editor.execute( new AddObjectCommand( result.scene ) );
+						var scene = result.scene;
+						scene.name = filename;
+
+						editor.addAnimation( scene, result.animations );
+						editor.execute( new AddObjectCommand( scene ) );
 
 
 					} );
 					} );
 
 
@@ -245,8 +248,11 @@ var Loader = function ( editor ) {
 
 
 					loader.parse( contents, '', function ( result ) {
 					loader.parse( contents, '', function ( result ) {
 
 
-						result.scene.name = filename;
-						editor.execute( new AddObjectCommand( result.scene ) );
+						var scene = result.scene;
+						scene.name = filename;
+
+						editor.addAnimation( scene, result.animations );
+						editor.execute( new AddObjectCommand( scene ) );
 
 
 					} );
 					} );
 
 
@@ -344,6 +350,7 @@ var Loader = function ( editor ) {
 					mesh.mixer = new THREE.AnimationMixer( mesh );
 					mesh.mixer = new THREE.AnimationMixer( mesh );
 					mesh.name = filename;
 					mesh.name = filename;
 
 
+					editor.addAnimation( mesh, geometry.animations );
 					editor.execute( new AddObjectCommand( mesh ) );
 					editor.execute( new AddObjectCommand( mesh ) );
 
 
 				}, false );
 				}, false );
@@ -450,7 +457,7 @@ var Loader = function ( editor ) {
 
 
 					var group = new THREE.Group();
 					var group = new THREE.Group();
 					group.scale.multiplyScalar( 0.1 );
 					group.scale.multiplyScalar( 0.1 );
-					group.scale.y *= -1;
+					group.scale.y *= - 1;
 
 
 					for ( var i = 0; i < paths.length; i ++ ) {
 					for ( var i = 0; i < paths.length; i ++ ) {
 
 
@@ -678,7 +685,10 @@ var Loader = function ( editor ) {
 					var loader = new THREE.GLTFLoader();
 					var loader = new THREE.GLTFLoader();
 					loader.parse( file.asArrayBuffer(), '', function ( result ) {
 					loader.parse( file.asArrayBuffer(), '', function ( result ) {
 
 
-						editor.execute( new AddObjectCommand( result.scene ) );
+						var scene = result.scene;
+
+						editor.addAnimation( scene, result.animations );
+						editor.execute( new AddObjectCommand( scene ) );
 
 
 					} );
 					} );
 
 
@@ -689,7 +699,10 @@ var Loader = function ( editor ) {
 					var loader = new THREE.GLTFLoader( manager );
 					var loader = new THREE.GLTFLoader( manager );
 					loader.parse( file.asText(), '', function ( result ) {
 					loader.parse( file.asText(), '', function ( result ) {
 
 
-						editor.execute( new AddObjectCommand( result.scene ) );
+						var scene = result.scene;
+
+						editor.addAnimation( scene, result.animations );
+						editor.execute( new AddObjectCommand( scene ) );
 
 
 					} );
 					} );
 
 

+ 65 - 5
editor/js/Sidebar.Animation.js

@@ -5,19 +5,79 @@
 Sidebar.Animation = function ( editor ) {
 Sidebar.Animation = function ( editor ) {
 
 
 	var signals = editor.signals;
 	var signals = editor.signals;
+	var mixer = editor.animationMixer;
 
 
-	var options = {};
-	var possibleAnimations = {};
+	var actions = {};
+
+	signals.objectSelected.add( function ( object ) {
+
+		var animations = editor.animations[ object !== null ? object.uuid : '' ];
+
+		if ( animations !== undefined ) {
+
+			container.setDisplay( '' );
+
+			var options = {};
+			var firstAnimation;
+
+			for ( var animation of animations ) {
+
+				if ( firstAnimation === undefined ) firstAnimation = animation.name;
+
+				actions[ animation.name ] = mixer.clipAction( animation, object );
+				options[ animation.name ] = animation.name;
+
+			}
+
+			animationsSelect.setOptions( options );
+			animationsSelect.setValue( firstAnimation );
+
+		} else {
+
+			container.setDisplay( 'none' );
+
+		}
+
+	} );
+
+	signals.objectRemoved.add( function ( object ) {
+
+		var animations = editor.animations[ object !== null ? object.uuid : '' ];
+
+		if ( animations !== undefined ) {
+
+			mixer.uncacheRoot( object );
+
+		}
+
+	} );
+
+	function playAction() {
+
+		actions[ animationsSelect.getValue() ].play();
+
+	}
+
+	function stopAction() {
+
+		actions[ animationsSelect.getValue() ].stop();
+
+	}
 
 
 	var container = new UI.Panel();
 	var container = new UI.Panel();
 	container.setDisplay( 'none' );
 	container.setDisplay( 'none' );
 
 
-	container.add( new UI.Text( 'Animation' ).setTextTransform( 'uppercase' ) );
+	container.add( new UI.Text( 'Animations' ).setTextTransform( 'uppercase' ) );
 	container.add( new UI.Break() );
 	container.add( new UI.Break() );
 	container.add( new UI.Break() );
 	container.add( new UI.Break() );
 
 
-	var animationsRow = new UI.Row();
-	container.add( animationsRow );
+	var div = new UI.Div();
+	container.add( div );
+
+	var animationsSelect = new UI.Select().setFontSize( '12px' );
+	div.add( animationsSelect );
+	div.add( new UI.Button( 'Play' ).setMarginLeft( '4px' ).onClick( playAction ) );
+	div.add( new UI.Button( 'Stop' ).setMarginLeft( '4px' ).onClick( stopAction ) );
 
 
 	return container;
 	return container;
 
 

+ 23 - 0
editor/js/Viewport.js

@@ -519,6 +519,29 @@ var Viewport = function ( editor ) {
 
 
 	} );
 	} );
 
 
+	// animations
+
+	var prevTime = performance.now();
+
+	function animate( time ) {
+
+		requestAnimationFrame( animate );
+
+		var mixer = editor.animationMixer;
+
+		if ( mixer.stats.actions.inUse > 0 ) {
+
+			editor.animationMixer.update( ( time - prevTime ) / 1000 );
+			render();
+
+		}
+
+		prevTime = time;
+
+	}
+
+	requestAnimationFrame( animate );
+
 	//
 	//
 
 
 	function render() {
 	function render() {

+ 5 - 5
editor/js/libs/ui.js

@@ -115,8 +115,8 @@ UI.Element.prototype = {
 // properties
 // properties
 
 
 var properties = [ 'position', 'left', 'top', 'right', 'bottom', 'width', 'height', 'border', 'borderLeft',
 var properties = [ 'position', 'left', 'top', 'right', 'bottom', 'width', 'height', 'border', 'borderLeft',
-'borderTop', 'borderRight', 'borderBottom', 'borderColor', 'display', 'overflow', 'margin', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'color',
-'background', 'backgroundColor', 'opacity', 'fontSize', 'fontWeight', 'textAlign', 'textDecoration', 'textTransform', 'cursor', 'zIndex' ];
+	'borderTop', 'borderRight', 'borderBottom', 'borderColor', 'display', 'overflow', 'margin', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'color',
+	'background', 'backgroundColor', 'opacity', 'fontSize', 'fontWeight', 'textAlign', 'textDecoration', 'textTransform', 'cursor', 'zIndex' ];
 
 
 properties.forEach( function ( property ) {
 properties.forEach( function ( property ) {
 
 
@@ -863,9 +863,9 @@ UI.Integer.prototype.setValue = function ( value ) {
 };
 };
 
 
 UI.Integer.prototype.setStep = function ( step ) {
 UI.Integer.prototype.setStep = function ( step ) {
-	
-	this.step = parseInt( step ); 
-	
+
+	this.step = parseInt( step );
+
 	return this;
 	return this;
 
 
 };
 };

+ 1 - 0
examples/files.js

@@ -19,6 +19,7 @@ var files = {
 		"webgl_effects_peppersghost",
 		"webgl_effects_peppersghost",
 		"webgl_effects_stereo",
 		"webgl_effects_stereo",
 		"webgl_framebuffer_texture",
 		"webgl_framebuffer_texture",
+		"webgl_furnace_test",
 		"webgl_geometries",
 		"webgl_geometries",
 		"webgl_geometries_parametric",
 		"webgl_geometries_parametric",
 		"webgl_geometry_colors",
 		"webgl_geometry_colors",

+ 8 - 2
examples/js/GPUComputationRenderer.js

@@ -277,7 +277,9 @@ function GPUComputationRenderer( sizeX, sizeY, renderer ) {
 		addResolutionDefine( material );
 		addResolutionDefine( material );
 
 
 		return material;
 		return material;
+
 	}
 	}
+
 	this.createShaderMaterial = createShaderMaterial;
 	this.createShaderMaterial = createShaderMaterial;
 
 
 	this.createRenderTarget = function( sizeXTexture, sizeYTexture, wrapS, wrapT, minFilter, magFilter ) {
 	this.createRenderTarget = function( sizeXTexture, sizeYTexture, wrapS, wrapT, minFilter, magFilter ) {
@@ -316,7 +318,6 @@ function GPUComputationRenderer( sizeX, sizeY, renderer ) {
 
 
 	};
 	};
 
 
-
 	this.renderTexture = function( input, output ) {
 	this.renderTexture = function( input, output ) {
 
 
 		// Takes a texture, and render out in rendertarget
 		// Takes a texture, and render out in rendertarget
@@ -333,10 +334,15 @@ function GPUComputationRenderer( sizeX, sizeY, renderer ) {
 
 
 	this.doRenderTarget = function( material, output ) {
 	this.doRenderTarget = function( material, output ) {
 
 
+		var currentRenderTarget = renderer.getRenderTarget();
+
 		mesh.material = material;
 		mesh.material = material;
-		renderer.render( scene, camera, output );
+		renderer.setRenderTarget( output );
+		renderer.render( scene, camera );
 		mesh.material = passThruShader;
 		mesh.material = passThruShader;
 
 
+		renderer.setRenderTarget( currentRenderTarget );
+
 	};
 	};
 
 
 	// Shaders
 	// Shaders

+ 39 - 14
examples/js/Ocean.js

@@ -212,6 +212,8 @@ THREE.Ocean.prototype.generateMesh = function () {
 
 
 THREE.Ocean.prototype.render = function () {
 THREE.Ocean.prototype.render = function () {
 
 
+	var currentRenderTarget = this.renderer.getRenderTarget();
+
 	this.scene.overrideMaterial = null;
 	this.scene.overrideMaterial = null;
 
 
 	if ( this.changed )
 	if ( this.changed )
@@ -223,9 +225,11 @@ THREE.Ocean.prototype.render = function () {
 	this.renderNormalMap();
 	this.renderNormalMap();
 	this.scene.overrideMaterial = null;
 	this.scene.overrideMaterial = null;
 
 
+	this.renderer.setRenderTarget( currentRenderTarget );
+
 };
 };
 
 
-THREE.Ocean.prototype.generateSeedPhaseTexture = function() {
+THREE.Ocean.prototype.generateSeedPhaseTexture = function () {
 
 
 	// Setup the seed texture
 	// Setup the seed texture
 	this.pingPhase = true;
 	this.pingPhase = true;
@@ -234,7 +238,7 @@ THREE.Ocean.prototype.generateSeedPhaseTexture = function() {
 
 
 		for ( var j = 0; j < this.resolution; j ++ ) {
 		for ( var j = 0; j < this.resolution; j ++ ) {
 
 
-			phaseArray[ i * this.resolution * 4 + j * 4 ] =  Math.random() * 2.0 * Math.PI;
+			phaseArray[ i * this.resolution * 4 + j * 4 ] = Math.random() * 2.0 * Math.PI;
 			phaseArray[ i * this.resolution * 4 + j * 4 + 1 ] = 0.0;
 			phaseArray[ i * this.resolution * 4 + j * 4 + 1 ] = 0.0;
 			phaseArray[ i * this.resolution * 4 + j * 4 + 2 ] = 0.0;
 			phaseArray[ i * this.resolution * 4 + j * 4 + 2 ] = 0.0;
 			phaseArray[ i * this.resolution * 4 + j * 4 + 3 ] = 0.0;
 			phaseArray[ i * this.resolution * 4 + j * 4 + 3 ] = 0.0;
@@ -256,7 +260,10 @@ THREE.Ocean.prototype.renderInitialSpectrum = function () {
 	this.scene.overrideMaterial = this.materialInitialSpectrum;
 	this.scene.overrideMaterial = this.materialInitialSpectrum;
 	this.materialInitialSpectrum.uniforms.u_wind.value.set( this.windX, this.windY );
 	this.materialInitialSpectrum.uniforms.u_wind.value.set( this.windX, this.windY );
 	this.materialInitialSpectrum.uniforms.u_size.value = this.size;
 	this.materialInitialSpectrum.uniforms.u_size.value = this.size;
-	this.renderer.render( this.scene, this.oceanCamera, this.initialSpectrumFramebuffer, true );
+
+	this.renderer.setRenderTarget( this.initialSpectrumFramebuffer );
+	this.renderer.clear();
+	this.renderer.render( this.scene, this.oceanCamera );
 
 
 };
 };
 
 
@@ -269,14 +276,15 @@ THREE.Ocean.prototype.renderWavePhase = function () {
 		this.materialPhase.uniforms.u_phases.value = this.pingPhaseTexture;
 		this.materialPhase.uniforms.u_phases.value = this.pingPhaseTexture;
 		this.initial = false;
 		this.initial = false;
 
 
-	}else {
+	} else {
 
 
 		this.materialPhase.uniforms.u_phases.value = this.pingPhase ? this.pingPhaseFramebuffer.texture : this.pongPhaseFramebuffer.texture;
 		this.materialPhase.uniforms.u_phases.value = this.pingPhase ? this.pingPhaseFramebuffer.texture : this.pongPhaseFramebuffer.texture;
 
 
 	}
 	}
 	this.materialPhase.uniforms.u_deltaTime.value = this.deltaTime;
 	this.materialPhase.uniforms.u_deltaTime.value = this.deltaTime;
 	this.materialPhase.uniforms.u_size.value = this.size;
 	this.materialPhase.uniforms.u_size.value = this.size;
-	this.renderer.render( this.scene, this.oceanCamera, this.pingPhase ? this.pongPhaseFramebuffer : this.pingPhaseFramebuffer );
+	this.renderer.setRenderTarget( this.pingPhase ? this.pongPhaseFramebuffer : this.pingPhaseFramebuffer );
+	this.renderer.render( this.scene, this.oceanCamera );
 	this.pingPhase = ! this.pingPhase;
 	this.pingPhase = ! this.pingPhase;
 
 
 };
 };
@@ -288,11 +296,13 @@ THREE.Ocean.prototype.renderSpectrum = function () {
 	this.materialSpectrum.uniforms.u_phases.value = this.pingPhase ? this.pingPhaseFramebuffer.texture : this.pongPhaseFramebuffer.texture;
 	this.materialSpectrum.uniforms.u_phases.value = this.pingPhase ? this.pingPhaseFramebuffer.texture : this.pongPhaseFramebuffer.texture;
 	this.materialSpectrum.uniforms.u_choppiness.value = this.choppiness;
 	this.materialSpectrum.uniforms.u_choppiness.value = this.choppiness;
 	this.materialSpectrum.uniforms.u_size.value = this.size;
 	this.materialSpectrum.uniforms.u_size.value = this.size;
-	this.renderer.render( this.scene, this.oceanCamera, this.spectrumFramebuffer );
+
+	this.renderer.setRenderTarget( this.spectrumFramebuffer );
+	this.renderer.render( this.scene, this.oceanCamera );
 
 
 };
 };
 
 
-THREE.Ocean.prototype.renderSpectrumFFT = function() {
+THREE.Ocean.prototype.renderSpectrumFFT = function () {
 
 
 	// GPU FFT using Stockham formulation
 	// GPU FFT using Stockham formulation
 	var iterations = Math.log( this.resolution ) / Math.log( 2 ); // log2
 	var iterations = Math.log( this.resolution ) / Math.log( 2 ); // log2
@@ -305,19 +315,25 @@ THREE.Ocean.prototype.renderSpectrumFFT = function() {
 
 
 			this.materialOceanHorizontal.uniforms.u_input.value = this.spectrumFramebuffer.texture;
 			this.materialOceanHorizontal.uniforms.u_input.value = this.spectrumFramebuffer.texture;
 			this.materialOceanHorizontal.uniforms.u_subtransformSize.value = Math.pow( 2, ( i % ( iterations ) ) + 1 );
 			this.materialOceanHorizontal.uniforms.u_subtransformSize.value = Math.pow( 2, ( i % ( iterations ) ) + 1 );
-			this.renderer.render( this.scene, this.oceanCamera, this.pingTransformFramebuffer );
+
+			this.renderer.setRenderTarget( this.pingTransformFramebuffer );
+			this.renderer.render( this.scene, this.oceanCamera );
 
 
 		} else if ( i % 2 === 1 ) {
 		} else if ( i % 2 === 1 ) {
 
 
 			this.materialOceanHorizontal.uniforms.u_input.value = this.pingTransformFramebuffer.texture;
 			this.materialOceanHorizontal.uniforms.u_input.value = this.pingTransformFramebuffer.texture;
 			this.materialOceanHorizontal.uniforms.u_subtransformSize.value = Math.pow( 2, ( i % ( iterations ) ) + 1 );
 			this.materialOceanHorizontal.uniforms.u_subtransformSize.value = Math.pow( 2, ( i % ( iterations ) ) + 1 );
-			this.renderer.render( this.scene, this.oceanCamera, this.pongTransformFramebuffer );
+
+			this.renderer.setRenderTarget( this.pongTransformFramebuffer );
+			this.renderer.render( this.scene, this.oceanCamera );
 
 
 		} else {
 		} else {
 
 
 			this.materialOceanHorizontal.uniforms.u_input.value = this.pongTransformFramebuffer.texture;
 			this.materialOceanHorizontal.uniforms.u_input.value = this.pongTransformFramebuffer.texture;
 			this.materialOceanHorizontal.uniforms.u_subtransformSize.value = Math.pow( 2, ( i % ( iterations ) ) + 1 );
 			this.materialOceanHorizontal.uniforms.u_subtransformSize.value = Math.pow( 2, ( i % ( iterations ) ) + 1 );
-			this.renderer.render( this.scene, this.oceanCamera, this.pingTransformFramebuffer );
+
+			this.renderer.setRenderTarget( this.pingTransformFramebuffer );
+			this.renderer.render( this.scene, this.oceanCamera );
 
 
 		}
 		}
 
 
@@ -329,19 +345,25 @@ THREE.Ocean.prototype.renderSpectrumFFT = function() {
 
 
 			this.materialOceanVertical.uniforms.u_input.value = ( iterations % 2 === 0 ) ? this.pingTransformFramebuffer.texture : this.pongTransformFramebuffer.texture;
 			this.materialOceanVertical.uniforms.u_input.value = ( iterations % 2 === 0 ) ? this.pingTransformFramebuffer.texture : this.pongTransformFramebuffer.texture;
 			this.materialOceanVertical.uniforms.u_subtransformSize.value = Math.pow( 2, ( i % ( iterations ) ) + 1 );
 			this.materialOceanVertical.uniforms.u_subtransformSize.value = Math.pow( 2, ( i % ( iterations ) ) + 1 );
-			this.renderer.render( this.scene, this.oceanCamera, this.displacementMapFramebuffer );
+
+			this.renderer.setRenderTarget( this.displacementMapFramebuffer );
+			this.renderer.render( this.scene, this.oceanCamera );
 
 
 		} else if ( i % 2 === 1 ) {
 		} else if ( i % 2 === 1 ) {
 
 
 			this.materialOceanVertical.uniforms.u_input.value = this.pingTransformFramebuffer.texture;
 			this.materialOceanVertical.uniforms.u_input.value = this.pingTransformFramebuffer.texture;
 			this.materialOceanVertical.uniforms.u_subtransformSize.value = Math.pow( 2, ( i % ( iterations ) ) + 1 );
 			this.materialOceanVertical.uniforms.u_subtransformSize.value = Math.pow( 2, ( i % ( iterations ) ) + 1 );
-			this.renderer.render( this.scene, this.oceanCamera, this.pongTransformFramebuffer );
+
+			this.renderer.setRenderTarget( this.pongTransformFramebuffer );
+			this.renderer.render( this.scene, this.oceanCamera );
 
 
 		} else {
 		} else {
 
 
 			this.materialOceanVertical.uniforms.u_input.value = this.pongTransformFramebuffer.texture;
 			this.materialOceanVertical.uniforms.u_input.value = this.pongTransformFramebuffer.texture;
 			this.materialOceanVertical.uniforms.u_subtransformSize.value = Math.pow( 2, ( i % ( iterations ) ) + 1 );
 			this.materialOceanVertical.uniforms.u_subtransformSize.value = Math.pow( 2, ( i % ( iterations ) ) + 1 );
-			this.renderer.render( this.scene, this.oceanCamera, this.pingTransformFramebuffer );
+
+			this.renderer.setRenderTarget( this.pingTransformFramebuffer );
+			this.renderer.render( this.scene, this.oceanCamera );
 
 
 		}
 		}
 
 
@@ -354,6 +376,9 @@ THREE.Ocean.prototype.renderNormalMap = function () {
 	this.scene.overrideMaterial = this.materialNormal;
 	this.scene.overrideMaterial = this.materialNormal;
 	if ( this.changed ) this.materialNormal.uniforms.u_size.value = this.size;
 	if ( this.changed ) this.materialNormal.uniforms.u_size.value = this.size;
 	this.materialNormal.uniforms.u_displacementMap.value = this.displacementMapFramebuffer.texture;
 	this.materialNormal.uniforms.u_displacementMap.value = this.displacementMapFramebuffer.texture;
-	this.renderer.render( this.scene, this.oceanCamera, this.normalMapFramebuffer, true );
+
+	this.renderer.setRenderTarget( this.normalMapFramebuffer );
+	this.renderer.clear();
+	this.renderer.render( this.scene, this.oceanCamera );
 
 
 };
 };

+ 11 - 2
examples/js/cameras/CinematicCamera.js

@@ -177,22 +177,31 @@ THREE.CinematicCamera.prototype.renderCinematic = function ( scene, renderer ) {
 
 
 	if ( this.postprocessing.enabled ) {
 	if ( this.postprocessing.enabled ) {
 
 
+		var currentRenderTarget = renderer.getRenderTarget();
+
 		renderer.clear();
 		renderer.clear();
 
 
 		// Render scene into texture
 		// Render scene into texture
 
 
 		scene.overrideMaterial = null;
 		scene.overrideMaterial = null;
-		renderer.render( scene, camera, this.postprocessing.rtTextureColor, true );
+		renderer.setRenderTarget( this.postprocessing.rtTextureColor );
+		renderer.clear();
+		renderer.render( scene, camera );
 
 
 		// Render depth into texture
 		// Render depth into texture
 
 
 		scene.overrideMaterial = this.materialDepth;
 		scene.overrideMaterial = this.materialDepth;
-		renderer.render( scene, camera, this.postprocessing.rtTextureDepth, true );
+		renderer.setRenderTarget( this.postprocessing.rtTextureDepth );
+		renderer.clear();
+		renderer.render( scene, camera );
 
 
 		// Render bokeh composite
 		// Render bokeh composite
 
 
+		renderer.setRenderTarget( null );
 		renderer.render( this.postprocessing.scene, this.postprocessing.camera );
 		renderer.render( this.postprocessing.scene, this.postprocessing.camera );
 
 
+		renderer.setRenderTarget( currentRenderTarget );
+
 	}
 	}
 
 
 };
 };

+ 87 - 45
examples/js/controls/FirstPersonControls.js

@@ -7,7 +7,6 @@
 THREE.FirstPersonControls = function ( object, domElement ) {
 THREE.FirstPersonControls = function ( object, domElement ) {
 
 
 	this.object = object;
 	this.object = object;
-	this.target = new THREE.Vector3( 0, 0, 0 );
 
 
 	this.domElement = ( domElement !== undefined ) ? domElement : document;
 	this.domElement = ( domElement !== undefined ) ? domElement : document;
 
 
@@ -35,11 +34,6 @@ THREE.FirstPersonControls = function ( object, domElement ) {
 	this.mouseX = 0;
 	this.mouseX = 0;
 	this.mouseY = 0;
 	this.mouseY = 0;
 
 
-	this.lat = 0;
-	this.lon = 0;
-	this.phi = 0;
-	this.theta = 0;
-
 	this.moveForward = false;
 	this.moveForward = false;
 	this.moveBackward = false;
 	this.moveBackward = false;
 	this.moveLeft = false;
 	this.moveLeft = false;
@@ -50,6 +44,17 @@ THREE.FirstPersonControls = function ( object, domElement ) {
 	this.viewHalfX = 0;
 	this.viewHalfX = 0;
 	this.viewHalfY = 0;
 	this.viewHalfY = 0;
 
 
+	// private variables
+
+	var lat = 0;
+	var lon = 0;
+
+	var lookDirection = new THREE.Vector3();
+	var spherical = new THREE.Spherical();
+	var target = new THREE.Vector3();
+
+	//
+
 	if ( this.domElement !== document ) {
 	if ( this.domElement !== document ) {
 
 
 		this.domElement.setAttribute( 'tabindex', - 1 );
 		this.domElement.setAttribute( 'tabindex', - 1 );
@@ -184,74 +189,97 @@ THREE.FirstPersonControls = function ( object, domElement ) {
 
 
 	};
 	};
 
 
-	this.update = function ( delta ) {
-
-		if ( this.enabled === false ) return;
-
-		if ( this.heightSpeed ) {
+	this.lookAt = function ( x, y, z ) {
 
 
-			var y = THREE.Math.clamp( this.object.position.y, this.heightMin, this.heightMax );
-			var heightDelta = y - this.heightMin;
+		if ( x.isVector3 ) {
 
 
-			this.autoSpeedFactor = delta * ( heightDelta * this.heightCoef );
+			target.copy( x );
 
 
 		} else {
 		} else {
 
 
-			this.autoSpeedFactor = 0.0;
+			target.set( x, y, z );
 
 
 		}
 		}
 
 
-		var actualMoveSpeed = delta * this.movementSpeed;
+		this.object.lookAt( target );
 
 
-		if ( this.moveForward || ( this.autoForward && ! this.moveBackward ) ) this.object.translateZ( - ( actualMoveSpeed + this.autoSpeedFactor ) );
-		if ( this.moveBackward ) this.object.translateZ( actualMoveSpeed );
+		setOrientation( this );
 
 
-		if ( this.moveLeft ) this.object.translateX( - actualMoveSpeed );
-		if ( this.moveRight ) this.object.translateX( actualMoveSpeed );
+		return this;
 
 
-		if ( this.moveUp ) this.object.translateY( actualMoveSpeed );
-		if ( this.moveDown ) this.object.translateY( - actualMoveSpeed );
+	};
 
 
-		var actualLookSpeed = delta * this.lookSpeed;
+	this.update = function () {
 
 
-		if ( ! this.activeLook ) {
+		var targetPosition = new THREE.Vector3();
 
 
-			actualLookSpeed = 0;
+		return function update( delta ) {
 
 
-		}
+			if ( this.enabled === false ) return;
 
 
-		var verticalLookRatio = 1;
+			if ( this.heightSpeed ) {
 
 
-		if ( this.constrainVertical ) {
+				var y = THREE.Math.clamp( this.object.position.y, this.heightMin, this.heightMax );
+				var heightDelta = y - this.heightMin;
 
 
-			verticalLookRatio = Math.PI / ( this.verticalMax - this.verticalMin );
+				this.autoSpeedFactor = delta * ( heightDelta * this.heightCoef );
 
 
-		}
+			} else {
 
 
-		this.lon += this.mouseX * actualLookSpeed;
-		if ( this.lookVertical ) this.lat -= this.mouseY * actualLookSpeed * verticalLookRatio;
+				this.autoSpeedFactor = 0.0;
 
 
-		this.lat = Math.max( - 85, Math.min( 85, this.lat ) );
-		this.phi = THREE.Math.degToRad( 90 - this.lat );
+			}
 
 
-		this.theta = THREE.Math.degToRad( this.lon );
+			var actualMoveSpeed = delta * this.movementSpeed;
 
 
-		if ( this.constrainVertical ) {
+			if ( this.moveForward || ( this.autoForward && ! this.moveBackward ) ) this.object.translateZ( - ( actualMoveSpeed + this.autoSpeedFactor ) );
+			if ( this.moveBackward ) this.object.translateZ( actualMoveSpeed );
 
 
-			this.phi = THREE.Math.mapLinear( this.phi, 0, Math.PI, this.verticalMin, this.verticalMax );
+			if ( this.moveLeft ) this.object.translateX( - actualMoveSpeed );
+			if ( this.moveRight ) this.object.translateX( actualMoveSpeed );
 
 
-		}
+			if ( this.moveUp ) this.object.translateY( actualMoveSpeed );
+			if ( this.moveDown ) this.object.translateY( - actualMoveSpeed );
 
 
-		var targetPosition = this.target,
-			position = this.object.position;
+			var actualLookSpeed = delta * this.lookSpeed;
 
 
-		targetPosition.x = position.x + 100 * Math.sin( this.phi ) * Math.cos( this.theta );
-		targetPosition.y = position.y + 100 * Math.cos( this.phi );
-		targetPosition.z = position.z + 100 * Math.sin( this.phi ) * Math.sin( this.theta );
+			if ( ! this.activeLook ) {
 
 
-		this.object.lookAt( targetPosition );
+				actualLookSpeed = 0;
 
 
-	};
+			}
+
+			var verticalLookRatio = 1;
+
+			if ( this.constrainVertical ) {
+
+				verticalLookRatio = Math.PI / ( this.verticalMax - this.verticalMin );
+
+			}
+
+			lon -= this.mouseX * actualLookSpeed;
+			if ( this.lookVertical ) lat -= this.mouseY * actualLookSpeed * verticalLookRatio;
+
+			lat = Math.max( - 85, Math.min( 85, lat ) );
+
+			var phi = THREE.Math.degToRad( 90 - lat );
+			var theta = THREE.Math.degToRad( lon );
+
+			if ( this.constrainVertical ) {
+
+				phi = THREE.Math.mapLinear( phi, 0, Math.PI, this.verticalMin, this.verticalMax );
+
+			}
+
+			var position = this.object.position;
+
+			targetPosition.setFromSphericalCoords( 1, phi, theta ).add( position );
+
+			this.object.lookAt( targetPosition );
+
+		};
+
+	}();
 
 
 	function contextmenu( event ) {
 	function contextmenu( event ) {
 
 
@@ -295,6 +323,20 @@ THREE.FirstPersonControls = function ( object, domElement ) {
 
 
 	}
 	}
 
 
+	function setOrientation( controls ) {
+
+		var quaternion = controls.object.quaternion;
+
+		lookDirection.set( 0, 0, - 1 ).applyQuaternion( quaternion );
+		spherical.setFromVector3( lookDirection );
+
+		lat = 90 - THREE.Math.radToDeg( spherical.phi );
+		lon = THREE.Math.radToDeg( spherical.theta );
+
+	}
+
 	this.handleResize();
 	this.handleResize();
 
 
+	setOrientation( this );
+
 };
 };

+ 24 - 5
examples/js/controls/OrbitControls.js

@@ -537,32 +537,44 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 
 	function handleKeyDown( event ) {
 	function handleKeyDown( event ) {
 
 
-		//console.log( 'handleKeyDown' );
+		// console.log( 'handleKeyDown' );
+
+		var needsUpdate = false;
 
 
 		switch ( event.keyCode ) {
 		switch ( event.keyCode ) {
 
 
 			case scope.keys.UP:
 			case scope.keys.UP:
 				pan( 0, scope.keyPanSpeed );
 				pan( 0, scope.keyPanSpeed );
-				scope.update();
+				needsUpdate = true;
 				break;
 				break;
 
 
 			case scope.keys.BOTTOM:
 			case scope.keys.BOTTOM:
 				pan( 0, - scope.keyPanSpeed );
 				pan( 0, - scope.keyPanSpeed );
-				scope.update();
+				needsUpdate = true;
 				break;
 				break;
 
 
 			case scope.keys.LEFT:
 			case scope.keys.LEFT:
 				pan( scope.keyPanSpeed, 0 );
 				pan( scope.keyPanSpeed, 0 );
-				scope.update();
+				needsUpdate = true;
 				break;
 				break;
 
 
 			case scope.keys.RIGHT:
 			case scope.keys.RIGHT:
 				pan( - scope.keyPanSpeed, 0 );
 				pan( - scope.keyPanSpeed, 0 );
-				scope.update();
+				needsUpdate = true;
 				break;
 				break;
 
 
 		}
 		}
 
 
+		if ( needsUpdate ) {
+
+			// prevent the browser from scrolling on cursor keys
+			event.preventDefault();
+
+			scope.update();
+
+		}
+
+
 	}
 	}
 
 
 	function handleTouchStartRotate( event ) {
 	function handleTouchStartRotate( event ) {
@@ -673,8 +685,15 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 
 		if ( scope.enabled === false ) return;
 		if ( scope.enabled === false ) return;
 
 
+		// Prevent the browser from scrolling.
+
 		event.preventDefault();
 		event.preventDefault();
 
 
+		// Manually set the focus since calling preventDefault above
+		// prevents the browser from setting it automatically.
+
+		scope.domElement.focus ? scope.domElement.focus() : window.focus();
+
 		switch ( event.button ) {
 		switch ( event.button ) {
 
 
 			case scope.mouseButtons.LEFT:
 			case scope.mouseButtons.LEFT:

+ 0 - 14
examples/js/controls/TransformControls.js

@@ -113,7 +113,6 @@ THREE.TransformControls = function ( camera, domElement ) {
 		domElement.addEventListener( "touchend", onPointerUp, false );
 		domElement.addEventListener( "touchend", onPointerUp, false );
 		domElement.addEventListener( "touchcancel", onPointerUp, false );
 		domElement.addEventListener( "touchcancel", onPointerUp, false );
 		domElement.addEventListener( "touchleave", onPointerUp, false );
 		domElement.addEventListener( "touchleave", onPointerUp, false );
-		domElement.addEventListener( "contextmenu", onContext, false );
 
 
 	}
 	}
 
 
@@ -128,7 +127,6 @@ THREE.TransformControls = function ( camera, domElement ) {
 		domElement.removeEventListener( "touchend", onPointerUp );
 		domElement.removeEventListener( "touchend", onPointerUp );
 		domElement.removeEventListener( "touchcancel", onPointerUp );
 		domElement.removeEventListener( "touchcancel", onPointerUp );
 		domElement.removeEventListener( "touchleave", onPointerUp );
 		domElement.removeEventListener( "touchleave", onPointerUp );
-		domElement.removeEventListener( "contextmenu", onContext );
 
 
 	};
 	};
 
 
@@ -517,12 +515,6 @@ THREE.TransformControls = function ( camera, domElement ) {
 
 
 	// mouse / touch event handlers
 	// mouse / touch event handlers
 
 
-	function onContext( event ) {
-
-		event.preventDefault();
-
-	}
-
 	function onPointerHover( event ) {
 	function onPointerHover( event ) {
 
 
 		if ( !scope.enabled ) return;
 		if ( !scope.enabled ) return;
@@ -535,8 +527,6 @@ THREE.TransformControls = function ( camera, domElement ) {
 
 
 		if ( !scope.enabled ) return;
 		if ( !scope.enabled ) return;
 
 
-		event.preventDefault();
-
 		document.addEventListener( "mousemove", onPointerMove, false );
 		document.addEventListener( "mousemove", onPointerMove, false );
 
 
 		scope.pointerHover( getPointer( event ) );
 		scope.pointerHover( getPointer( event ) );
@@ -548,8 +538,6 @@ THREE.TransformControls = function ( camera, domElement ) {
 
 
 		if ( !scope.enabled ) return;
 		if ( !scope.enabled ) return;
 
 
-		event.preventDefault();
-
 		scope.pointerMove( getPointer( event ) );
 		scope.pointerMove( getPointer( event ) );
 
 
 	}
 	}
@@ -558,8 +546,6 @@ THREE.TransformControls = function ( camera, domElement ) {
 
 
 		if ( !scope.enabled ) return;
 		if ( !scope.enabled ) return;
 
 
-		event.preventDefault(); // Prevent MouseEvent on mobile
-
 		document.removeEventListener( "mousemove", onPointerMove, false );
 		document.removeEventListener( "mousemove", onPointerMove, false );
 
 
 		scope.pointerUp( getPointer( event ) );
 		scope.pointerUp( getPointer( event ) );

+ 11 - 3
examples/js/crossfade/scenes.js

@@ -101,11 +101,19 @@ function Scene( type, numObjects, cameraZ, fov, rotationSpeed, clearColor ) {
 
 
 		renderer.setClearColor( this.clearColor );
 		renderer.setClearColor( this.clearColor );
 
 
-		if ( rtt )
-			renderer.render( this.scene, this.camera, this.fbo, true );
-		else
+		if ( rtt ) {
+
+			renderer.setRenderTarget( this.fbo );
+			renderer.clear();
+			renderer.render( this.scene, this.camera );
+
+		} else {
+
+			renderer.setRenderTarget( null );
 			renderer.render( this.scene, this.camera );
 			renderer.render( this.scene, this.camera );
 
 
+		}
+
 	};
 	};
 
 
 }
 }

+ 4 - 2
examples/js/crossfade/transition.js

@@ -1,4 +1,4 @@
-function Transition ( sceneA, sceneB ) {
+function Transition( sceneA, sceneB ) {
 
 
 	this.scene = new THREE.Scene();
 	this.scene = new THREE.Scene();
 
 
@@ -157,7 +157,9 @@ function Transition ( sceneA, sceneB ) {
 
 
 			this.sceneA.render( delta, true );
 			this.sceneA.render( delta, true );
 			this.sceneB.render( delta, true );
 			this.sceneB.render( delta, true );
-			renderer.render( this.scene, this.cameraOrtho, null, true );
+			renderer.setRenderTarget( null );
+			renderer.clear();
+			renderer.render( this.scene, this.cameraOrtho );
 
 
 		}
 		}
 
 

+ 13 - 2
examples/js/effects/AnaglyphEffect.js

@@ -130,16 +130,27 @@ THREE.AnaglyphEffect = function ( renderer, width, height ) {
 
 
 	this.render = function ( scene, camera ) {
 	this.render = function ( scene, camera ) {
 
 
+		var currentRenderTarget = renderer.getRenderTarget();
+
 		scene.updateMatrixWorld();
 		scene.updateMatrixWorld();
 
 
 		if ( camera.parent === null ) camera.updateMatrixWorld();
 		if ( camera.parent === null ) camera.updateMatrixWorld();
 
 
 		_stereo.update( camera );
 		_stereo.update( camera );
 
 
-		renderer.render( scene, _stereo.cameraL, _renderTargetL, true );
-		renderer.render( scene, _stereo.cameraR, _renderTargetR, true );
+		renderer.setRenderTarget( _renderTargetL );
+		renderer.clear();
+		renderer.render( scene, _stereo.cameraL );
+
+		renderer.setRenderTarget( _renderTargetR );
+		renderer.clear();
+		renderer.render( scene, _stereo.cameraR );
+
+		renderer.setRenderTarget( null );
 		renderer.render( _scene, _camera );
 		renderer.render( _scene, _camera );
 
 
+		renderer.setRenderTarget( currentRenderTarget );
+
 	};
 	};
 
 
 	this.dispose = function () {
 	this.dispose = function () {

+ 26 - 6
examples/js/effects/OutlineEffect.js

@@ -402,11 +402,31 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 	}
 	}
 
 
-	this.render = function ( scene, camera, renderTarget, forceClear ) {
+	this.render = function ( scene, camera ) {
+
+		var renderTarget;
+		var forceClear;
+
+		if ( arguments[ 2 ] !== undefined ) {
+
+			console.warn( 'THREE.OutlineEffect.render(): the renderTarget argument has been removed. Use .setRenderTarget() instead.' );
+			renderTarget = arguments[ 2 ];
+
+		}
+
+		if ( arguments[ 3 ] !== undefined ) {
+
+			console.warn( 'THREE.OutlineEffect.render(): the forceClear argument has been removed. Use .clear() instead.' );
+			forceClear = arguments[ 3 ];
+
+		}
+
+		renderer.setRenderTarget( renderTarget );
+		if ( forceClear ) renderer.clear();
 
 
 		if ( this.enabled === false ) {
 		if ( this.enabled === false ) {
 
 
-			renderer.render( scene, camera, renderTarget, forceClear );
+			renderer.render( scene, camera );
 			return;
 			return;
 
 
 		}
 		}
@@ -415,7 +435,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 		renderer.autoClear = this.autoClear;
 		renderer.autoClear = this.autoClear;
 
 
 		// 1. render normally
 		// 1. render normally
-		renderer.render( scene, camera, renderTarget, forceClear );
+		renderer.render( scene, camera );
 
 
 		// 2. render outline
 		// 2. render outline
 		var currentSceneAutoUpdate = scene.autoUpdate;
 		var currentSceneAutoUpdate = scene.autoUpdate;
@@ -429,7 +449,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 		scene.traverse( setOutlineMaterial );
 		scene.traverse( setOutlineMaterial );
 
 
-		renderer.render( scene, camera, renderTarget );
+		renderer.render( scene, camera );
 
 
 		scene.traverse( restoreOriginalMaterial );
 		scene.traverse( restoreOriginalMaterial );
 
 
@@ -478,9 +498,9 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 	};
 	};
 
 
-	this.getSize = function () {
+	this.getSize = function ( target ) {
 
 
-		return renderer.getSize();
+		return renderer.getSize( target );
 
 
 	};
 	};
 
 

+ 9 - 2
examples/js/effects/ParallaxBarrierEffect.js

@@ -87,8 +87,15 @@ THREE.ParallaxBarrierEffect = function ( renderer ) {
 
 
 		_stereo.update( camera );
 		_stereo.update( camera );
 
 
-		renderer.render( scene, _stereo.cameraL, _renderTargetL, true );
-		renderer.render( scene, _stereo.cameraR, _renderTargetR, true );
+		renderer.setRenderTarget( _renderTargetL );
+		renderer.clear();
+		renderer.render( scene, _stereo.cameraL );
+
+		renderer.setRenderTarget( _renderTargetR );
+		renderer.clear();
+		renderer.render( scene, _stereo.cameraR );
+
+		renderer.setRenderTarget( null );
 		renderer.render( _scene, _camera );
 		renderer.render( _scene, _camera );
 
 
 	};
 	};

+ 2 - 1
examples/js/effects/StereoEffect.js

@@ -9,6 +9,7 @@ THREE.StereoEffect = function ( renderer ) {
 
 
 	var _stereo = new THREE.StereoCamera();
 	var _stereo = new THREE.StereoCamera();
 	_stereo.aspect = 0.5;
 	_stereo.aspect = 0.5;
+	var size = new THREE.Vector2();
 
 
 	this.setEyeSeparation = function ( eyeSep ) {
 	this.setEyeSeparation = function ( eyeSep ) {
 
 
@@ -30,7 +31,7 @@ THREE.StereoEffect = function ( renderer ) {
 
 
 		_stereo.update( camera );
 		_stereo.update( camera );
 
 
-		var size = renderer.getSize();
+		renderer.getSize( size );
 
 
 		if ( renderer.autoClear ) renderer.clear();
 		if ( renderer.autoClear ) renderer.clear();
 		renderer.setScissorTest( true );
 		renderer.setScissorTest( true );

+ 10 - 5
examples/js/exporters/ColladaExporter.js

@@ -413,7 +413,7 @@ THREE.ColladaExporter.prototype = {
 
 
 					(
 					(
 						type !== 'constant' ?
 						type !== 'constant' ?
-						'<diffuse>' +
+							'<diffuse>' +
 
 
 						(
 						(
 							m.map ?
 							m.map ?
@@ -421,12 +421,12 @@ THREE.ColladaExporter.prototype = {
 								`<color sid="diffuse">${ diffuse.r } ${ diffuse.g } ${ diffuse.b } 1</color>`
 								`<color sid="diffuse">${ diffuse.r } ${ diffuse.g } ${ diffuse.b } 1</color>`
 						) +
 						) +
 						'</diffuse>'
 						'</diffuse>'
-						: ''
+							: ''
 					) +
 					) +
 
 
 					(
 					(
 						type === 'phong' ?
 						type === 'phong' ?
-						`<specular><color sid="specular">${ specular.r } ${ specular.g } ${ specular.b } 1</color></specular>` +
+							`<specular><color sid="specular">${ specular.r } ${ specular.g } ${ specular.b } 1</color></specular>` +
 
 
 						'<shininess>' +
 						'<shininess>' +
 
 
@@ -437,7 +437,7 @@ THREE.ColladaExporter.prototype = {
 						) +
 						) +
 
 
 						'</shininess>'
 						'</shininess>'
-						: ''
+							: ''
 					) +
 					) +
 
 
 					`<reflective><color>${ diffuse.r } ${ diffuse.g } ${ diffuse.b } 1</color></reflective>` +
 					`<reflective><color>${ diffuse.r } ${ diffuse.g } ${ diffuse.b } 1</color></reflective>` +
@@ -525,10 +525,15 @@ THREE.ColladaExporter.prototype = {
 				// the materials.
 				// the materials.
 				var mat = o.material || new THREE.MeshBasicMaterial();
 				var mat = o.material || new THREE.MeshBasicMaterial();
 				var materials = Array.isArray( mat ) ? mat : [ mat ];
 				var materials = Array.isArray( mat ) ? mat : [ mat ];
+
 				if ( geometry.groups.length > materials.length ) {
 				if ( geometry.groups.length > materials.length ) {
+
 					matidsArray = new Array( geometry.groups.length );
 					matidsArray = new Array( geometry.groups.length );
+
 				} else {
 				} else {
-					matidsArray = new Array( materials.length )
+
+					matidsArray = new Array( materials.length );
+
 				}
 				}
 				matids = matidsArray.fill()
 				matids = matidsArray.fill()
 					.map( ( v, i ) => processMaterial( materials[ i % materials.length ] ) );
 					.map( ( v, i ) => processMaterial( materials[ i % materials.length ] ) );

+ 280 - 25
examples/js/exporters/GLTFExporter.js

@@ -365,7 +365,7 @@ THREE.GLTFExporter.prototype = {
 		 */
 		 */
 		function applyTextureTransform( mapDef, texture ) {
 		function applyTextureTransform( mapDef, texture ) {
 
 
-			var didTransform = false
+			var didTransform = false;
 			var transformDef = {};
 			var transformDef = {};
 
 
 			if ( texture.offset.x !== 0 || texture.offset.y !== 0 ) {
 			if ( texture.offset.x !== 0 || texture.offset.y !== 0 ) {
@@ -385,7 +385,7 @@ THREE.GLTFExporter.prototype = {
 			if ( texture.repeat.x !== 1 || texture.repeat.y !== 1 ) {
 			if ( texture.repeat.x !== 1 || texture.repeat.y !== 1 ) {
 
 
 				transformDef.scale = texture.repeat.toArray();
 				transformDef.scale = texture.repeat.toArray();
-				didTransform = true;				
+				didTransform = true;
 
 
 			}
 			}
 
 
@@ -981,7 +981,10 @@ THREE.GLTFExporter.prototype = {
 			// occlusionTexture
 			// occlusionTexture
 			if ( material.aoMap ) {
 			if ( material.aoMap ) {
 
 
-				var occlusionMapDef = { index: processTexture( material.aoMap ) };
+				var occlusionMapDef = {
+					index: processTexture( material.aoMap ),
+					texCoord: 1
+				};
 
 
 				if ( material.aoMapIntensity !== 1.0 ) {
 				if ( material.aoMapIntensity !== 1.0 ) {
 
 
@@ -1076,6 +1079,8 @@ THREE.GLTFExporter.prototype = {
 
 
 				if ( ! geometry.isBufferGeometry ) {
 				if ( ! geometry.isBufferGeometry ) {
 
 
+					console.warn( 'GLTFExporter: Exporting THREE.Geometry will increase file size. Use THREE.BufferGeometry instead.' );
+
 					var geometryTemp = new THREE.BufferGeometry();
 					var geometryTemp = new THREE.BufferGeometry();
 					geometryTemp.fromGeometry( geometry );
 					geometryTemp.fromGeometry( geometry );
 					geometry = geometryTemp;
 					geometry = geometryTemp;
@@ -1227,9 +1232,9 @@ THREE.GLTFExporter.prototype = {
 
 
 						var baseAttribute = geometry.attributes[ attributeName ];
 						var baseAttribute = geometry.attributes[ attributeName ];
 
 
-						if ( cachedData.attributes.has( baseAttribute ) ) {
+						if ( cachedData.attributes.has( attribute ) ) {
 
 
-							target[ gltfAttributeName ] = cachedData.attributes.get( baseAttribute );
+							target[ gltfAttributeName ] = cachedData.attributes.get( attribute );
 							continue;
 							continue;
 
 
 						}
 						}
@@ -1405,7 +1410,7 @@ THREE.GLTFExporter.prototype = {
 				gltfCamera.perspective = {
 				gltfCamera.perspective = {
 
 
 					aspectRatio: camera.aspect,
 					aspectRatio: camera.aspect,
-					yfov: THREE.Math.degToRad( camera.fov ) / camera.aspect,
+					yfov: THREE.Math.degToRad( camera.fov ),
 					zfar: camera.far <= 0 ? 0.001 : camera.far,
 					zfar: camera.far <= 0 ? 0.001 : camera.far,
 					znear: camera.near < 0 ? 0 : camera.near
 					znear: camera.near < 0 ? 0 : camera.near
 
 
@@ -1443,12 +1448,15 @@ THREE.GLTFExporter.prototype = {
 
 
 			}
 			}
 
 
+			clip = THREE.GLTFExporter.Utils.mergeMorphTargetTracks( clip.clone(), root );
+
+			var tracks = clip.tracks;
 			var channels = [];
 			var channels = [];
 			var samplers = [];
 			var samplers = [];
 
 
-			for ( var i = 0; i < clip.tracks.length; ++ i ) {
+			for ( var i = 0; i < tracks.length; ++ i ) {
 
 
-				var track = clip.tracks[ i ];
+				var track = tracks[ i ];
 				var trackBinding = THREE.PropertyBinding.parseTrackName( track.name );
 				var trackBinding = THREE.PropertyBinding.parseTrackName( track.name );
 				var trackNode = THREE.PropertyBinding.findNode( root, trackBinding.nodeName );
 				var trackNode = THREE.PropertyBinding.findNode( root, trackBinding.nodeName );
 				var trackProperty = PATH_PROPERTIES[ trackBinding.propertyName ];
 				var trackProperty = PATH_PROPERTIES[ trackBinding.propertyName ];
@@ -1479,16 +1487,6 @@ THREE.GLTFExporter.prototype = {
 
 
 				if ( trackProperty === PATH_PROPERTIES.morphTargetInfluences ) {
 				if ( trackProperty === PATH_PROPERTIES.morphTargetInfluences ) {
 
 
-					if ( trackNode.morphTargetInfluences.length !== 1 &&
-						trackBinding.propertyIndex !== undefined ) {
-
-						console.warn( 'THREE.GLTFExporter: Skipping animation track "%s". ' +
-							'Morph target keyframe tracks must target all available morph targets ' +
-							'for the given mesh.', track.name );
-						continue;
-
-					}
-
 					outputItemSize /= trackNode.morphTargetInfluences.length;
 					outputItemSize /= trackNode.morphTargetInfluences.length;
 
 
 				}
 				}
@@ -1591,6 +1589,59 @@ THREE.GLTFExporter.prototype = {
 
 
 		}
 		}
 
 
+		function processLight( light ) {
+
+			var lightDef = {};
+
+			if ( light.name ) lightDef.name = light.name;
+
+			lightDef.color = light.color.toArray();
+
+			lightDef.intensity = light.intensity;
+
+			if ( light.isDirectionalLight ) {
+
+				lightDef.type = 'directional';
+
+			} else if ( light.isPointLight ) {
+
+				lightDef.type = 'point';
+				if ( light.distance > 0 ) lightDef.range = light.distance;
+
+			} else if ( light.isSpotLight ) {
+
+				lightDef.type = 'spot';
+				if ( light.distance > 0 ) lightDef.range = light.distance;
+				lightDef.spot = {};
+				lightDef.spot.innerConeAngle = ( light.penumbra - 1.0 ) * light.angle * - 1.0;
+				lightDef.spot.outerConeAngle = light.angle;
+
+			}
+
+			if ( light.decay !== undefined && light.decay !== 2 ) {
+
+				console.warn( 'THREE.GLTFExporter: Light decay may be lost. glTF is physically-based, '
+					+ 'and expects light.decay=2.' );
+
+			}
+
+			if ( light.target
+					&& ( light.target.parent !== light
+					 || light.target.position.x !== 0
+					 || light.target.position.y !== 0
+					 || light.target.position.z !== - 1 ) ) {
+
+				console.warn( 'THREE.GLTFExporter: Light direction may be lost. For best results, '
+					+ 'make light.target a child of the light with position 0,0,-1.' );
+
+			}
+
+			var lights = outputJSON.extensions[ 'KHR_lights_punctual' ].lights;
+			lights.push( lightDef );
+			return lights.length - 1;
+
+		}
+
 		/**
 		/**
 		 * Process Object3D node
 		 * Process Object3D node
 		 * @param  {THREE.Object3D} node Object3D to processNode
 		 * @param  {THREE.Object3D} node Object3D to processNode
@@ -1598,13 +1649,6 @@ THREE.GLTFExporter.prototype = {
 		 */
 		 */
 		function processNode( object ) {
 		function processNode( object ) {
 
 
-			if ( object.isLight ) {
-
-				console.warn( 'GLTFExporter: Unsupported node type:', object.constructor.name );
-				return null;
-
-			}
-
 			if ( ! outputJSON.nodes ) {
 			if ( ! outputJSON.nodes ) {
 
 
 				outputJSON.nodes = [];
 				outputJSON.nodes = [];
@@ -1675,6 +1719,24 @@ THREE.GLTFExporter.prototype = {
 
 
 				gltfNode.camera = processCamera( object );
 				gltfNode.camera = processCamera( object );
 
 
+			} else if ( object.isDirectionalLight || object.isPointLight || object.isSpotLight ) {
+
+				if ( ! extensionsUsed[ 'KHR_lights_punctual' ] ) {
+
+					outputJSON.extensions = outputJSON.extensions || {};
+					outputJSON.extensions[ 'KHR_lights_punctual' ] = { lights: [] };
+					extensionsUsed[ 'KHR_lights_punctual' ] = true;
+
+				}
+
+				gltfNode.extensions = gltfNode.extensions || {};
+				gltfNode.extensions[ 'KHR_lights_punctual' ] = { light: processLight( object ) };
+
+			} else if ( object.isLight ) {
+
+				console.warn( 'THREE.GLTFExporter: Only directional, point, and spot lights are supported.' );
+				return null;
+
 			}
 			}
 
 
 			if ( object.isSkinnedMesh ) {
 			if ( object.isSkinnedMesh ) {
@@ -1942,3 +2004,196 @@ THREE.GLTFExporter.prototype = {
 	}
 	}
 
 
 };
 };
+
+THREE.GLTFExporter.Utils = {
+
+	insertKeyframe: function ( track, time ) {
+
+		var tolerance = 0.001; // 1ms
+		var valueSize = track.getValueSize();
+
+		var times = new track.TimeBufferType( track.times.length + 1 );
+		var values = new track.ValueBufferType( track.values.length + valueSize );
+		var interpolant = track.createInterpolant( new track.ValueBufferType( valueSize ) );
+
+		var index;
+
+		if ( track.times.length === 0 ) {
+
+			times[ 0 ] = time;
+
+			for ( var i = 0; i < valueSize; i ++ ) {
+
+				values[ i ] = 0;
+
+			}
+
+			index = 0;
+
+		} else if ( time < track.times[ 0 ] ) {
+
+			if ( Math.abs( track.times[ 0 ] - time ) < tolerance ) return 0;
+
+			times[ 0 ] = time;
+			times.set( track.times, 1 );
+
+			values.set( interpolant.evaluate( time ), 0 );
+			values.set( track.values, valueSize );
+
+			index = 0;
+
+		} else if ( time > track.times[ track.times.length - 1 ] ) {
+
+			if ( Math.abs( track.times[ track.times.length - 1 ] - time ) < tolerance ) {
+
+				return track.times.length - 1;
+
+			}
+
+			times[ times.length - 1 ] = time;
+			times.set( track.times, 0 );
+
+			values.set( track.values, 0 );
+			values.set( interpolant.evaluate( time ), track.values.length );
+
+			index = times.length - 1;
+
+		} else {
+
+			for ( var i = 0; i < track.times.length; i ++ ) {
+
+				if ( Math.abs( track.times[ i ] - time ) < tolerance ) return i;
+
+				if ( track.times[ i ] < time && track.times[ i + 1 ] > time ) {
+
+					times.set( track.times.slice( 0, i + 1 ), 0 );
+					times[ i + 1 ] = time;
+					times.set( track.times.slice( i + 1 ), i + 2 );
+
+					values.set( track.values.slice( 0, ( i + 1 ) * valueSize ), 0 );
+					values.set( interpolant.evaluate( time ), ( i + 1 ) * valueSize );
+					values.set( track.values.slice( ( i + 1 ) * valueSize ), ( i + 2 ) * valueSize );
+
+					index = i + 1;
+
+					break;
+
+				}
+
+			}
+
+		}
+
+		track.times = times;
+		track.values = values;
+
+		return index;
+
+	},
+
+	mergeMorphTargetTracks: function ( clip, root ) {
+
+		var tracks = [];
+		var mergedTracks = {};
+		var sourceTracks = clip.tracks;
+
+		for ( var i = 0; i < sourceTracks.length; ++ i ) {
+
+			var sourceTrack = sourceTracks[ i ];
+			var sourceTrackBinding = THREE.PropertyBinding.parseTrackName( sourceTrack.name );
+			var sourceTrackNode = THREE.PropertyBinding.findNode( root, sourceTrackBinding.nodeName );
+
+			if ( sourceTrackBinding.propertyName !== 'morphTargetInfluences' || sourceTrackBinding.propertyIndex === undefined ) {
+
+				// Tracks that don't affect morph targets, or that affect all morph targets together, can be left as-is.
+				tracks.push( sourceTrack );
+				continue;
+
+			}
+
+			if ( sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodDiscrete
+				&& sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodLinear ) {
+
+				if ( sourceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
+
+					// This should never happen, because glTF morph target animations
+					// affect all targets already.
+					throw new Error( 'THREE.GLTFExporter: Cannot merge tracks with glTF CUBICSPLINE interpolation.' );
+
+				}
+
+				console.warn( 'THREE.GLTFExporter: Morph target interpolation mode not yet supported. Using LINEAR instead.' );
+
+				sourceTrack = sourceTrack.clone();
+				sourceTrack.setInterpolation( InterpolateLinear );
+
+			}
+
+			var targetCount = sourceTrackNode.morphTargetInfluences.length;
+			var targetIndex = sourceTrackNode.morphTargetDictionary[ sourceTrackBinding.propertyIndex ];
+
+			if ( targetIndex === undefined ) {
+
+				throw new Error( 'THREE.GLTFExporter: Morph target name not found: ' + sourceTrackBinding.propertyIndex );
+
+			}
+
+			var mergedTrack;
+
+			// If this is the first time we've seen this object, create a new
+			// track to store merged keyframe data for each morph target.
+			if ( mergedTracks[ sourceTrackNode.uuid ] === undefined ) {
+
+				mergedTrack = sourceTrack.clone();
+
+				var values = new mergedTrack.ValueBufferType( targetCount * mergedTrack.times.length );
+
+				for ( var j = 0; j < mergedTrack.times.length; j ++ ) {
+
+					values[ j * targetCount + targetIndex ] = mergedTrack.values[ j ];
+
+				}
+
+				mergedTrack.name = '.morphTargetInfluences';
+				mergedTrack.values = values;
+
+				mergedTracks[ sourceTrackNode.uuid ] = mergedTrack;
+				tracks.push( mergedTrack );
+
+				continue;
+
+			}
+
+			var mergedKeyframeIndex = 0;
+			var sourceKeyframeIndex = 0;
+			var sourceInterpolant = sourceTrack.createInterpolant( new sourceTrack.ValueBufferType( 1 ) );
+
+			mergedTrack = mergedTracks[ sourceTrackNode.uuid ];
+
+			// For every existing keyframe of the merged track, write a (possibly
+			// interpolated) value from the source track.
+			for ( var j = 0; j < mergedTrack.times.length; j ++ ) {
+
+				mergedTrack.values[ j * targetCount + targetIndex ] = sourceInterpolant.evaluate( mergedTrack.times[ j ] );
+
+			}
+
+			// For every existing keyframe of the source track, write a (possibly
+			// new) keyframe to the merged track. Values from the previous loop may
+			// be written again, but keyframes are de-duplicated.
+			for ( var j = 0; j < sourceTrack.times.length; j ++ ) {
+
+				var keyframeIndex = this.insertKeyframe( mergedTrack, sourceTrack.times[ j ] );
+				mergedTrack.values[ keyframeIndex * targetCount + targetIndex ] = sourceTrack.values[ j ];
+
+			}
+
+		}
+
+		clip.tracks = tracks;
+
+		return clip;
+
+	}
+
+};

+ 7 - 3
examples/js/loaders/AssimpJSONLoader.js

@@ -169,12 +169,13 @@ THREE.AssimpJSONLoader.prototype = {
 
 
 						// prop.semantic gives the type of the texture
 						// prop.semantic gives the type of the texture
 						// 1: diffuse
 						// 1: diffuse
-						// 2: specular mao
+						// 2: specular map
+						// 4: emissive map
 						// 5: height map (bumps)
 						// 5: height map (bumps)
 						// 6: normal map
 						// 6: normal map
-						// more values (i.e. emissive, environment) are known by assimp and may be relevant
+						// more values (i.e. environment, etc) are known by assimp and may be relevant
 
 
-						if ( semantic === 1 || semantic === 2 || semantic === 5 || semantic === 6 ) {
+						if ( semantic === 1 || semantic === 2 || semantic === 4 || semantic === 5 || semantic === 6 ) {
 
 
 							var keyname;
 							var keyname;
 
 
@@ -186,6 +187,9 @@ THREE.AssimpJSONLoader.prototype = {
 								case 2:
 								case 2:
 									keyname = 'specularMap';
 									keyname = 'specularMap';
 									break;
 									break;
+								case 4:
+									keyname = 'emissiveMap';
+									break;
 								case 5:
 								case 5:
 									keyname = 'bumpMap';
 									keyname = 'bumpMap';
 									break;
 									break;

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

@@ -2825,7 +2825,7 @@ THREE.ColladaLoader.prototype = {
 						break;
 						break;
 
 
 					case 'mass':
 					case 'mass':
-						data.mass = parseFloats( child.textContent )[0];
+						data.mass = parseFloats( child.textContent )[ 0 ];
 						break;
 						break;
 
 
 				}
 				}

+ 14 - 4
examples/js/loaders/EquirectangularToCubeGenerator.js

@@ -11,6 +11,8 @@ THREE.CubemapGenerator = function ( renderer ) {
 
 
 THREE.CubemapGenerator.prototype.fromEquirectangular = function ( texture, options ) {
 THREE.CubemapGenerator.prototype.fromEquirectangular = function ( texture, options ) {
 
 
+	options = options || {};
+
 	var scene = new THREE.Scene();
 	var scene = new THREE.Scene();
 
 
 	var shader = {
 	var shader = {
@@ -92,9 +94,9 @@ THREE.CubemapGenerator.prototype.fromEquirectangular = function ( texture, optio
 		type: texture.type,
 		type: texture.type,
 		format: texture.format,
 		format: texture.format,
 		encoding: texture.encoding,
 		encoding: texture.encoding,
-		generateMipmaps: ( options.generateMipmaps !== undefined ) ?  options.generateMipmaps : texture.generateMipmaps,
-		minFilter: ( options.minFilter !== undefined ) ?  options.minFilter : texture.minFilter,
-		magFilter: ( options.magFilter !== undefined ) ?  options.magFilter : texture.magFilter
+		generateMipmaps: ( options.generateMipmaps !== undefined ) ? options.generateMipmaps : texture.generateMipmaps,
+		minFilter: ( options.minFilter !== undefined ) ? options.minFilter : texture.minFilter,
+		magFilter: ( options.magFilter !== undefined ) ? options.magFilter : texture.magFilter
 	};
 	};
 
 
 	var camera = new THREE.CubeCamera( 1, 10, resolution, params );
 	var camera = new THREE.CubeCamera( 1, 10, resolution, params );
@@ -120,6 +122,8 @@ THREE.EquirectangularToCubeGenerator = ( function () {
 
 
 	var EquirectangularToCubeGenerator = function ( sourceTexture, options ) {
 	var EquirectangularToCubeGenerator = function ( sourceTexture, options ) {
 
 
+		options = options || {};
+
 		this.sourceTexture = sourceTexture;
 		this.sourceTexture = sourceTexture;
 		this.resolution = options.resolution || 512;
 		this.resolution = options.resolution || 512;
 
 
@@ -152,6 +156,8 @@ THREE.EquirectangularToCubeGenerator = ( function () {
 
 
 		update: function ( renderer ) {
 		update: function ( renderer ) {
 
 
+			var currentRenderTarget = renderer.getRenderTarget();
+
 			boxMesh.material.uniforms.equirectangularMap.value = this.sourceTexture;
 			boxMesh.material.uniforms.equirectangularMap.value = this.sourceTexture;
 
 
 			for ( var i = 0; i < 6; i ++ ) {
 			for ( var i = 0; i < 6; i ++ ) {
@@ -164,10 +170,14 @@ THREE.EquirectangularToCubeGenerator = ( function () {
 				camera.up.set( v.u[ 0 ], v.u[ 1 ], v.u[ 2 ] );
 				camera.up.set( v.u[ 0 ], v.u[ 1 ], v.u[ 2 ] );
 				camera.lookAt( v.t[ 0 ], v.t[ 1 ], v.t[ 2 ] );
 				camera.lookAt( v.t[ 0 ], v.t[ 1 ], v.t[ 2 ] );
 
 
-				renderer.render( scene, camera, this.renderTarget, true );
+				renderer.setRenderTarget( this.renderTarget );
+				renderer.clear();
+				renderer.render( scene, camera );
 
 
 			}
 			}
 
 
+			renderer.setRenderTarget( currentRenderTarget );
+
 			return this.renderTarget.texture;
 			return this.renderTarget.texture;
 
 
 		},
 		},

+ 2 - 1
examples/js/loaders/FBXLoader.js

@@ -44,6 +44,7 @@ THREE.FBXLoader = ( function () {
 			var path = ( self.path === undefined ) ? THREE.LoaderUtils.extractUrlBase( url ) : self.path;
 			var path = ( self.path === undefined ) ? THREE.LoaderUtils.extractUrlBase( url ) : self.path;
 
 
 			var loader = new THREE.FileLoader( this.manager );
 			var loader = new THREE.FileLoader( this.manager );
+			loader.setPath( self.path );
 			loader.setResponseType( 'arraybuffer' );
 			loader.setResponseType( 'arraybuffer' );
 
 
 			loader.load( url, function ( buffer ) {
 			loader.load( url, function ( buffer ) {
@@ -2509,7 +2510,7 @@ THREE.FBXLoader = ( function () {
 
 
 										sceneGraph.traverse( function ( child ) {
 										sceneGraph.traverse( function ( child ) {
 
 
-											if ( child.ID = rawModel.id ) {
+											if ( child.ID === rawModel.id ) {
 
 
 												node.transform = child.matrix;
 												node.transform = child.matrix;
 
 

+ 26 - 13
examples/js/loaders/GLTFLoader.js

@@ -338,7 +338,7 @@ THREE.GLTFLoader = ( function () {
 
 
 			case 'directional':
 			case 'directional':
 				lightNode = new THREE.DirectionalLight( color );
 				lightNode = new THREE.DirectionalLight( color );
-				lightNode.target.position.set( 0, 0, -1 );
+				lightNode.target.position.set( 0, 0, - 1 );
 				lightNode.add( lightNode.target );
 				lightNode.add( lightNode.target );
 				break;
 				break;
 
 
@@ -356,7 +356,7 @@ THREE.GLTFLoader = ( function () {
 				lightDef.spot.outerConeAngle = lightDef.spot.outerConeAngle !== undefined ? lightDef.spot.outerConeAngle : Math.PI / 4.0;
 				lightDef.spot.outerConeAngle = lightDef.spot.outerConeAngle !== undefined ? lightDef.spot.outerConeAngle : Math.PI / 4.0;
 				lightNode.angle = lightDef.spot.outerConeAngle;
 				lightNode.angle = lightDef.spot.outerConeAngle;
 				lightNode.penumbra = 1.0 - lightDef.spot.innerConeAngle / lightDef.spot.outerConeAngle;
 				lightNode.penumbra = 1.0 - lightDef.spot.innerConeAngle / lightDef.spot.outerConeAngle;
-				lightNode.target.position.set( 0, 0, -1 );
+				lightNode.target.position.set( 0, 0, - 1 );
 				lightNode.add( lightNode.target );
 				lightNode.add( lightNode.target );
 				break;
 				break;
 
 
@@ -365,6 +365,10 @@ THREE.GLTFLoader = ( function () {
 
 
 		}
 		}
 
 
+		// Some lights (e.g. spot) default to a position other than the origin. Reset the position
+		// here, because node-level parsing will only override position if explicitly specified.
+		lightNode.position.set( 0, 0, 0 );
+
 		lightNode.decay = 2;
 		lightNode.decay = 2;
 
 
 		if ( lightDef.intensity !== undefined ) lightNode.intensity = lightDef.intensity;
 		if ( lightDef.intensity !== undefined ) lightNode.intensity = lightDef.intensity;
@@ -964,6 +968,7 @@ THREE.GLTFLoader = ( function () {
 					uniforms.refractionRatio.value = material.refractionRatio;
 					uniforms.refractionRatio.value = material.refractionRatio;
 
 
 					uniforms.maxMipLevel.value = renderer.properties.get( material.envMap ).__maxMipLevel;
 					uniforms.maxMipLevel.value = renderer.properties.get( material.envMap ).__maxMipLevel;
+
 				}
 				}
 
 
 				uniforms.specular.value.copy( material.specular );
 				uniforms.specular.value.copy( material.specular );
@@ -1197,6 +1202,7 @@ THREE.GLTFLoader = ( function () {
 	var ATTRIBUTES = {
 	var ATTRIBUTES = {
 		POSITION: 'position',
 		POSITION: 'position',
 		NORMAL: 'normal',
 		NORMAL: 'normal',
+		TANGENT: 'tangent',
 		TEXCOORD_0: 'uv',
 		TEXCOORD_0: 'uv',
 		TEXCOORD_1: 'uv2',
 		TEXCOORD_1: 'uv2',
 		COLOR_0: 'color',
 		COLOR_0: 'color',
@@ -1848,7 +1854,7 @@ THREE.GLTFLoader = ( function () {
 
 
 				case 'light':
 				case 'light':
 					dependency = this.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].loadLight( index );
 					dependency = this.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].loadLight( index );
-					break
+					break;
 
 
 				default:
 				default:
 					throw new Error( 'Unknown type: ' + type );
 					throw new Error( 'Unknown type: ' + type );
@@ -2227,6 +2233,18 @@ THREE.GLTFLoader = ( function () {
 
 
 		return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) {
 		return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) {
 
 
+			switch ( mapName ) {
+
+				case 'aoMap':
+				case 'emissiveMap':
+				case 'metalnessMap':
+				case 'normalMap':
+				case 'roughnessMap':
+					texture.format = THREE.RGBFormat;
+					break;
+
+			}
+
 			if ( parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] ) {
 			if ( parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] ) {
 
 
 				var transform = mapDef.extensions !== undefined ? mapDef.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] : undefined;
 				var transform = mapDef.extensions !== undefined ? mapDef.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] : undefined;
@@ -2392,14 +2410,6 @@ THREE.GLTFLoader = ( function () {
 
 
 			if ( materialDef.name !== undefined ) material.name = materialDef.name;
 			if ( materialDef.name !== undefined ) material.name = materialDef.name;
 
 
-			// Normal map textures use OpenGL conventions:
-			// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materialnormaltexture
-			if ( material.normalScale ) {
-
-				material.normalScale.y = - material.normalScale.y;
-
-			}
-
 			// baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding.
 			// baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding.
 			if ( material.map ) material.map.encoding = THREE.sRGBEncoding;
 			if ( material.map ) material.map.encoding = THREE.sRGBEncoding;
 			if ( material.emissiveMap ) material.emissiveMap.encoding = THREE.sRGBEncoding;
 			if ( material.emissiveMap ) material.emissiveMap.encoding = THREE.sRGBEncoding;
@@ -2757,6 +2767,7 @@ THREE.GLTFLoader = ( function () {
 
 
 					var materials = isMultiMaterial ? mesh.material : [ mesh.material ];
 					var materials = isMultiMaterial ? mesh.material : [ mesh.material ];
 
 
+					var useVertexTangents = geometry.attributes.tangent !== undefined;
 					var useVertexColors = geometry.attributes.color !== undefined;
 					var useVertexColors = geometry.attributes.color !== undefined;
 					var useFlatShading = geometry.attributes.normal === undefined;
 					var useFlatShading = geometry.attributes.normal === undefined;
 					var useSkinning = mesh.isSkinnedMesh === true;
 					var useSkinning = mesh.isSkinnedMesh === true;
@@ -2809,12 +2820,13 @@ THREE.GLTFLoader = ( function () {
 						}
 						}
 
 
 						// Clone the material if it will be modified
 						// Clone the material if it will be modified
-						if ( useVertexColors || useFlatShading || useSkinning || useMorphTargets ) {
+						if ( useVertexTangents || useVertexColors || useFlatShading || useSkinning || useMorphTargets ) {
 
 
 							var cacheKey = 'ClonedMaterial:' + material.uuid + ':';
 							var cacheKey = 'ClonedMaterial:' + material.uuid + ':';
 
 
 							if ( material.isGLTFSpecularGlossinessMaterial ) cacheKey += 'specular-glossiness:';
 							if ( material.isGLTFSpecularGlossinessMaterial ) cacheKey += 'specular-glossiness:';
 							if ( useSkinning ) cacheKey += 'skinning:';
 							if ( useSkinning ) cacheKey += 'skinning:';
+							if ( useVertexTangents ) cacheKey += 'vertex-tangents:';
 							if ( useVertexColors ) cacheKey += 'vertex-colors:';
 							if ( useVertexColors ) cacheKey += 'vertex-colors:';
 							if ( useFlatShading ) cacheKey += 'flat-shading:';
 							if ( useFlatShading ) cacheKey += 'flat-shading:';
 							if ( useMorphTargets ) cacheKey += 'morph-targets:';
 							if ( useMorphTargets ) cacheKey += 'morph-targets:';
@@ -2829,6 +2841,7 @@ THREE.GLTFLoader = ( function () {
 									: material.clone();
 									: material.clone();
 
 
 								if ( useSkinning ) cachedMaterial.skinning = true;
 								if ( useSkinning ) cachedMaterial.skinning = true;
+								if ( useVertexTangents ) cachedMaterial.vertexTangents = true;
 								if ( useVertexColors ) cachedMaterial.vertexColors = THREE.VertexColors;
 								if ( useVertexColors ) cachedMaterial.vertexColors = THREE.VertexColors;
 								if ( useFlatShading ) cachedMaterial.flatShading = true;
 								if ( useFlatShading ) cachedMaterial.flatShading = true;
 								if ( useMorphTargets ) cachedMaterial.morphTargets = true;
 								if ( useMorphTargets ) cachedMaterial.morphTargets = true;
@@ -3129,7 +3142,7 @@ THREE.GLTFLoader = ( function () {
 
 
 		var nodeDef = json.nodes[ nodeIndex ];
 		var nodeDef = json.nodes[ nodeIndex ];
 
 
-		return ( function() {
+		return ( function () {
 
 
 			// .isBone isn't in glTF spec. See .markDefs
 			// .isBone isn't in glTF spec. See .markDefs
 			if ( nodeDef.isBone === true ) {
 			if ( nodeDef.isBone === true ) {

+ 57 - 67
examples/js/loaders/LDrawLoader.js

@@ -66,13 +66,13 @@ THREE.LDrawLoader = ( function () {
 
 
 		},
 		},
 
 
-		getRemainingString: function() {
+		getRemainingString: function () {
 
 
 			return this.line.substring( this.currentCharIndex, this.lineLength );
 			return this.line.substring( this.currentCharIndex, this.lineLength );
 
 
 		},
 		},
 
 
-		isAtTheEnd: function() {
+		isAtTheEnd: function () {
 
 
 			return this.currentCharIndex >= this.lineLength;
 			return this.currentCharIndex >= this.lineLength;
 
 
@@ -86,21 +86,27 @@ THREE.LDrawLoader = ( function () {
 
 
 		getLineNumberString: function () {
 		getLineNumberString: function () {
 
 
-			return this.lineNumber >= 0? " at line " + this.lineNumber: "";
+			return this.lineNumber >= 0 ? " at line " + this.lineNumber : "";
 
 
 		}
 		}
 
 
 
 
 	};
 	};
 
 
-	function sortByMaterial ( a, b ) {
+	function sortByMaterial( a, b ) {
 
 
 		if ( a.colourCode === b.colourCode ) {
 		if ( a.colourCode === b.colourCode ) {
+
 			return 0;
 			return 0;
+
 		}
 		}
+
 		if ( a.colourCode < b.colourCode ) {
 		if ( a.colourCode < b.colourCode ) {
-			return -1;
+
+			return - 1;
+
 		}
 		}
+
 		return 1;
 		return 1;
 
 
 	}
 	}
@@ -149,14 +155,14 @@ THREE.LDrawLoader = ( function () {
 				index0 = iElem * elementSize;
 				index0 = iElem * elementSize;
 				numGroupVerts = elementSize;
 				numGroupVerts = elementSize;
 
 
-			}
-			else {
+			} else {
 
 
 				numGroupVerts += elementSize;
 				numGroupVerts += elementSize;
 
 
 			}
 			}
 
 
 		}
 		}
+
 		if ( numGroupVerts > 0 ) {
 		if ( numGroupVerts > 0 ) {
 
 
 			bufferGeometry.addGroup( index0, Infinity, materials.length - 1 );
 			bufferGeometry.addGroup( index0, Infinity, materials.length - 1 );
@@ -166,12 +172,12 @@ THREE.LDrawLoader = ( function () {
 		bufferGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
 		bufferGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
 
 
 		var object3d = null;
 		var object3d = null;
+
 		if ( elementSize === 2 ) {
 		if ( elementSize === 2 ) {
 
 
 			object3d = new THREE.LineSegments( bufferGeometry, materials );
 			object3d = new THREE.LineSegments( bufferGeometry, materials );
 
 
-		}
-		else if ( elementSize === 3 ) {
+		} else if ( elementSize === 3 ) {
 
 
 			bufferGeometry.computeVertexNormals();
 			bufferGeometry.computeVertexNormals();
 
 
@@ -259,7 +265,7 @@ THREE.LDrawLoader = ( function () {
 
 
 			var fileLoader = new THREE.FileLoader( this.manager );
 			var fileLoader = new THREE.FileLoader( this.manager );
 			fileLoader.setPath( this.path );
 			fileLoader.setPath( this.path );
-			fileLoader.load( url, function( text ) {
+			fileLoader.load( url, function ( text ) {
 
 
 				processObject( text, onLoad );
 				processObject( text, onLoad );
 
 
@@ -308,10 +314,10 @@ THREE.LDrawLoader = ( function () {
 							finalizeObject();
 							finalizeObject();
 
 
 						}
 						}
+
 					}
 					}
 
 
-				}
-				else {
+				} else {
 
 
 					// No subobjects, finish object
 					// No subobjects, finish object
 					finalizeObject();
 					finalizeObject();
@@ -349,7 +355,7 @@ THREE.LDrawLoader = ( function () {
 
 
 				}
 				}
 
 
-				function loadSubobject ( subobject, sync ) {
+				function loadSubobject( subobject, sync ) {
 
 
 					parseScope.mainColourCode = subobject.material.userData.code;
 					parseScope.mainColourCode = subobject.material.userData.code;
 					parseScope.mainEdgeColourCode = subobject.material.userData.edgeMaterial.userData.code;
 					parseScope.mainEdgeColourCode = subobject.material.userData.edgeMaterial.userData.code;
@@ -416,8 +422,7 @@ THREE.LDrawLoader = ( function () {
 								// Try absolute path
 								// Try absolute path
 								newLocationState = LDrawLoader.FILE_LOCATION_NOT_FOUND;
 								newLocationState = LDrawLoader.FILE_LOCATION_NOT_FOUND;
 
 
-							}
-							else {
+							} else {
 
 
 								// Next attempt is lower case
 								// Next attempt is lower case
 								subobject.fileName = subobject.fileName.toLowerCase();
 								subobject.fileName = subobject.fileName.toLowerCase();
@@ -442,8 +447,7 @@ THREE.LDrawLoader = ( function () {
 								scope.removeScopeLevel();
 								scope.removeScopeLevel();
 								onProcessed( objGroup );
 								onProcessed( objGroup );
 
 
-							}
-							else {
+							} else {
 
 
 								// Load next subobject
 								// Load next subobject
 								loadSubobject( parseScope.subobjects[ parseScope.subobjectIndex ] );
 								loadSubobject( parseScope.subobjects[ parseScope.subobjectIndex ] );
@@ -485,8 +489,7 @@ THREE.LDrawLoader = ( function () {
 
 
 						loadSubobject( parseScope.subobjects[ parseScope.subobjectIndex ] );
 						loadSubobject( parseScope.subobjects[ parseScope.subobjectIndex ] );
 
 
-					}
-					else {
+					} else {
 
 
 						finalizeObject();
 						finalizeObject();
 
 
@@ -494,7 +497,7 @@ THREE.LDrawLoader = ( function () {
 
 
 				}
 				}
 
 
-				function addSubobject ( subobject, subobjectGroup ) {
+				function addSubobject( subobject, subobjectGroup ) {
 
 
 					if ( scope.separateObjects ) {
 					if ( scope.separateObjects ) {
 
 
@@ -546,7 +549,7 @@ THREE.LDrawLoader = ( function () {
 
 
 		},
 		},
 
 
-		setFileMap: function( fileMap ) {
+		setFileMap: function ( fileMap ) {
 
 
 			this.fileMap = fileMap;
 			this.fileMap = fileMap;
 
 
@@ -601,7 +604,7 @@ THREE.LDrawLoader = ( function () {
 
 
 		},
 		},
 
 
-		removeScopeLevel: function() {
+		removeScopeLevel: function () {
 
 
 			this.parseScopesStack.pop();
 			this.parseScopesStack.pop();
 
 
@@ -641,7 +644,7 @@ THREE.LDrawLoader = ( function () {
 
 
 			}
 			}
 
 
-			for ( var i = this.parseScopesStack.length - 1; i >= 0; i-- ) {
+			for ( var i = this.parseScopesStack.length - 1; i >= 0; i -- ) {
 
 
 				var material = this.parseScopesStack[ i ].lib[ colourCode ];
 				var material = this.parseScopesStack[ i ].lib[ colourCode ];
 
 
@@ -736,9 +739,10 @@ THREE.LDrawLoader = ( function () {
 
 
 							colour = '#' + colour.substring( 2 );
 							colour = '#' + colour.substring( 2 );
 
 
-						}
-						else if ( ! colour.startsWith( '#' ) ) {
+						} else if ( ! colour.startsWith( '#' ) ) {
+
 							throw 'LDrawLoader: Invalid colour while parsing material' + lineParser.getLineNumberString() + ".";
 							throw 'LDrawLoader: Invalid colour while parsing material' + lineParser.getLineNumberString() + ".";
+
 						}
 						}
 						break;
 						break;
 
 
@@ -749,8 +753,7 @@ THREE.LDrawLoader = ( function () {
 
 
 							edgeColour = '#' + edgeColour.substring( 2 );
 							edgeColour = '#' + edgeColour.substring( 2 );
 
 
-						}
-						else if ( ! edgeColour.startsWith( '#' ) ) {
+						} else if ( ! edgeColour.startsWith( '#' ) ) {
 
 
 							// Try to see if edge colour is a colour code
 							// Try to see if edge colour is a colour code
 							edgeMaterial = this.getMaterial( edgeColour );
 							edgeMaterial = this.getMaterial( edgeColour );
@@ -849,13 +852,13 @@ THREE.LDrawLoader = ( function () {
 						// Default plastic material with shiny specular
 						// Default plastic material with shiny specular
 						hsl.l = Math.min( 1, hsl.l + ( 1 - hsl.l ) * 0.12 );
 						hsl.l = Math.min( 1, hsl.l + ( 1 - hsl.l ) * 0.12 );
 
 
-					}
-					else {
+					} else {
 
 
 						// Try to imitate pearlescency by setting the specular to the complementary of the color, and low shininess
 						// Try to imitate pearlescency by setting the specular to the complementary of the color, and low shininess
 						hsl.h = ( hsl.h + 0.5 ) % 1;
 						hsl.h = ( hsl.h + 0.5 ) % 1;
 						hsl.l = Math.min( 1, hsl.l + ( 1 - hsl.l ) * 0.7 );
 						hsl.l = Math.min( 1, hsl.l + ( 1 - hsl.l ) * 0.7 );
 						shininess = 10;
 						shininess = 10;
+
 					}
 					}
 
 
 					specular.setHSL( hsl.h, hsl.s, hsl.l );
 					specular.setHSL( hsl.h, hsl.s, hsl.l );
@@ -891,6 +894,7 @@ THREE.LDrawLoader = ( function () {
 				default:
 				default:
 					// Should not happen
 					// Should not happen
 					break;
 					break;
+
 			}
 			}
 
 
 			// BFC (Back Face Culling) LDraw language meta extension is not implemented, so set all materials double-sided:
 			// BFC (Back Face Culling) LDraw language meta extension is not implemented, so set all materials double-sided:
@@ -902,15 +906,19 @@ THREE.LDrawLoader = ( function () {
 			material.userData.canHaveEnvMap = canHaveEnvMap;
 			material.userData.canHaveEnvMap = canHaveEnvMap;
 
 
 			if ( luminance !== 0 ) {
 			if ( luminance !== 0 ) {
+
 				material.emissive.set( material.color ).multiplyScalar( luminance );
 				material.emissive.set( material.color ).multiplyScalar( luminance );
+
 			}
 			}
 
 
 			if ( ! edgeMaterial ) {
 			if ( ! edgeMaterial ) {
+
 				// This is the material used for edges
 				// This is the material used for edges
 				edgeMaterial = new THREE.LineBasicMaterial( { color: edgeColour } );
 				edgeMaterial = new THREE.LineBasicMaterial( { color: edgeColour } );
 				edgeMaterial.userData.code = code;
 				edgeMaterial.userData.code = code;
 				edgeMaterial.name = name + " - Edge";
 				edgeMaterial.name = name + " - Edge";
 				edgeMaterial.userData.canHaveEnvMap = false;
 				edgeMaterial.userData.canHaveEnvMap = false;
+
 			}
 			}
 
 
 			material.userData.code = code;
 			material.userData.code = code;
@@ -948,8 +956,7 @@ THREE.LDrawLoader = ( function () {
 				triangles = [];
 				triangles = [];
 				lineSegments = [];
 				lineSegments = [];
 
 
-			}
-			else {
+			} else {
 
 
 				if ( this.currentGroupObject === null ) {
 				if ( this.currentGroupObject === null ) {
 
 
@@ -1014,7 +1021,7 @@ THREE.LDrawLoader = ( function () {
 
 
 			}
 			}
 
 
-			function parseVector ( lp ) {
+			function parseVector( lp ) {
 
 
 				var v = new THREE.Vector3( parseFloat( lp.getToken() ), parseFloat( lp.getToken() ), parseFloat( lp.getToken() ) );
 				var v = new THREE.Vector3( parseFloat( lp.getToken() ), parseFloat( lp.getToken() ), parseFloat( lp.getToken() ) );
 
 
@@ -1028,24 +1035,10 @@ THREE.LDrawLoader = ( function () {
 
 
 			}
 			}
 
 
-			function findSubobject( fileName ) {
-
-				for ( var i = 0, n = subobjects.length; i < n; i ++ ) {
-
-					if ( subobjects[ i ].fileName === fileName ) {
-						return subobjects[ i ];
-					}
-
-					return null;
-
-				}
-
-			}
-
 			// Parse all line commands
 			// Parse all line commands
 			for ( lineIndex = 0; lineIndex < numLines; lineIndex ++ ) {
 			for ( lineIndex = 0; lineIndex < numLines; lineIndex ++ ) {
 
 
-				line = lines[ lineIndex ];
+				var line = lines[ lineIndex ];
 
 
 				if ( line.length === 0 ) continue;
 				if ( line.length === 0 ) continue;
 
 
@@ -1060,8 +1053,7 @@ THREE.LDrawLoader = ( function () {
 						currentEmbeddedFileName = line.substring( 7 );
 						currentEmbeddedFileName = line.substring( 7 );
 						currentEmbeddedText = '';
 						currentEmbeddedText = '';
 
 
-					}
-					else {
+					} else {
 
 
 						currentEmbeddedText += line + '\n';
 						currentEmbeddedText += line + '\n';
 
 
@@ -1076,8 +1068,10 @@ THREE.LDrawLoader = ( function () {
 				lp.seekNonSpace();
 				lp.seekNonSpace();
 
 
 				if ( lp.isAtTheEnd() ) {
 				if ( lp.isAtTheEnd() ) {
+
 					// Empty line
 					// Empty line
 					continue;
 					continue;
+
 				}
 				}
 
 
 				// Parse the line type
 				// Parse the line type
@@ -1102,10 +1096,9 @@ THREE.LDrawLoader = ( function () {
 
 
 										this.addMaterial( material );
 										this.addMaterial( material );
 
 
-									}
-									else {
+									}	else {
 
 
-										console.warn( 'LDrawLoader: Error parsing material' + lineParser.getLineNumberString() );
+										console.warn( 'LDrawLoader: Error parsing material' + lp.getLineNumberString() );
 
 
 									}
 									}
 									break;
 									break;
@@ -1117,22 +1110,22 @@ THREE.LDrawLoader = ( function () {
 
 
 								case '!KEYWORDS':
 								case '!KEYWORDS':
 
 
-										var newKeywords = lp.getRemainingString().split( ',' );
-										if ( newKeywords.length > 0 ) {
+									var newKeywords = lp.getRemainingString().split( ',' );
+									if ( newKeywords.length > 0 ) {
 
 
-											if ( ! keywords ) {
+										if ( ! keywords ) {
 
 
-												keywords = [];
+											keywords = [];
 
 
-											}
+										}
 
 
-											newKeywords.forEach( function( keyword ) {
+										newKeywords.forEach( function ( keyword ) {
 
 
-												keywords.push( keyword.trim() );
+											keywords.push( keyword.trim() );
 
 
-											} );
+										} );
 
 
-										}
+									}
 									break;
 									break;
 
 
 								case 'FILE':
 								case 'FILE':
@@ -1190,16 +1183,14 @@ THREE.LDrawLoader = ( function () {
 							// Found the subobject path in the preloaded file path map
 							// Found the subobject path in the preloaded file path map
 							fileName = scope.fileMap[ fileName ];
 							fileName = scope.fileMap[ fileName ];
 
 
-						}
-						else {
+						}	else {
 
 
 							// Standardized subfolders
 							// Standardized subfolders
 							if ( fileName.startsWith( 's/' ) ) {
 							if ( fileName.startsWith( 's/' ) ) {
 
 
 								fileName = 'parts/' + fileName;
 								fileName = 'parts/' + fileName;
 
 
-							}
-							else if ( fileName.startsWith( '48/' ) ) {
+							} else if ( fileName.startsWith( '48/' ) ) {
 
 
 								fileName = 'p/' + fileName;
 								fileName = 'p/' + fileName;
 
 
@@ -1316,8 +1307,7 @@ THREE.LDrawLoader = ( function () {
 
 
 				}
 				}
 
 
-			}
-			else {
+			} else {
 
 
 				groupObject = this.currentGroupObject;
 				groupObject = this.currentGroupObject;
 
 

+ 19 - 4
examples/js/loaders/SVGLoader.js

@@ -162,6 +162,7 @@ THREE.SVGLoader.prototype = {
 							} else {
 							} else {
 								path.lineTo( point.x, point.y );
 								path.lineTo( point.x, point.y );
 							}
 							}
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -172,6 +173,7 @@ THREE.SVGLoader.prototype = {
 							control.x = point.x;
 							control.x = point.x;
 							control.y = point.y;
 							control.y = point.y;
 							path.lineTo( point.x, point.y );
 							path.lineTo( point.x, point.y );
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -182,6 +184,7 @@ THREE.SVGLoader.prototype = {
 							control.x = point.x;
 							control.x = point.x;
 							control.y = point.y;
 							control.y = point.y;
 							path.lineTo( point.x, point.y );
 							path.lineTo( point.x, point.y );
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -193,6 +196,7 @@ THREE.SVGLoader.prototype = {
 							control.x = point.x;
 							control.x = point.x;
 							control.y = point.y;
 							control.y = point.y;
 							path.lineTo( point.x, point.y );
 							path.lineTo( point.x, point.y );
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -211,6 +215,7 @@ THREE.SVGLoader.prototype = {
 							control.y = numbers[ j + 3 ];
 							control.y = numbers[ j + 3 ];
 							point.x = numbers[ j + 4 ];
 							point.x = numbers[ j + 4 ];
 							point.y = numbers[ j + 5 ];
 							point.y = numbers[ j + 5 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -229,6 +234,7 @@ THREE.SVGLoader.prototype = {
 							control.y = numbers[ j + 1 ];
 							control.y = numbers[ j + 1 ];
 							point.x = numbers[ j + 2 ];
 							point.x = numbers[ j + 2 ];
 							point.y = numbers[ j + 3 ];
 							point.y = numbers[ j + 3 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -245,6 +251,7 @@ THREE.SVGLoader.prototype = {
 							control.y = numbers[ j + 1 ];
 							control.y = numbers[ j + 1 ];
 							point.x = numbers[ j + 2 ];
 							point.x = numbers[ j + 2 ];
 							point.y = numbers[ j + 3 ];
 							point.y = numbers[ j + 3 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -263,6 +270,7 @@ THREE.SVGLoader.prototype = {
 							control.y = ry;
 							control.y = ry;
 							point.x = numbers[ j + 0 ];
 							point.x = numbers[ j + 0 ];
 							point.y = numbers[ j + 1 ];
 							point.y = numbers[ j + 1 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -277,6 +285,7 @@ THREE.SVGLoader.prototype = {
 							parseArcCommand(
 							parseArcCommand(
 								path, numbers[ j ], numbers[ j + 1 ], numbers[ j + 2 ], numbers[ j + 3 ], numbers[ j + 4 ], start, point
 								path, numbers[ j ], numbers[ j + 1 ], numbers[ j + 2 ], numbers[ j + 3 ], numbers[ j + 4 ], start, point
 							);
 							);
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -294,6 +303,7 @@ THREE.SVGLoader.prototype = {
 							} else {
 							} else {
 								path.lineTo( point.x, point.y );
 								path.lineTo( point.x, point.y );
 							}
 							}
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -304,6 +314,7 @@ THREE.SVGLoader.prototype = {
 							control.x = point.x;
 							control.x = point.x;
 							control.y = point.y;
 							control.y = point.y;
 							path.lineTo( point.x, point.y );
 							path.lineTo( point.x, point.y );
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -314,6 +325,7 @@ THREE.SVGLoader.prototype = {
 							control.x = point.x;
 							control.x = point.x;
 							control.y = point.y;
 							control.y = point.y;
 							path.lineTo( point.x, point.y );
 							path.lineTo( point.x, point.y );
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -325,6 +337,7 @@ THREE.SVGLoader.prototype = {
 							control.x = point.x;
 							control.x = point.x;
 							control.y = point.y;
 							control.y = point.y;
 							path.lineTo( point.x, point.y );
 							path.lineTo( point.x, point.y );
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -343,6 +356,7 @@ THREE.SVGLoader.prototype = {
 							control.y = point.y + numbers[ j + 3 ];
 							control.y = point.y + numbers[ j + 3 ];
 							point.x += numbers[ j + 4 ];
 							point.x += numbers[ j + 4 ];
 							point.y += numbers[ j + 5 ];
 							point.y += numbers[ j + 5 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -361,6 +375,7 @@ THREE.SVGLoader.prototype = {
 							control.y = point.y + numbers[ j + 1 ];
 							control.y = point.y + numbers[ j + 1 ];
 							point.x += numbers[ j + 2 ];
 							point.x += numbers[ j + 2 ];
 							point.y += numbers[ j + 3 ];
 							point.y += numbers[ j + 3 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -377,6 +392,7 @@ THREE.SVGLoader.prototype = {
 							control.y = point.y + numbers[ j + 1 ];
 							control.y = point.y + numbers[ j + 1 ];
 							point.x += numbers[ j + 2 ];
 							point.x += numbers[ j + 2 ];
 							point.y += numbers[ j + 3 ];
 							point.y += numbers[ j + 3 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -395,6 +411,7 @@ THREE.SVGLoader.prototype = {
 							control.y = ry;
 							control.y = ry;
 							point.x = point.x + numbers[ j + 0 ];
 							point.x = point.x + numbers[ j + 0 ];
 							point.y = point.y + numbers[ j + 1 ];
 							point.y = point.y + numbers[ j + 1 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -409,6 +426,7 @@ THREE.SVGLoader.prototype = {
 							parseArcCommand(
 							parseArcCommand(
 								path, numbers[ j ], numbers[ j + 1 ], numbers[ j + 2 ], numbers[ j + 3 ], numbers[ j + 4 ], start, point
 								path, numbers[ j ], numbers[ j + 1 ], numbers[ j + 2 ], numbers[ j + 3 ], numbers[ j + 4 ], start, point
 							);
 							);
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						}
 						break;
 						break;
 
 
@@ -432,10 +450,7 @@ THREE.SVGLoader.prototype = {
 
 
 				// console.log( type, parseFloats( data ), parseFloats( data ).length  )
 				// console.log( type, parseFloats( data ), parseFloats( data ).length  )
 
 
-				if ( doSetFirstPoint === true ) {
-					firstPoint.copy( point );
-					doSetFirstPoint = false;
-				}
+				doSetFirstPoint = false;
 
 
 			}
 			}
 
 

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

@@ -522,7 +522,9 @@ THREE.TGALoader.prototype = {
 
 
 		//
 		//
 
 
-		var canvas = document.createElement( 'canvas' );
+		var useOffscreen = typeof OffscreenCanvas !== 'undefined';
+
+		var canvas = useOffscreen ? new OffscreenCanvas( header.width, header.height ) : document.createElement( 'canvas' );
 		canvas.width = header.width;
 		canvas.width = header.width;
 		canvas.height = header.height;
 		canvas.height = header.height;
 
 
@@ -534,7 +536,7 @@ THREE.TGALoader.prototype = {
 
 
 		context.putImageData( imageData, 0, 0 );
 		context.putImageData( imageData, 0, 0 );
 
 
-		return canvas;
+		return useOffscreen ? canvas.transferToImageBitmap() : canvas;
 
 
 	},
 	},
 
 

+ 23 - 19
examples/js/loaders/deprecated/LegacyGLTFLoader.js

@@ -491,8 +491,8 @@ THREE.LegacyGLTFLoader = ( function () {
 	};
 	};
 
 
 	var WEBGL_SIDES = {
 	var WEBGL_SIDES = {
-		1028: THREE.BackSide,  // Culling front
-		1029: THREE.FrontSide  // Culling back
+		1028: THREE.BackSide, // Culling front
+		1029: THREE.FrontSide // Culling back
 		//1032: THREE.NoSide   // Culling front and back, what to do?
 		//1032: THREE.NoSide   // Culling front and back, what to do?
 	};
 	};
 
 
@@ -566,8 +566,10 @@ THREE.LegacyGLTFLoader = ( function () {
 
 
 	function _each( object, callback, thisObj ) {
 	function _each( object, callback, thisObj ) {
 
 
-		if ( !object ) {
+		if ( ! object ) {
+
 			return Promise.resolve();
 			return Promise.resolve();
+
 		}
 		}
 
 
 		var results;
 		var results;
@@ -589,11 +591,11 @@ THREE.LegacyGLTFLoader = ( function () {
 
 
 					if ( value instanceof Promise ) {
 					if ( value instanceof Promise ) {
 
 
-						value.then( function( key, value ) {
+						value.then( function ( key, value ) {
 
 
 							results[ key ] = value;
 							results[ key ] = value;
 
 
-						}.bind( this, idx ));
+						}.bind( this, idx ) );
 
 
 					} else {
 					} else {
 
 
@@ -621,11 +623,11 @@ THREE.LegacyGLTFLoader = ( function () {
 
 
 						if ( value instanceof Promise ) {
 						if ( value instanceof Promise ) {
 
 
-							value.then( function( key, value ) {
+							value.then( function ( key, value ) {
 
 
 								results[ key ] = value;
 								results[ key ] = value;
 
 
-							}.bind( this, key ));
+							}.bind( this, key ) );
 
 
 						} else {
 						} else {
 
 
@@ -641,11 +643,11 @@ THREE.LegacyGLTFLoader = ( function () {
 
 
 		}
 		}
 
 
-		return Promise.all( fns ).then( function() {
+		return Promise.all( fns ).then( function () {
 
 
 			return results;
 			return results;
 
 
-		});
+		} );
 
 
 	}
 	}
 
 
@@ -1210,7 +1212,7 @@ THREE.LegacyGLTFLoader = ( function () {
 
 
 					}
 					}
 
 
-					keys.forEach( function( v ) {
+					keys.forEach( function ( v ) {
 
 
 						if ( khr_material.values[ v ] !== undefined ) materialValues[ v ] = khr_material.values[ v ];
 						if ( khr_material.values[ v ] !== undefined ) materialValues[ v ] = khr_material.values[ v ];
 
 
@@ -1515,7 +1517,7 @@ THREE.LegacyGLTFLoader = ( function () {
 
 
 					materialParams.color = new THREE.Color().fromArray( materialValues.diffuse );
 					materialParams.color = new THREE.Color().fromArray( materialValues.diffuse );
 
 
-				} else if ( typeof( materialValues.diffuse ) === 'string' ) {
+				} else if ( typeof ( materialValues.diffuse ) === 'string' ) {
 
 
 					materialParams.map = dependencies.textures[ materialValues.diffuse ];
 					materialParams.map = dependencies.textures[ materialValues.diffuse ];
 
 
@@ -1523,13 +1525,13 @@ THREE.LegacyGLTFLoader = ( function () {
 
 
 				delete materialParams.diffuse;
 				delete materialParams.diffuse;
 
 
-				if ( typeof( materialValues.reflective ) === 'string' ) {
+				if ( typeof ( materialValues.reflective ) === 'string' ) {
 
 
 					materialParams.envMap = dependencies.textures[ materialValues.reflective ];
 					materialParams.envMap = dependencies.textures[ materialValues.reflective ];
 
 
 				}
 				}
 
 
-				if ( typeof( materialValues.bump ) === 'string' ) {
+				if ( typeof ( materialValues.bump ) === 'string' ) {
 
 
 					materialParams.bumpMap = dependencies.textures[ materialValues.bump ];
 					materialParams.bumpMap = dependencies.textures[ materialValues.bump ];
 
 
@@ -1547,7 +1549,7 @@ THREE.LegacyGLTFLoader = ( function () {
 
 
 					}
 					}
 
 
-				} else if ( typeof( materialValues.emission ) === 'string' ) {
+				} else if ( typeof ( materialValues.emission ) === 'string' ) {
 
 
 					if ( materialType === THREE.MeshBasicMaterial ) {
 					if ( materialType === THREE.MeshBasicMaterial ) {
 
 
@@ -1565,7 +1567,7 @@ THREE.LegacyGLTFLoader = ( function () {
 
 
 					materialParams.specular = new THREE.Color().fromArray( materialValues.specular );
 					materialParams.specular = new THREE.Color().fromArray( materialValues.specular );
 
 
-				} else if ( typeof( materialValues.specular ) === 'string' ) {
+				} else if ( typeof ( materialValues.specular ) === 'string' ) {
 
 
 					materialParams.specularMap = dependencies.textures[ materialValues.specular ];
 					materialParams.specularMap = dependencies.textures[ materialValues.specular ];
 
 
@@ -1670,9 +1672,9 @@ THREE.LegacyGLTFLoader = ( function () {
 
 
 									var parameters = json.techniques[ material.technique ].parameters || {};
 									var parameters = json.techniques[ material.technique ].parameters || {};
 
 
-									for( var attributeName in parameters ) {
+									for ( var attributeName in parameters ) {
 
 
-										if ( parameters [ attributeName ][ 'semantic' ] === attributeId ) {
+										if ( parameters[ attributeName ][ 'semantic' ] === attributeId ) {
 
 
 											geometry.addAttribute( attributeName, bufferAttribute );
 											geometry.addAttribute( attributeName, bufferAttribute );
 
 
@@ -2217,8 +2219,10 @@ THREE.LegacyGLTFLoader = ( function () {
 					if ( child.material && child.material.isRawShaderMaterial ) {
 					if ( child.material && child.material.isRawShaderMaterial ) {
 
 
 						child.gltfShader = new GLTFShader( child, dependencies.nodes );
 						child.gltfShader = new GLTFShader( child, dependencies.nodes );
-						child.onBeforeRender = function(renderer, scene, camera){
-							this.gltfShader.update(scene, camera);
+						child.onBeforeRender = function ( renderer, scene, camera ) {
+
+							this.gltfShader.update( scene, camera );
+
 						};
 						};
 
 
 					}
 					}

+ 1 - 0
examples/js/nodes/Nodes.js

@@ -20,6 +20,7 @@ export { NodeBuilder } from './core/NodeBuilder.js';
 
 
 // inputs
 // inputs
 
 
+export { BoolNode } from './inputs/BoolNode.js';
 export { IntNode } from './inputs/IntNode.js';
 export { IntNode } from './inputs/IntNode.js';
 export { FloatNode } from './inputs/FloatNode.js';
 export { FloatNode } from './inputs/FloatNode.js';
 export { Vector2Node } from './inputs/Vector2Node.js';
 export { Vector2Node } from './inputs/Vector2Node.js';

+ 2 - 0
examples/js/nodes/THREE.Nodes.js

@@ -20,6 +20,7 @@ import {
 
 
 	// inputs
 	// inputs
 
 
+	BoolNode,
 	IntNode,
 	IntNode,
 	FloatNode,
 	FloatNode,
 	Vector2Node,
 	Vector2Node,
@@ -132,6 +133,7 @@ THREE.NodeBuilder = NodeBuilder;
 
 
 // inputs
 // inputs
 
 
+THREE.BoolNode = BoolNode;
 THREE.IntNode = IntNode;
 THREE.IntNode = IntNode;
 THREE.FloatNode = FloatNode;
 THREE.FloatNode = FloatNode;
 THREE.Vector2Node = Vector2Node;
 THREE.Vector2Node = Vector2Node;

+ 2 - 2
examples/js/nodes/accessors/CameraNode.js

@@ -101,7 +101,7 @@ CameraNode.prototype.getType = function ( builder ) {
 
 
 };
 };
 
 
-CameraNode.prototype.isUnique = function ( builder ) {
+CameraNode.prototype.getUnique = function ( builder ) {
 
 
 	switch ( this.scope ) {
 	switch ( this.scope ) {
 
 
@@ -116,7 +116,7 @@ CameraNode.prototype.isUnique = function ( builder ) {
 
 
 };
 };
 
 
-CameraNode.prototype.isShared = function ( builder ) {
+CameraNode.prototype.getShared = function ( builder ) {
 
 
 	switch ( this.scope ) {
 	switch ( this.scope ) {
 
 

+ 1 - 1
examples/js/nodes/accessors/NormalNode.js

@@ -21,7 +21,7 @@ NormalNode.prototype = Object.create( TempNode.prototype );
 NormalNode.prototype.constructor = NormalNode;
 NormalNode.prototype.constructor = NormalNode;
 NormalNode.prototype.nodeType = "Normal";
 NormalNode.prototype.nodeType = "Normal";
 
 
-NormalNode.prototype.isShared = function ( builder ) {
+NormalNode.prototype.getShared = function ( builder ) {
 
 
 	switch ( this.scope ) {
 	switch ( this.scope ) {
 
 

+ 1 - 1
examples/js/nodes/accessors/PositionNode.js

@@ -36,7 +36,7 @@ PositionNode.prototype.getType = function ( ) {
 
 
 };
 };
 
 
-PositionNode.prototype.isShared = function ( builder ) {
+PositionNode.prototype.getShared = function ( builder ) {
 
 
 	switch ( this.scope ) {
 	switch ( this.scope ) {
 
 

+ 1 - 1
examples/js/nodes/core/FunctionNode.js

@@ -25,7 +25,7 @@ FunctionNode.prototype.nodeType = "Function";
 
 
 FunctionNode.prototype.useKeywords = true;
 FunctionNode.prototype.useKeywords = true;
 
 
-FunctionNode.prototype.isShared = function ( builder, output ) {
+FunctionNode.prototype.getShared = function ( builder, output ) {
 
 
 	return ! this.isMethod;
 	return ! this.isMethod;
 
 

+ 12 - 4
examples/js/nodes/core/InputNode.js

@@ -18,7 +18,15 @@ function InputNode( type, params ) {
 InputNode.prototype = Object.create( TempNode.prototype );
 InputNode.prototype = Object.create( TempNode.prototype );
 InputNode.prototype.constructor = InputNode;
 InputNode.prototype.constructor = InputNode;
 
 
-InputNode.prototype.isReadonly = function ( builder ) {
+InputNode.prototype.setReadonly = function ( value ) {
+
+	this.readonly = value;
+
+	return this;
+
+};
+
+InputNode.prototype.getReadonly = function ( builder ) {
 
 
 	return this.readonly;
 	return this.readonly;
 
 
@@ -48,7 +56,7 @@ InputNode.prototype.generate = function ( builder, output, uuid, type, ns, needs
 	type = type || this.getType( builder );
 	type = type || this.getType( builder );
 
 
 	var data = builder.getNodeData( uuid ),
 	var data = builder.getNodeData( uuid ),
-		readonly = this.isReadonly( builder ) && this.generateReadonly !== undefined;
+		readonly = this.getReadonly( builder ) && this.generateReadonly !== undefined;
 
 
 	if ( readonly ) {
 	if ( readonly ) {
 
 
@@ -60,7 +68,7 @@ InputNode.prototype.generate = function ( builder, output, uuid, type, ns, needs
 
 
 			if ( ! data.vertex ) {
 			if ( ! data.vertex ) {
 
 
-				data.vertex = builder.createVertexUniform( type, this, ns, needsUpdate );
+				data.vertex = builder.createVertexUniform( type, this, ns, needsUpdate, this.getLabel() );
 
 
 			}
 			}
 
 
@@ -70,7 +78,7 @@ InputNode.prototype.generate = function ( builder, output, uuid, type, ns, needs
 
 
 			if ( ! data.fragment ) {
 			if ( ! data.fragment ) {
 
 
-				data.fragment = builder.createFragmentUniform( type, this, ns, needsUpdate );
+				data.fragment = builder.createFragmentUniform( type, this, ns, needsUpdate, this.getLabel() );
 
 
 			}
 			}
 
 

+ 28 - 18
examples/js/nodes/core/NodeBuilder.js

@@ -22,7 +22,8 @@ var elements = NodeUtils.elements,
 		vec3: 'v3',
 		vec3: 'v3',
 		vec4: 'v4',
 		vec4: 'v4',
 		mat4: 'v4',
 		mat4: 'v4',
-		int: 'i'
+		int: 'i',
+		bool: 'b'
 	},
 	},
 	convertTypeToFormat = {
 	convertTypeToFormat = {
 		t: 'sampler2D',
 		t: 'sampler2D',
@@ -442,9 +443,7 @@ NodeBuilder.prototype = {
 
 
 	},
 	},
 
 
-	getVar: function ( uuid, type, ns, shader ) {
-
-		shader = shader || 'varying';
+	getVar: function ( uuid, type, ns, shader = 'varying', prefix = 'V', label = '' ) {
 
 
 		var vars = this.getVars( shader ),
 		var vars = this.getVars( shader ),
 			data = vars[ uuid ];
 			data = vars[ uuid ];
@@ -452,7 +451,7 @@ NodeBuilder.prototype = {
 		if ( ! data ) {
 		if ( ! data ) {
 
 
 			var index = vars.length,
 			var index = vars.length,
-				name = ns ? ns : 'nVv' + index;
+				name = ns ? ns : 'node' + prefix + index + ( label ? '_' + label : '' );
 
 
 			data = { name: name, type: type };
 			data = { name: name, type: type };
 
 
@@ -465,9 +464,9 @@ NodeBuilder.prototype = {
 
 
 	},
 	},
 
 
-	getTempVar: function ( uuid, type, ns ) {
+	getTempVar: function ( uuid, type, ns, label ) {
 
 
-		return this.getVar( uuid, type, ns, this.shader );
+		return this.getVar( uuid, type, ns, this.shader, 'T', label );
 
 
 	},
 	},
 
 
@@ -550,14 +549,14 @@ NodeBuilder.prototype = {
 
 
 	},
 	},
 
 
-	createUniform: function ( shader, type, node, ns, needsUpdate ) {
+	createUniform: function ( shader, type, node, ns, needsUpdate, label ) {
 
 
 		var uniforms = this.inputs.uniforms,
 		var uniforms = this.inputs.uniforms,
 			index = uniforms.list.length;
 			index = uniforms.list.length;
 
 
 		var uniform = new NodeUniform( {
 		var uniform = new NodeUniform( {
 			type: type,
 			type: type,
-			name: ns ? ns : 'nVu' + index,
+			name: ns ? ns : 'nodeU' + index + ( label ? '_' + label : '' ),
 			node: node,
 			node: node,
 			needsUpdate: needsUpdate
 			needsUpdate: needsUpdate
 		} );
 		} );
@@ -573,15 +572,15 @@ NodeBuilder.prototype = {
 
 
 	},
 	},
 
 
-	createVertexUniform: function ( type, node, ns, needsUpdate ) {
+	createVertexUniform: function ( type, node, ns, needsUpdate, label ) {
 
 
-		return this.createUniform( 'vertex', type, node, ns, needsUpdate );
+		return this.createUniform( 'vertex', type, node, ns, needsUpdate, label );
 
 
 	},
 	},
 
 
-	createFragmentUniform: function ( type, node, ns, needsUpdate ) {
+	createFragmentUniform: function ( type, node, ns, needsUpdate, label ) {
 
 
-		return this.createUniform( 'fragment', type, node, ns, needsUpdate );
+		return this.createUniform( 'fragment', type, node, ns, needsUpdate, label );
 
 
 	},
 	},
 
 
@@ -821,28 +820,39 @@ NodeBuilder.prototype = {
 			case 'f <- v2' : return code + '.x';
 			case 'f <- v2' : return code + '.x';
 			case 'f <- v3' : return code + '.x';
 			case 'f <- v3' : return code + '.x';
 			case 'f <- v4' : return code + '.x';
 			case 'f <- v4' : return code + '.x';
-			case 'f <- i' : return 'float( ' + code + ' )';
+			case 'f <- i' :
+			case 'f <- b' :	return 'float( ' + code + ' )';
 
 
 			case 'v2 <- f' : return 'vec2( ' + code + ' )';
 			case 'v2 <- f' : return 'vec2( ' + code + ' )';
 			case 'v2 <- v3': return code + '.xy';
 			case 'v2 <- v3': return code + '.xy';
 			case 'v2 <- v4': return code + '.xy';
 			case 'v2 <- v4': return code + '.xy';
-			case 'v2 <- i' : return 'vec2( float( ' + code + ' ) )';
+			case 'v2 <- i' :
+			case 'v2 <- b' : return 'vec2( float( ' + code + ' ) )';
 
 
 			case 'v3 <- f' : return 'vec3( ' + code + ' )';
 			case 'v3 <- f' : return 'vec3( ' + code + ' )';
 			case 'v3 <- v2': return 'vec3( ' + code + ', 0.0 )';
 			case 'v3 <- v2': return 'vec3( ' + code + ', 0.0 )';
 			case 'v3 <- v4': return code + '.xyz';
 			case 'v3 <- v4': return code + '.xyz';
-			case 'v3 <- i' : return 'vec2( float( ' + code + ' ) )';
+			case 'v3 <- i' :
+			case 'v3 <- b' : return 'vec2( float( ' + code + ' ) )';
 
 
 			case 'v4 <- f' : return 'vec4( ' + code + ' )';
 			case 'v4 <- f' : return 'vec4( ' + code + ' )';
 			case 'v4 <- v2': return 'vec4( ' + code + ', 0.0, 1.0 )';
 			case 'v4 <- v2': return 'vec4( ' + code + ', 0.0, 1.0 )';
 			case 'v4 <- v3': return 'vec4( ' + code + ', 1.0 )';
 			case 'v4 <- v3': return 'vec4( ' + code + ', 1.0 )';
-			case 'v4 <- i' : return 'vec4( float( ' + code + ' ) )';
+			case 'v4 <- i' :
+			case 'v4 <- b' : return 'vec4( float( ' + code + ' ) )';
 
 
-			case 'i <- f' : return 'int( ' + code + ' )';
+			case 'i <- f' :
+			case 'i <- b' : return 'int( ' + code + ' )';
 			case 'i <- v2' : return 'int( ' + code + '.x )';
 			case 'i <- v2' : return 'int( ' + code + '.x )';
 			case 'i <- v3' : return 'int( ' + code + '.x )';
 			case 'i <- v3' : return 'int( ' + code + '.x )';
 			case 'i <- v4' : return 'int( ' + code + '.x )';
 			case 'i <- v4' : return 'int( ' + code + '.x )';
 
 
+			case 'b <- f' : return '( ' + code + ' != 0.0 )';
+			case 'b <- v2' : return '( ' + code + ' != vec2( 0.0 ) )';
+			case 'b <- v3' : return '( ' + code + ' != vec3( 0.0 ) )';
+			case 'b <- v4' : return '( ' + code + ' != vec4( 0.0 ) )';
+			case 'b <- i' : return '( ' + code + ' != 0 )';
+
 		}
 		}
 
 
 		return code;
 		return code;

+ 23 - 9
examples/js/nodes/core/TempNode.js

@@ -23,9 +23,9 @@ TempNode.prototype.build = function ( builder, output, uuid, ns ) {
 
 
 	output = output || this.getType( builder );
 	output = output || this.getType( builder );
 
 
-	if ( this.isShared( builder, output ) ) {
+	if ( this.getShared( builder, output ) ) {
 
 
-		var isUnique = this.isUnique( builder, output );
+		var isUnique = this.getUnique( builder, output );
 
 
 		if ( isUnique && this.constructor.uuid === undefined ) {
 		if ( isUnique && this.constructor.uuid === undefined ) {
 
 
@@ -40,7 +40,7 @@ TempNode.prototype.build = function ( builder, output, uuid, ns ) {
 
 
 		if ( builder.parsing ) {
 		if ( builder.parsing ) {
 
 
-			if ( ( data.deps || 0 ) > 0 ) {
+			if ( ( data.deps || 0 ) > 0 || this.getLabel() ) {
 
 
 				this.appendDepsNode( builder, data, output );
 				this.appendDepsNode( builder, data, output );
 
 
@@ -56,7 +56,7 @@ TempNode.prototype.build = function ( builder, output, uuid, ns ) {
 
 
 			return data.name;
 			return data.name;
 
 
-		} else if ( ! this.isShared( builder, type ) || ( ! builder.optimize || data.deps == 1 ) ) {
+		} else if ( ! this.getLabel() && ( ! this.getShared( builder, type ) || ( ! builder.optimize || data.deps === 1 ) ) ) {
 
 
 			return Node.prototype.build.call( this, builder, output, uuid );
 			return Node.prototype.build.call( this, builder, output, uuid );
 
 
@@ -88,23 +88,37 @@ TempNode.prototype.build = function ( builder, output, uuid, ns ) {
 
 
 };
 };
 
 
-TempNode.prototype.isShared = function ( builder, output ) {
+TempNode.prototype.getShared = function ( builder, output ) {
 
 
 	return output !== 'sampler2D' && output !== 'samplerCube' && this.shared;
 	return output !== 'sampler2D' && output !== 'samplerCube' && this.shared;
 
 
 };
 };
 
 
-TempNode.prototype.isUnique = function ( builder, output ) {
+TempNode.prototype.getUnique = function ( builder, output ) {
 
 
 	return this.unique;
 	return this.unique;
 
 
 };
 };
 
 
+TempNode.prototype.setLabel = function ( name ) {
+
+	this.label = name;
+
+	return this;
+
+};
+
+TempNode.prototype.getLabel = function ( builder ) {
+
+	return this.label;
+
+};
+
 TempNode.prototype.getUuid = function ( unique ) {
 TempNode.prototype.getUuid = function ( unique ) {
 
 
 	var uuid = unique || unique == undefined ? this.constructor.uuid || this.uuid : this.uuid;
 	var uuid = unique || unique == undefined ? this.constructor.uuid || this.uuid : this.uuid;
 
 
-	if ( typeof this.scope == "string" ) uuid = this.scope + '-' + uuid;
+	if ( typeof this.scope === "string" ) uuid = this.scope + '-' + uuid;
 
 
 	return uuid;
 	return uuid;
 
 
@@ -122,11 +136,11 @@ TempNode.prototype.getTemp = function ( builder, uuid ) {
 
 
 TempNode.prototype.generate = function ( builder, output, uuid, type, ns ) {
 TempNode.prototype.generate = function ( builder, output, uuid, type, ns ) {
 
 
-	if ( ! this.isShared( builder, output ) ) console.error( "THREE.TempNode is not shared!" );
+	if ( ! this.getShared( builder, output ) ) console.error( "THREE.TempNode is not shared!" );
 
 
 	uuid = uuid || this.uuid;
 	uuid = uuid || this.uuid;
 
 
-	return builder.getTempVar( uuid, type || this.getType( builder ), ns ).name;
+	return builder.getTempVar( uuid, type || this.getType( builder ), ns, this.getLabel() ).name;
 
 
 };
 };
 
 

+ 51 - 0
examples/js/nodes/inputs/BoolNode.js

@@ -0,0 +1,51 @@
+/**
+ * @author sunag / http://www.sunag.com.br/
+ */
+
+import { InputNode } from '../core/InputNode.js';
+
+function BoolNode( value ) {
+
+	InputNode.call( this, 'b' );
+
+	this.value = Boolean( value );
+
+}
+
+BoolNode.prototype = Object.create( InputNode.prototype );
+BoolNode.prototype.constructor = BoolNode;
+BoolNode.prototype.nodeType = "Bool";
+
+BoolNode.prototype.generateReadonly = function ( builder, output, uuid, type, ns, needsUpdate ) {
+
+	return builder.format( this.value, type, output );
+
+};
+
+BoolNode.prototype.copy = function ( source ) {
+
+	InputNode.prototype.copy.call( this, source );
+
+	this.value = source.value;
+
+};
+
+BoolNode.prototype.toJSON = function ( meta ) {
+
+	var data = this.getJSONNode( meta );
+
+	if ( ! data ) {
+
+		data = this.createJSONNode( meta );
+
+		data.value = this.value;
+
+		if ( this.readonly === true ) data.readonly = true;
+
+	}
+
+	return data;
+
+};
+
+export { BoolNode };

+ 6 - 2
examples/js/nodes/inputs/RTTNode.js

@@ -72,7 +72,9 @@ RTTNode.prototype.updateFramesaveTo = function ( frame ) {
 
 
 	this.saveToCurrent = this.saveTo;
 	this.saveToCurrent = this.saveTo;
 
 
-	frame.renderer.render( this.saveToScene, this.camera, this.saveTo.renderTarget, this.saveTo.clear );
+	frame.renderer.setRenderTarget( this.saveTo.renderTarget );
+	if ( this.saveTo.clear ) frame.renderer.clear();
+	frame.renderer.render( this.saveToScene, this.camera );
 
 
 };
 };
 
 
@@ -96,7 +98,9 @@ RTTNode.prototype.updateFrame = function ( frame ) {
 
 
 			}
 			}
 
 
-			frame.renderer.render( this.scene, this.camera, this.renderTarget, this.clear );
+			frame.renderer.setRenderTarget( this.renderTarget );
+			if ( this.clear ) frame.renderer.clear();
+			frame.renderer.render( this.scene, this.camera );
 
 
 		}
 		}
 
 

+ 1 - 1
examples/js/nodes/inputs/ScreenNode.js

@@ -15,7 +15,7 @@ ScreenNode.prototype = Object.create( TextureNode.prototype );
 ScreenNode.prototype.constructor = ScreenNode;
 ScreenNode.prototype.constructor = ScreenNode;
 ScreenNode.prototype.nodeType = "Screen";
 ScreenNode.prototype.nodeType = "Screen";
 
 
-ScreenNode.prototype.isUnique = function () {
+ScreenNode.prototype.getUnique = function () {
 
 
 	return true;
 	return true;
 
 

+ 1 - 0
examples/js/nodes/materials/PhongNodeMaterial.js

@@ -32,6 +32,7 @@ NodeUtils.addShortcuts( PhongNodeMaterial.prototype, 'fragment', [
 	'ao',
 	'ao',
 	'environment',
 	'environment',
 	'environmentAlpha',
 	'environmentAlpha',
+	'mask',
 	'position'
 	'position'
 ] );
 ] );
 
 

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

@@ -22,6 +22,7 @@ SpriteNodeMaterial.prototype.constructor = SpriteNodeMaterial;
 NodeUtils.addShortcuts( SpriteNodeMaterial.prototype, 'fragment', [
 NodeUtils.addShortcuts( SpriteNodeMaterial.prototype, 'fragment', [
 	'color',
 	'color',
 	'alpha',
 	'alpha',
+	'mask',
 	'position',
 	'position',
 	'spherical'
 	'spherical'
 ] );
 ] );

+ 1 - 0
examples/js/nodes/materials/StandardNodeMaterial.js

@@ -34,6 +34,7 @@ NodeUtils.addShortcuts( StandardNodeMaterial.prototype, 'fragment', [
 	'shadow',
 	'shadow',
 	'ao',
 	'ao',
 	'environment',
 	'environment',
+	'mask',
 	'position'
 	'position'
 ] );
 ] );
 
 

+ 21 - 2
examples/js/nodes/materials/nodes/PhongNode.js

@@ -103,6 +103,8 @@ PhongNode.prototype.build = function ( builder ) {
 
 
 		// parse all nodes to reuse generate codes
 		// parse all nodes to reuse generate codes
 
 
+		if ( this.mask ) this.mask.parse( builder );
+
 		this.color.parse( builder, { slot: 'color' } );
 		this.color.parse( builder, { slot: 'color' } );
 		this.specular.parse( builder );
 		this.specular.parse( builder );
 		this.shininess.parse( builder );
 		this.shininess.parse( builder );
@@ -123,6 +125,8 @@ PhongNode.prototype.build = function ( builder ) {
 
 
 		// build code
 		// build code
 
 
+		var mask = this.mask ? this.mask.buildCode( builder, 'b' ) : undefined;
+
 		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 specular = this.specular.buildCode( builder, 'c' );
 		var shininess = this.shininess.buildCode( builder, 'f' );
 		var shininess = this.shininess.buildCode( builder, 'f' );
@@ -157,8 +161,19 @@ PhongNode.prototype.build = function ( builder ) {
 			"#include <normal_fragment_begin>",
 			"#include <normal_fragment_begin>",
 
 
 			// prevent undeclared material
 			// prevent undeclared material
-			"	BlinnPhongMaterial material;",
+			"	BlinnPhongMaterial material;"
+		];
+
+		if ( mask ) {
+
+			output.push(
+				mask.code,
+				'if ( ! ' + mask.result + ' ) discard;'
+			);
 
 
+		}
+
+		output.push(
 			color.code,
 			color.code,
 			"	vec3 diffuseColor = " + color.result + ";",
 			"	vec3 diffuseColor = " + color.result + ";",
 			"	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
 			"	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
@@ -172,7 +187,7 @@ PhongNode.prototype.build = function ( builder ) {
 			"	float shininess = max( 0.0001, " + shininess.result + " );",
 			"	float shininess = max( 0.0001, " + shininess.result + " );",
 
 
 			"	float specularStrength = 1.0;" // Ignored in MaterialNode ( replace to specular )
 			"	float specularStrength = 1.0;" // Ignored in MaterialNode ( replace to specular )
-		];
+		);
 
 
 		if ( alpha ) {
 		if ( alpha ) {
 
 
@@ -335,6 +350,8 @@ PhongNode.prototype.copy = function ( source ) {
 	this.specular = source.specular;
 	this.specular = source.specular;
 	this.shininess = source.shininess;
 	this.shininess = source.shininess;
 
 
+	if ( source.mask ) this.mask = source.mask;
+
 	if ( source.alpha ) this.alpha = source.alpha;
 	if ( source.alpha ) this.alpha = source.alpha;
 
 
 	if ( source.normal ) this.normal = source.normal;
 	if ( source.normal ) this.normal = source.normal;
@@ -370,6 +387,8 @@ PhongNode.prototype.toJSON = function ( meta ) {
 		data.specular = this.specular.toJSON( meta ).uuid;
 		data.specular = this.specular.toJSON( meta ).uuid;
 		data.shininess = this.shininess.toJSON( meta ).uuid;
 		data.shininess = this.shininess.toJSON( meta ).uuid;
 
 
+		if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
+
 		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
 		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
 
 
 		if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;
 		if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;

+ 23 - 6
examples/js/nodes/materials/nodes/SpriteNode.js

@@ -123,18 +123,31 @@ SpriteNode.prototype.build = function ( builder ) {
 
 
 		// parse all nodes to reuse generate codes
 		// parse all nodes to reuse generate codes
 
 
+		if ( this.mask ) this.mask.parse( builder );
+
 		if ( this.alpha ) this.alpha.parse( builder );
 		if ( this.alpha ) this.alpha.parse( builder );
 
 
 		this.color.parse( builder, { slot: 'color' } );
 		this.color.parse( builder, { slot: 'color' } );
 
 
 		// build code
 		// build code
 
 
-		var alpha = this.alpha ? this.alpha.buildCode( builder, 'f' ) : undefined,
-			color = this.color.buildCode( builder, 'c', { slot: 'color' } );
+		var mask = this.mask ? this.mask.buildCode( builder, 'b' ) : undefined,
+			alpha = this.alpha ? this.alpha.buildCode( builder, 'f' ) : undefined,
+			color = this.color.buildCode( builder, 'c', { slot: 'color' } ),
+			output = [];
+
+		if ( mask ) {
+
+			output.push(
+				mask.code,
+				'if ( ! ' + mask.result + ' ) discard;'
+			);
+
+		}
 
 
 		if ( alpha ) {
 		if ( alpha ) {
 
 
-			output = [
+			output.push(
 				alpha.code,
 				alpha.code,
 				'#ifdef ALPHATEST',
 				'#ifdef ALPHATEST',
 
 
@@ -143,14 +156,14 @@ SpriteNode.prototype.build = function ( builder ) {
 				'#endif',
 				'#endif',
 				color.code,
 				color.code,
 				"gl_FragColor = vec4( " + color.result + ", " + alpha.result + " );"
 				"gl_FragColor = vec4( " + color.result + ", " + alpha.result + " );"
-			];
+			);
 
 
 		} else {
 		} else {
 
 
-			output = [
+			output.push(
 				color.code,
 				color.code,
 				"gl_FragColor = vec4( " + color.result + ", 1.0 );"
 				"gl_FragColor = vec4( " + color.result + ", 1.0 );"
-			];
+			);
 
 
 		}
 		}
 
 
@@ -180,6 +193,8 @@ SpriteNode.prototype.copy = function ( source ) {
 
 
 	if ( source.spherical !== undefined ) this.spherical = source.spherical;
 	if ( source.spherical !== undefined ) this.spherical = source.spherical;
 
 
+	if ( source.mask ) this.mask = source.mask;
+
 	if ( source.alpha ) this.alpha = source.alpha;
 	if ( source.alpha ) this.alpha = source.alpha;
 
 
 };
 };
@@ -202,6 +217,8 @@ SpriteNode.prototype.toJSON = function ( meta ) {
 
 
 		if ( this.spherical === false ) data.spherical = false;
 		if ( this.spherical === false ) data.spherical = false;
 
 
+		if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
+
 		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
 		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
 
 
 	}
 	}

+ 22 - 3
examples/js/nodes/materials/nodes/StandardNode.js

@@ -117,6 +117,8 @@ StandardNode.prototype.build = function ( builder ) {
 
 
 		// parse all nodes to reuse generate codes
 		// parse all nodes to reuse generate codes
 
 
+		if ( this.mask ) this.mask.parse( builder );
+
 		this.color.parse( builder, { slot: 'color', context: contextGammaOnly } );
 		this.color.parse( builder, { slot: 'color', context: contextGammaOnly } );
 		this.roughness.parse( builder );
 		this.roughness.parse( builder );
 		this.metalness.parse( builder );
 		this.metalness.parse( builder );
@@ -141,6 +143,8 @@ StandardNode.prototype.build = function ( builder ) {
 
 
 		// build code
 		// build code
 
 
+		var mask = this.mask ? this.mask.buildCode( builder, 'b' ) : undefined;
+
 		var color = this.color.buildCode( builder, 'c', { slot: 'color', context: contextGammaOnly } );
 		var color = this.color.buildCode( builder, 'c', { slot: 'color', context: contextGammaOnly } );
 		var roughness = this.roughness.buildCode( builder, 'f' );
 		var roughness = this.roughness.buildCode( builder, 'f' );
 		var metalness = this.metalness.buildCode( builder, 'f' );
 		var metalness = this.metalness.buildCode( builder, 'f' );
@@ -194,8 +198,19 @@ StandardNode.prototype.build = function ( builder ) {
 
 
 			// add before: prevent undeclared material
 			// add before: prevent undeclared material
 			"	PhysicalMaterial material;",
 			"	PhysicalMaterial material;",
-			"	material.diffuseColor = vec3( 1.0 );",
+			"	material.diffuseColor = vec3( 1.0 );"
+		];
+
+		if ( mask ) {
+
+			output.push(
+				mask.code,
+				'if ( ! ' + mask.result + ' ) discard;'
+			);
 
 
+		}
+
+		output.push(
 			color.code,
 			color.code,
 			"	vec3 diffuseColor = " + color.result + ";",
 			"	vec3 diffuseColor = " + color.result + ";",
 			"	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
 			"	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
@@ -207,7 +222,7 @@ StandardNode.prototype.build = function ( builder ) {
 
 
 			metalness.code,
 			metalness.code,
 			"	float metalnessFactor = " + metalness.result + ";"
 			"	float metalnessFactor = " + metalness.result + ";"
-		];
+		);
 
 
 		if ( alpha ) {
 		if ( alpha ) {
 
 
@@ -215,7 +230,7 @@ StandardNode.prototype.build = function ( builder ) {
 				alpha.code,
 				alpha.code,
 				'#ifdef ALPHATEST',
 				'#ifdef ALPHATEST',
 
 
-				'if ( ' + alpha.result + ' <= ALPHATEST ) discard;',
+				'	if ( ' + alpha.result + ' <= ALPHATEST ) discard;',
 
 
 				'#endif'
 				'#endif'
 			);
 			);
@@ -403,6 +418,8 @@ StandardNode.prototype.copy = function ( source ) {
 	this.roughness = source.roughness;
 	this.roughness = source.roughness;
 	this.metalness = source.metalness;
 	this.metalness = source.metalness;
 
 
+	if ( source.mask ) this.mask = source.mask;
+
 	if ( source.alpha ) this.alpha = source.alpha;
 	if ( source.alpha ) this.alpha = source.alpha;
 
 
 	if ( source.normal ) this.normal = source.normal;
 	if ( source.normal ) this.normal = source.normal;
@@ -442,6 +459,8 @@ StandardNode.prototype.toJSON = function ( meta ) {
 		data.roughness = this.roughness.toJSON( meta ).uuid;
 		data.roughness = this.roughness.toJSON( meta ).uuid;
 		data.metalness = this.metalness.toJSON( meta ).uuid;
 		data.metalness = this.metalness.toJSON( meta ).uuid;
 
 
+		if ( this.mask ) data.mask = this.mask.toJSON( meta ).uuid;
+
 		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
 		if ( this.alpha ) data.alpha = this.alpha.toJSON( meta ).uuid;
 
 
 		if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;
 		if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;

+ 35 - 16
examples/js/nodes/math/CondNode.js

@@ -4,18 +4,18 @@
 
 
 import { TempNode } from '../core/TempNode.js';
 import { TempNode } from '../core/TempNode.js';
 
 
-function CondNode( a, b, ifNode, elseNode, op ) {
+function CondNode( a, b, op, ifNode, elseNode ) {
 
 
 	TempNode.call( this );
 	TempNode.call( this );
 
 
 	this.a = a;
 	this.a = a;
 	this.b = b;
 	this.b = b;
 
 
+	this.op = op;
+	
 	this.ifNode = ifNode;
 	this.ifNode = ifNode;
 	this.elseNode = elseNode;
 	this.elseNode = elseNode;
 
 
-	this.op = op;
-
 }
 }
 
 
 CondNode.EQUAL = '==';
 CondNode.EQUAL = '==';
@@ -31,13 +31,22 @@ CondNode.prototype.nodeType = "Cond";
 
 
 CondNode.prototype.getType = function ( builder ) {
 CondNode.prototype.getType = function ( builder ) {
 
 
-	if ( builder.getTypeLength( this.elseNode.getType( builder ) ) > builder.getTypeLength( this.ifNode.getType( builder ) ) ) {
+	if (this.ifNode) {
+		
+		var ifType = this.ifNode.getType( builder );
+		var elseType = this.elseNode.getType( builder );
+		
+		if ( builder.getTypeLength( elseType ) > builder.getTypeLength( ifType ) ) {
 
 
-		return this.elseNode.getType( builder );
+			return elseType;
 
 
-	}
+		}
 
 
-	return this.ifNode.getType( builder );
+		return ifType;
+		
+	}
+	
+	return 'b';
 
 
 };
 };
 
 
@@ -59,10 +68,20 @@ CondNode.prototype.generate = function ( builder, output ) {
 		condType = this.getCondType( builder ),
 		condType = this.getCondType( builder ),
 		a = this.a.build( builder, condType ),
 		a = this.a.build( builder, condType ),
 		b = this.b.build( builder, condType ),
 		b = this.b.build( builder, condType ),
-		ifNode = this.ifNode.build( builder, type ),
-		elseNode = this.elseNode.build( builder, type );
-
-	var code = '( ' + [ a, this.op, b, '?', ifNode, ':', elseNode ].join( ' ' ) + ' )';
+		code;
+		
+	if (this.ifNode) {
+		
+		var ifCode = this.ifNode.build( builder, type ),
+			elseCode = this.elseNode.build( builder, type );
+		
+		code = '( ' + [ a, this.op, b, '?', ifCode, ':', elseCode ].join( ' ' ) + ' )';
+		
+	} else {
+
+		code = '( ' + a + ' ' + this.op + ' ' +  b  + ' )';
+		
+	}
 
 
 	return builder.format( code, this.getType( builder ), output );
 	return builder.format( code, this.getType( builder ), output );
 
 
@@ -75,11 +94,11 @@ CondNode.prototype.copy = function ( source ) {
 	this.a = source.a;
 	this.a = source.a;
 	this.b = source.b;
 	this.b = source.b;
 
 
+	this.op = source.op;
+
 	this.ifNode = source.ifNode;
 	this.ifNode = source.ifNode;
 	this.elseNode = source.elseNode;
 	this.elseNode = source.elseNode;
 
 
-	this.op = source.op;
-
 };
 };
 
 
 CondNode.prototype.toJSON = function ( meta ) {
 CondNode.prototype.toJSON = function ( meta ) {
@@ -93,11 +112,11 @@ CondNode.prototype.toJSON = function ( meta ) {
 		data.a = this.a.toJSON( meta ).uuid;
 		data.a = this.a.toJSON( meta ).uuid;
 		data.b = this.b.toJSON( meta ).uuid;
 		data.b = this.b.toJSON( meta ).uuid;
 
 
-		data.ifNode = this.ifNode.toJSON( meta ).uuid;
-		data.elseNode = this.elseNode.toJSON( meta ).uuid;
-
 		data.op = this.op;
 		data.op = this.op;
 
 
+		if ( data.ifNode ) data.ifNode = this.ifNode.toJSON( meta ).uuid;
+		if ( data.elseNode ) data.elseNode = this.elseNode.toJSON( meta ).uuid;
+
 	}
 	}
 
 
 	return data;
 	return data;

+ 4 - 2
examples/js/nodes/postprocessing/NodePostProcessing.js

@@ -16,7 +16,7 @@ function NodePostProcessing( renderer, renderTarget ) {
 			stencilBuffer: false
 			stencilBuffer: false
 		};
 		};
 
 
-		var size = renderer.getDrawingBufferSize();
+		var size = renderer.getDrawingBufferSize( new THREE.Vector2() );
 		renderTarget = new THREE.WebGLRenderTarget( size.width, size.height, parameters );
 		renderTarget = new THREE.WebGLRenderTarget( size.width, size.height, parameters );
 
 
 	}
 	}
@@ -64,10 +64,12 @@ NodePostProcessing.prototype = {
 		frame.setRenderer( this.renderer )
 		frame.setRenderer( this.renderer )
 			.setRenderTexture( this.renderTarget.texture );
 			.setRenderTexture( this.renderTarget.texture );
 
 
-		this.renderer.render( scene, camera, this.renderTarget );
+		this.renderer.setRenderTarget( this.renderTarget );
+		this.renderer.render( scene, camera );
 
 
 		frame.updateNode( this.material );
 		frame.updateNode( this.material );
 
 
+		this.renderer.setRenderTarget( null );
 		this.renderer.render( this.scene, this.camera );
 		this.renderer.render( this.scene, this.camera );
 
 
 	},
 	},

+ 2 - 2
examples/js/nodes/utils/ColorSpaceNode.js

@@ -131,7 +131,7 @@ ColorSpaceNode.Nodes = ( function () {
 	var LinearToLogLuv = new FunctionNode( [
 	var LinearToLogLuv = new FunctionNode( [
 		"vec4 LinearToLogLuv( in vec4 value ) {",
 		"vec4 LinearToLogLuv( in vec4 value ) {",
 
 
-		"	vec3 Xp_Y_XYZp = value.rgb * cLogLuvM;",
+		"	vec3 Xp_Y_XYZp = cLogLuvM * value.rgb;",
 		"	Xp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));",
 		"	Xp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));",
 		"	vec4 vResult;",
 		"	vec4 vResult;",
 		"	vResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;",
 		"	vResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;",
@@ -155,7 +155,7 @@ ColorSpaceNode.Nodes = ( function () {
 		"	Xp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);",
 		"	Xp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);",
 		"	Xp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;",
 		"	Xp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;",
 		"	Xp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;",
 		"	Xp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;",
-		"	vec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;",
+		"	vec3 vRGB = cLogLuvInverseM * Xp_Y_XYZp.rgb;",
 		"	return vec4( max(vRGB, 0.0), 1.0 );",
 		"	return vec4( max(vRGB, 0.0), 1.0 );",
 
 
 		"}"
 		"}"

+ 3 - 3
examples/js/nodes/utils/TimerNode.js

@@ -12,7 +12,7 @@ function TimerNode( scale, scope, timeScale ) {
 	this.scale = scale !== undefined ? scale : 1;
 	this.scale = scale !== undefined ? scale : 1;
 	this.scope = scope || TimerNode.GLOBAL;
 	this.scope = scope || TimerNode.GLOBAL;
 
 
-	this.timeScale = timeScale !== undefined ? timeScale : this.scale !== 1;
+	this.timeScale = timeScale !== undefined ? timeScale : scale !== undefined;
 
 
 }
 }
 
 
@@ -24,7 +24,7 @@ TimerNode.prototype = Object.create( FloatNode.prototype );
 TimerNode.prototype.constructor = TimerNode;
 TimerNode.prototype.constructor = TimerNode;
 TimerNode.prototype.nodeType = "Timer";
 TimerNode.prototype.nodeType = "Timer";
 
 
-TimerNode.prototype.isReadonly = function () {
+TimerNode.prototype.getReadonly = function () {
 
 
 	// never use TimerNode as readonly but aways as "uniform"
 	// never use TimerNode as readonly but aways as "uniform"
 
 
@@ -32,7 +32,7 @@ TimerNode.prototype.isReadonly = function () {
 
 
 };
 };
 
 
-TimerNode.prototype.isUnique = function () {
+TimerNode.prototype.getUnique = function () {
 
 
 	// share TimerNode "uniform" input if is used on more time with others TimerNode
 	// share TimerNode "uniform" input if is used on more time with others TimerNode
 
 

+ 1 - 1
examples/js/nodes/utils/VelocityNode.js

@@ -21,7 +21,7 @@ VelocityNode.prototype = Object.create( Vector3Node.prototype );
 VelocityNode.prototype.constructor = VelocityNode;
 VelocityNode.prototype.constructor = VelocityNode;
 VelocityNode.prototype.nodeType = "Velocity";
 VelocityNode.prototype.nodeType = "Velocity";
 
 
-VelocityNode.prototype.isReadonly = function ( builder ) {
+VelocityNode.prototype.getReadonly = function ( builder ) {
 
 
 	return false;
 	return false;
 
 

+ 12 - 6
examples/js/objects/Fire.js

@@ -342,7 +342,8 @@ THREE.Fire = function ( geometry, options ) {
 
 
 		this.sourceMaterial.uniforms[ "densityMap" ].value = this.field0.texture;
 		this.sourceMaterial.uniforms[ "densityMap" ].value = this.field0.texture;
 
 
-		renderer.render( this.fieldScene, this.orthoCamera, this.field1 );
+		renderer.setRenderTarget( this.field1 );
+		renderer.render( this.fieldScene, this.orthoCamera );
 
 
 		this.sourceMesh.visible = false;
 		this.sourceMesh.visible = false;
 
 
@@ -356,7 +357,8 @@ THREE.Fire = function ( geometry, options ) {
 
 
 		this.diffuseMaterial.uniforms[ "densityMap" ].value = this.field0.texture;
 		this.diffuseMaterial.uniforms[ "densityMap" ].value = this.field0.texture;
 
 
-		renderer.render( this.fieldScene, this.orthoCamera, this.field1 );
+		renderer.setRenderTarget( this.field1 );
+		renderer.render( this.fieldScene, this.orthoCamera );
 
 
 		this.diffuseMesh.visible = false;
 		this.diffuseMesh.visible = false;
 
 
@@ -370,7 +372,8 @@ THREE.Fire = function ( geometry, options ) {
 
 
 		this.driftMaterial.uniforms[ "densityMap" ].value = this.field0.texture;
 		this.driftMaterial.uniforms[ "densityMap" ].value = this.field0.texture;
 
 
-		renderer.render( this.fieldScene, this.orthoCamera, this.field1 );
+		renderer.setRenderTarget( this.field1 );
+		renderer.render( this.fieldScene, this.orthoCamera );
 
 
 		this.driftMesh.visible = false;
 		this.driftMesh.visible = false;
 
 
@@ -386,7 +389,8 @@ THREE.Fire = function ( geometry, options ) {
 
 
 		this.projMaterial1.uniforms[ "densityMap" ].value = this.field0.texture;
 		this.projMaterial1.uniforms[ "densityMap" ].value = this.field0.texture;
 
 
-		renderer.render( this.fieldScene, this.orthoCamera, this.fieldProj );
+		renderer.setRenderTarget( this.fieldProj );
+		renderer.render( this.fieldScene, this.orthoCamera );
 
 
 		this.projMesh1.visible = false;
 		this.projMesh1.visible = false;
 
 
@@ -398,7 +402,8 @@ THREE.Fire = function ( geometry, options ) {
 
 
 		for ( var i = 0; i < 20; i ++ ) {
 		for ( var i = 0; i < 20; i ++ ) {
 
 
-			renderer.render( this.fieldScene, this.orthoCamera, this.field1 );
+			renderer.setRenderTarget( this.field1 );
+			renderer.render( this.fieldScene, this.orthoCamera );
 
 
 			var temp = this.field1;
 			var temp = this.field1;
 			this.field1 = this.fieldProj;
 			this.field1 = this.fieldProj;
@@ -417,7 +422,8 @@ THREE.Fire = function ( geometry, options ) {
 
 
 		this.projMesh3.visible = true;
 		this.projMesh3.visible = true;
 
 
-		renderer.render( this.fieldScene, this.orthoCamera, this.field1 );
+		renderer.setRenderTarget( this.field1 );
+		renderer.render( this.fieldScene, this.orthoCamera );
 
 
 		this.projMesh3.visible = false;
 		this.projMesh3.visible = false;
 
 

+ 1 - 1
examples/js/objects/Lensflare.js

@@ -162,7 +162,7 @@ THREE.Lensflare = function () {
 
 
 	this.onBeforeRender = function ( renderer, scene, camera ) {
 	this.onBeforeRender = function ( renderer, scene, camera ) {
 
 
-		viewport.copy( renderer.getCurrentViewport() );
+		renderer.getCurrentViewport( viewport );
 
 
 		var invAspect = viewport.w / viewport.z;
 		var invAspect = viewport.w / viewport.z;
 		var halfViewportWidth = viewport.z / 2.0;
 		var halfViewportWidth = viewport.z / 2.0;

+ 5 - 2
examples/js/objects/Reflector.js

@@ -33,6 +33,7 @@ THREE.Reflector = function ( geometry, options ) {
 	var view = new THREE.Vector3();
 	var view = new THREE.Vector3();
 	var target = new THREE.Vector3();
 	var target = new THREE.Vector3();
 	var q = new THREE.Vector4();
 	var q = new THREE.Vector4();
+	var size = new THREE.Vector2();
 
 
 	var textureMatrix = new THREE.Matrix4();
 	var textureMatrix = new THREE.Matrix4();
 	var virtualCamera = new THREE.PerspectiveCamera();
 	var virtualCamera = new THREE.PerspectiveCamera();
@@ -160,7 +161,9 @@ THREE.Reflector = function ( geometry, options ) {
 		renderer.vr.enabled = false; // Avoid camera modification and recursion
 		renderer.vr.enabled = false; // Avoid camera modification and recursion
 		renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
 		renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
 
 
-		renderer.render( scene, virtualCamera, renderTarget, true );
+		renderer.setRenderTarget( renderTarget );
+		renderer.clear();
+		renderer.render( scene, virtualCamera );
 
 
 		renderer.vr.enabled = currentVrEnabled;
 		renderer.vr.enabled = currentVrEnabled;
 		renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
 		renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
@@ -173,7 +176,7 @@ THREE.Reflector = function ( geometry, options ) {
 
 
 		if ( bounds !== undefined ) {
 		if ( bounds !== undefined ) {
 
 
-			var size = renderer.getSize();
+			renderer.getSize( size );
 			var pixelRatio = renderer.getPixelRatio();
 			var pixelRatio = renderer.getPixelRatio();
 
 
 			viewport.x = bounds.x * size.width * pixelRatio;
 			viewport.x = bounds.x * size.width * pixelRatio;

+ 5 - 2
examples/js/objects/Refractor.js

@@ -187,6 +187,7 @@ THREE.Refractor = function ( geometry, options ) {
 	var render = ( function () {
 	var render = ( function () {
 
 
 		var viewport = new THREE.Vector4();
 		var viewport = new THREE.Vector4();
+		var size = new THREE.Vector2();
 
 
 		return function render( renderer, scene, camera ) {
 		return function render( renderer, scene, camera ) {
 
 
@@ -199,7 +200,9 @@ THREE.Refractor = function ( geometry, options ) {
 			renderer.vr.enabled = false; // avoid camera modification
 			renderer.vr.enabled = false; // avoid camera modification
 			renderer.shadowMap.autoUpdate = false; // avoid re-computing shadows
 			renderer.shadowMap.autoUpdate = false; // avoid re-computing shadows
 
 
-			renderer.render( scene, virtualCamera, renderTarget, true );
+			renderer.setRenderTarget( renderTarget );
+			renderer.clear();
+			renderer.render( scene, virtualCamera );
 
 
 			renderer.vr.enabled = currentVrEnabled;
 			renderer.vr.enabled = currentVrEnabled;
 			renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
 			renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
@@ -211,7 +214,7 @@ THREE.Refractor = function ( geometry, options ) {
 
 
 			if ( bounds !== undefined ) {
 			if ( bounds !== undefined ) {
 
 
-				var size = renderer.getSize();
+				renderer.getSize( size );
 				var pixelRatio = renderer.getPixelRatio();
 				var pixelRatio = renderer.getPixelRatio();
 
 
 				viewport.x = bounds.x * size.width * pixelRatio;
 				viewport.x = bounds.x * size.width * pixelRatio;

+ 3 - 1
examples/js/objects/Water.js

@@ -291,7 +291,9 @@ THREE.Water = function ( geometry, options ) {
 		renderer.vr.enabled = false; // Avoid camera modification and recursion
 		renderer.vr.enabled = false; // Avoid camera modification and recursion
 		renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
 		renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
 
 
-		renderer.render( scene, mirrorCamera, renderTarget, true );
+		renderer.setRenderTarget( renderTarget );
+		renderer.clear();
+		renderer.render( scene, mirrorCamera );
 
 
 		scope.visible = true;
 		scope.visible = true;
 
 

+ 2 - 1
examples/js/pmrem/PMREMCubeUVPacker.js

@@ -137,7 +137,8 @@ THREE.PMREMCubeUVPacker = ( function () {
 			renderer.gammaOutput = false;
 			renderer.gammaOutput = false;
 			renderer.toneMapping = THREE.LinearToneMapping;
 			renderer.toneMapping = THREE.LinearToneMapping;
 			renderer.toneMappingExposure = 1.0;
 			renderer.toneMappingExposure = 1.0;
-			renderer.render( scene, camera, this.CubeUVRenderTarget, false );
+			renderer.setRenderTarget( this.CubeUVRenderTarget );
+			renderer.render( scene, camera );
 
 
 			renderer.setRenderTarget( currentRenderTarget );
 			renderer.setRenderTarget( currentRenderTarget );
 			renderer.toneMapping = toneMapping;
 			renderer.toneMapping = toneMapping;

+ 3 - 1
examples/js/pmrem/PMREMGenerator.js

@@ -137,7 +137,9 @@ THREE.PMREMGenerator = ( function () {
 
 
 			renderTarget.activeCubeFace = faceIndex;
 			renderTarget.activeCubeFace = faceIndex;
 			shader.uniforms[ 'faceIndex' ].value = faceIndex;
 			shader.uniforms[ 'faceIndex' ].value = faceIndex;
-			renderer.render( scene, camera, renderTarget, true );
+			renderer.setRenderTarget( renderTarget );
+			renderer.clear();
+			renderer.render( scene, camera );
 
 
 		},
 		},
 
 

+ 14 - 6
examples/js/postprocessing/AdaptiveToneMappingPass.js

@@ -130,7 +130,7 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 
 	constructor: THREE.AdaptiveToneMappingPass,
 	constructor: THREE.AdaptiveToneMappingPass,
 
 
-	render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) {
+	render: function ( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {
 
 
 		if ( this.needsInit ) {
 		if ( this.needsInit ) {
 
 
@@ -148,20 +148,23 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 			//Render the luminance of the current scene into a render target with mipmapping enabled
 			//Render the luminance of the current scene into a render target with mipmapping enabled
 			this.quad.material = this.materialLuminance;
 			this.quad.material = this.materialLuminance;
 			this.materialLuminance.uniforms.tDiffuse.value = readBuffer.texture;
 			this.materialLuminance.uniforms.tDiffuse.value = readBuffer.texture;
-			renderer.render( this.scene, this.camera, this.currentLuminanceRT );
+			renderer.setRenderTarget( this.currentLuminanceRT );
+			renderer.render( this.scene, this.camera );
 
 
 			//Use the new luminance values, the previous luminance and the frame delta to
 			//Use the new luminance values, the previous luminance and the frame delta to
 			//adapt the luminance over time.
 			//adapt the luminance over time.
 			this.quad.material = this.materialAdaptiveLum;
 			this.quad.material = this.materialAdaptiveLum;
-			this.materialAdaptiveLum.uniforms.delta.value = delta;
+			this.materialAdaptiveLum.uniforms.delta.value = deltaTime;
 			this.materialAdaptiveLum.uniforms.lastLum.value = this.previousLuminanceRT.texture;
 			this.materialAdaptiveLum.uniforms.lastLum.value = this.previousLuminanceRT.texture;
 			this.materialAdaptiveLum.uniforms.currentLum.value = this.currentLuminanceRT.texture;
 			this.materialAdaptiveLum.uniforms.currentLum.value = this.currentLuminanceRT.texture;
-			renderer.render( this.scene, this.camera, this.luminanceRT );
+			renderer.setRenderTarget( this.luminanceRT );
+			renderer.render( this.scene, this.camera );
 
 
 			//Copy the new adapted luminance value so that it can be used by the next frame.
 			//Copy the new adapted luminance value so that it can be used by the next frame.
 			this.quad.material = this.materialCopy;
 			this.quad.material = this.materialCopy;
 			this.copyUniforms.tDiffuse.value = this.luminanceRT.texture;
 			this.copyUniforms.tDiffuse.value = this.luminanceRT.texture;
-			renderer.render( this.scene, this.camera, this.previousLuminanceRT );
+			renderer.setRenderTarget( this.previousLuminanceRT );
+			renderer.render( this.scene, this.camera );
 
 
 		}
 		}
 
 
@@ -170,11 +173,16 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 
 		if ( this.renderToScreen ) {
 		if ( this.renderToScreen ) {
 
 
+			renderer.setRenderTarget( null );
 			renderer.render( this.scene, this.camera );
 			renderer.render( this.scene, this.camera );
 
 
 		} else {
 		} else {
 
 
-			renderer.render( this.scene, this.camera, writeBuffer, this.clear );
+			renderer.setRenderTarget( writeBuffer );
+
+			if ( this.clear ) renderer.clear();
+
+			renderer.render( this.scene, this.camera );
 
 
 		}
 		}
 
 

+ 16 - 8
examples/js/postprocessing/AfterimagePass.js

@@ -70,17 +70,25 @@ THREE.AfterimagePass.prototype = Object.assign( Object.create( THREE.Pass.protot
 
 
 		this.quadComp.material = this.shaderMaterial;
 		this.quadComp.material = this.shaderMaterial;
 
 
-		renderer.render( this.sceneComp, this.camera, this.textureComp );
-		renderer.render( this.scene, this.camera, this.textureOld );
-		
+		renderer.setRenderTarget( this.textureComp );
+		renderer.render( this.sceneComp, this.camera );
+
+		renderer.setRenderTarget( this.textureOld );
+		renderer.render( this.scene, this.camera );
+
 		if ( this.renderToScreen ) {
 		if ( this.renderToScreen ) {
-			
+
+			renderer.setRenderTarget( null );
 			renderer.render( this.scene, this.camera );
 			renderer.render( this.scene, this.camera );
-			
+
 		} else {
 		} else {
-			
-			renderer.render( this.scene, this.camera, writeBuffer, this.clear );
-			
+
+			renderer.setRenderTarget( writeBuffer );
+
+			if ( this.clear ) renderer.clear();
+
+			renderer.render( this.scene, this.camera );
+
 		}
 		}
 
 
 	}
 	}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно