Mr.doob 6 years ago
parent
commit
fdbd9de6c1
100 changed files with 1824 additions and 993 deletions
  1. 2 5
      build/three.js
  2. 131 410
      build/three.min.js
  3. 2 5
      build/three.module.js
  4. 1 1
      docs/api/en/audio/Audio.html
  5. 1 1
      docs/api/en/audio/AudioAnalyser.html
  6. 4 4
      docs/api/en/audio/AudioListener.html
  7. 2 2
      docs/api/en/audio/PositionalAudio.html
  8. 1 0
      docs/api/en/constants/Renderer.html
  9. 1 1
      docs/api/en/core/Object3D.html
  10. 4 1
      docs/api/en/extras/core/ShapePath.html
  11. 73 0
      docs/api/en/helpers/PositionalAudioHelper.html
  12. 7 0
      docs/api/en/materials/Material.html
  13. 0 6
      docs/api/en/renderers/WebGLRenderTargetCube.html
  14. 67 22
      docs/api/en/renderers/WebGLRenderer.html
  15. 10 2
      docs/api/en/textures/DataTexture3D.html
  16. 1 1
      docs/api/zh/audio/Audio.html
  17. 1 1
      docs/api/zh/audio/AudioAnalyser.html
  18. 4 4
      docs/api/zh/audio/AudioListener.html
  19. 2 2
      docs/api/zh/audio/PositionalAudio.html
  20. 1 1
      docs/api/zh/core/Object3D.html
  21. 73 0
      docs/api/zh/helpers/PositionalAudioHelper.html
  22. 4 0
      docs/api/zh/materials/Material.html
  23. 0 5
      docs/api/zh/renderers/WebGLRenderTargetCube.html
  24. 6 4
      docs/api/zh/renderers/WebGLRenderer.html
  25. 1 1
      docs/api/zh/textures/Texture.html
  26. 6 1
      docs/list.js
  27. 126 0
      docs/manual/en/introduction/How-to-dispose-of-objects.html
  28. 1 1
      docs/manual/zh/introduction/Creating-a-scene.html
  29. 125 0
      docs/manual/zh/introduction/How-to-dispose-of-objects.html
  30. 0 2
      editor/examples/arkanoid.app.json
  31. 0 2
      editor/examples/camera.app.json
  32. 0 2
      editor/examples/particles.app.json
  33. 0 2
      editor/examples/pong.app.json
  34. 0 2
      editor/examples/shaders.app.json
  35. 1 0
      editor/index.html
  36. 0 2
      editor/js/Config.js
  37. 22 8
      editor/js/Editor.js
  38. 25 10
      editor/js/Loader.js
  39. 41 18
      editor/js/Menubar.Add.js
  40. 1 1
      editor/js/Menubar.Edit.js
  41. 65 5
      editor/js/Sidebar.Animation.js
  42. 1 1
      editor/js/Sidebar.Geometry.BufferGeometry.js
  43. 1 1
      editor/js/Sidebar.Geometry.Geometry.js
  44. 1 1
      editor/js/Sidebar.Geometry.Modifiers.js
  45. 185 0
      editor/js/Sidebar.Geometry.TubeGeometry.js
  46. 1 1
      editor/js/Sidebar.Geometry.js
  47. 3 3
      editor/js/Sidebar.Material.js
  48. 2 2
      editor/js/Sidebar.Object.js
  49. 5 28
      editor/js/Sidebar.Project.js
  50. 3 3
      editor/js/Sidebar.Scene.js
  51. 10 4
      editor/js/Strings.js
  52. 3 3
      editor/js/Viewport.Info.js
  53. 27 3
      editor/js/Viewport.js
  54. 1 2
      editor/js/libs/app.js
  55. 1 5
      editor/js/libs/tern-threejs/threejs.js
  56. 5 5
      editor/js/libs/ui.js
  57. 8 2
      examples/js/GPUComputationRenderer.js
  58. 200 64
      examples/js/MarchingCubes.js
  59. 39 14
      examples/js/Ocean.js
  60. 11 2
      examples/js/cameras/CinematicCamera.js
  61. 16 8
      examples/js/controls/OrbitControls.js
  62. 0 14
      examples/js/controls/TransformControls.js
  63. 11 3
      examples/js/crossfade/scenes.js
  64. 4 2
      examples/js/crossfade/transition.js
  65. 13 2
      examples/js/effects/AnaglyphEffect.js
  66. 27 6
      examples/js/effects/OutlineEffect.js
  67. 9 2
      examples/js/effects/ParallaxBarrierEffect.js
  68. 2 1
      examples/js/effects/StereoEffect.js
  69. 3 1
      examples/js/exporters/GLTFExporter.js
  70. 7 3
      examples/js/loaders/AssimpJSONLoader.js
  71. 2 2
      examples/js/loaders/ColladaLoader.js
  72. 14 6
      examples/js/loaders/EquirectangularToCubeGenerator.js
  73. 17 3
      examples/js/loaders/FBXLoader.js
  74. 65 65
      examples/js/loaders/GLTFLoader.js
  75. 57 67
      examples/js/loaders/LDrawLoader.js
  76. 19 4
      examples/js/loaders/SVGLoader.js
  77. 4 2
      examples/js/loaders/TGALoader.js
  78. 29 11
      examples/js/loaders/VRMLLoader.js
  79. 23 19
      examples/js/loaders/deprecated/LegacyGLTFLoader.js
  80. 6 2
      examples/js/nodes/inputs/RTTNode.js
  81. 4 2
      examples/js/nodes/postprocessing/NodePostProcessing.js
  82. 12 6
      examples/js/objects/Fire.js
  83. 1 1
      examples/js/objects/Lensflare.js
  84. 5 2
      examples/js/objects/Reflector.js
  85. 5 2
      examples/js/objects/Refractor.js
  86. 3 1
      examples/js/objects/Water.js
  87. 2 1
      examples/js/pmrem/PMREMCubeUVPacker.js
  88. 3 2
      examples/js/pmrem/PMREMGenerator.js
  89. 35 27
      examples/js/postprocessing/AdaptiveToneMappingPass.js
  90. 18 10
      examples/js/postprocessing/AfterimagePass.js
  91. 11 5
      examples/js/postprocessing/BloomPass.js
  92. 9 4
      examples/js/postprocessing/BokehPass.js
  93. 3 1
      examples/js/postprocessing/CubeTexturePass.js
  94. 5 2
      examples/js/postprocessing/DotScreenPass.js
  95. 7 3
      examples/js/postprocessing/EffectComposer.js
  96. 5 2
      examples/js/postprocessing/FilmPass.js
  97. 7 4
      examples/js/postprocessing/GlitchPass.js
  98. 7 4
      examples/js/postprocessing/HalftonePass.js
  99. 8 3
      examples/js/postprocessing/MaskPass.js
  100. 27 9
      examples/js/postprocessing/OutlinePass.js

File diff suppressed because it is too large
+ 2 - 5
build/three.js


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


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


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

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

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

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

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

@@ -13,8 +13,8 @@
 		<h1>[name]</h1>
 
 		<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.
 		</p>
 
@@ -22,8 +22,8 @@
 		<h2>Example</h2>
 
 		<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 ]
 		</p>
 

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

@@ -22,8 +22,8 @@
 		<h2>Example</h2>
 
 		<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 ]
 		</p>
 

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

@@ -55,6 +55,7 @@
 		THREE.ReinhardToneMapping
 		THREE.Uncharted2ToneMapping
 		THREE.CineonToneMapping
+		THREE.ACESFilmicToneMapping
 		</code>
 		<p>
 		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.
 		</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>
 		<p>
 		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.
 		</p>
 
+		<h3>[property:Color color]</h3>
+		<p>[page:Color] of the shape, by default set to white (0xffffff).</p>
+
 		<h2>Methods</h2>
 
 		<h3>[method:null moveTo]( [param:Float x], [param:Float y] )</h3>
@@ -86,6 +89,6 @@
 
 		<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>
 </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].
 		</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>
 		<p>
 		Defines whether this material is visible. Default is *true*.

+ 0 - 6
docs/api/en/renderers/WebGLRenderTargetCube.html

@@ -50,12 +50,6 @@
 
 		<h2>Properties</h2>
 
-		<h3>[property:integer activeCubeFace]</h3>
-		<p>
-		The activeCubeFace property corresponds to a cube side (PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5) and is
-		used and set internally by the [page:CubeCamera].
-		</p>
-
 		<h3>See [page:WebGLRenderTarget] for inherited properties</h3>
 
 

+ 67 - 22
docs/api/en/renderers/WebGLRenderer.html

@@ -348,37 +348,66 @@
 		<h3>[method:RenderTarget getRenderTarget]()</h3>
 		<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>
 		<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>
 		<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>
 
-		<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>
 			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>
 
 		<h3>[method:null renderBufferDirect]( [param:Camera camera], [param:Fog fog], [param:Geometry geometry], [param:Material material], [param:Object3D object], [param:Object group] )</h3>
@@ -405,15 +434,23 @@
 		<h3>[method:null setPixelRatio]( [param:number value] )</h3>
 		<p>Sets device pixel ratio. This is usually used for HiDPI device to prevent bluring output canvas.</p>
 
-		<h3>[method:null setRenderTarget]( [param:WebGLRenderTarget renderTarget] )</h3>
+		<h3>[method:null setRenderTarget]( [param:WebGLRenderTarget renderTarget], [param:Integer activeCubeFace], [param:Integer activeMipMapLevel] )</h3>
 		<p>
-		renderTarget -- The [page:WebGLRenderTarget renderTarget] that needs to be activated (optional).<br /><br />
+		renderTarget -- The [page:WebGLRenderTarget renderTarget] that needs to be activated (optional).<br />
+		activeCubeFace -- Specifies the active cube side (PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5) of [page:WebGLRenderTargetCube] (optional).<br />
+		activeMipMapLevel -- Specifies the active mipmap level (optional).<br /><br />
 		This method sets the active rendertarget. If the parameter is omitted the canvas is set as the active rendertarget.
 		</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>
-		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>
 
 		<h3>[method:null setScissorTest]( [param:Boolean boolean] )</h3>
@@ -449,8 +486,16 @@
 		The slot number can be found as a value of the uniform of the sampler.
 		</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>
 

+ 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_volume WebGL2 / materials / texture3d / volume]</div>
 
-		<h2>Properties</h2>
+    <h2>Properties</h2>
 
 		<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>
 
 		<h2>Methods</h2>

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

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

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

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

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

@@ -13,8 +13,8 @@
 		<h1>[name]</h1>
 
 		<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变换.
 		</p>
 
@@ -22,8 +22,8 @@
 		<h2>示例</h2>
 
 		<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 ]
 		</p>
 

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

@@ -22,8 +22,8 @@
 		<h2>示例</h2>
 
 		<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 ]
 		</p>
 

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

@@ -273,7 +273,7 @@
 		将局部空间向量转换为世界空间向量。
 	</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>
 	<p>
 		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]。
 </p>
 
+<h3>[property:Boolean vertexTangents]</h3>
+<p> TODO.
+</p>
+
 <h3>[property:Boolean visible]</h3>
 <p> 此材质是否可见。默认为*true*。
 </p>

+ 0 - 5
docs/api/zh/renderers/WebGLRenderTargetCube.html

@@ -47,11 +47,6 @@
 
 		<h2>属性</h2>
 
-		<h3>[property:integer activeCubeFace]</h3>
-		<p>
-		activeCubeFace属性对应立方体的面(PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5) 并由[page:CubeCamera]内部使用和设置
-		</p>
-
 		<h3>继承属性,请参阅[page:WebGLRenderTarget]</h3>
 
 

+ 6 - 4
docs/api/zh/renderers/WebGLRenderer.html

@@ -348,7 +348,7 @@
 		<p>将GL状态重置为默认值。WebGL环境丢失时会内部调用</p>
 
 		<h3>[method:null readRenderTargetPixels]( [param:WebGLRenderTarget renderTarget], [param:Float x], [param:Float y], [param:Float width], [param:Float height], buffer )</h3>
-		<p>将enderTarget中的像素数据读取到传入的缓冲区中。这是link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/readPixels WebGLRenderingContext.readPixels]()的包装器<br />
+		<p>将enderTarget中的像素数据读取到传入的缓冲区中。这是[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/readPixels WebGLRenderingContext.readPixels]()的包装器<br />
 		示例:[example:webgl_interactive_cubes_gpu interactive / cubes / gpu]
 		</p>
 
@@ -376,7 +376,7 @@
 
 		<h3>[method:null setAnimationLoop]( [param:Function callback] )</h3>
 		<p>[page:Function callback] — 每个可用帧都会调用的函数。 如果传入‘null’,所有正在进行的动画都会停止。</p>
-		<p>可用来代替[link:https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame requestAnimationFrame]的内置函数. 对于WebVR想谬,必须使用此功能</p>
+		<p>可用来代替[link:https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame requestAnimationFrame]的内置函数. 对于WebVR项目,必须使用此函数。</p>
 
 		<h3>[method:null setClearAlpha]( [param:Float alpha] )</h3>
 		<p>设置alpha。合法参数是一个*0.0*到 *1.0*之间的浮点数</p>
@@ -387,9 +387,11 @@
 		<h3>[method:null setPixelRatio]( [param:number value] )</h3>
 		<p>设置设备像素比。通常用于避免HiDPI设备上绘图模糊</p>
 
-		<h3>[method:null setRenderTarget]( [param:WebGLRenderTarget renderTarget] )</h3>
+		<h3>[method:null setRenderTarget]( [param:WebGLRenderTarget renderTarget], [param:Integer activeCubeFace], [param:Integer activeMipMapLevel] )</h3>
 		<p>
-		renderTarget -- 需要被激活的[page:WebGLRenderTarget renderTarget](可选).<br /><br />
+		renderTarget -- 需要被激活的[page:WebGLRenderTarget renderTarget](可选).<br />
+		activeCubeFace -- Specifies the active cube side (PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5) of [page:WebGLRenderTargetCube] (optional).<br />
+		activeMipMapLevel -- Specifies the active mipmap level (optional).<br /><br />
 		该方法设置活跃rendertarget. 参数缺省则将canvas设置成活跃rendertarget
 		</p>
 

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

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

+ 6 - 1
docs/list.js

@@ -22,6 +22,7 @@ var list = {
 
 			"Next Steps": {
 				"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",
 				"Matrix transformations": "manual/en/introduction/Matrix-transformations",
 				"Animation system": "manual/en/introduction/Animation-system"
@@ -196,6 +197,7 @@ var list = {
 				"FaceNormalsHelper": "api/en/helpers/FaceNormalsHelper",
 				"GridHelper": "api/en/helpers/GridHelper",
 				"PolarGridHelper": "api/en/helpers/PolarGridHelper",
+				"PositionalAudioHelper": "api/en/helpers/PositionalAudioHelper",
 				"HemisphereLightHelper": "api/en/helpers/HemisphereLightHelper",
 				"PlaneHelper": "api/en/helpers/PlaneHelper",
 				"PointLightHelper": "api/en/helpers/PointLightHelper",
@@ -380,7 +382,8 @@ var list = {
 
 			"Exporters": {
 				"GLTFExporter": "examples/exporters/GLTFExporter",
-				"PLYExporter": "examples/exporters/PLYExporter"
+				"PLYExporter": "examples/exporters/PLYExporter",
+				"ColladaExporter": "examples/exporters/ColladaExporter"
 			},
 
 			"Plugins": {
@@ -447,6 +450,7 @@ var list = {
 
 			"进阶": {
 				"如何更新场景": "manual/zh/introduction/How-to-update-things",
+				"如何废置对象": "manual/zh/introduction/How-to-dispose-of-objects",
 				"如何创建VR内容": "manual/zh/introduction/How-to-create-VR-content",
 				"矩阵变换": "manual/zh/introduction/Matrix-transformations",
 				"动画系统": "manual/zh/introduction/Animation-system"
@@ -621,6 +625,7 @@ var list = {
 				"FaceNormalsHelper": "api/zh/helpers/FaceNormalsHelper",
 				"GridHelper": "api/zh/helpers/GridHelper",
 				"PolarGridHelper": "api/zh/helpers/PolarGridHelper",
+				"PositionalAudioHelper": "api/zh/helpers/PositionalAudioHelper",
 				"HemisphereLightHelper": "api/zh/helpers/HemisphereLightHelper",
 				"PlaneHelper": "api/zh/helpers/PlaneHelper",
 				"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>

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

@@ -10,7 +10,7 @@
 	<body>
 		<h1>创建一个场景([name])</h1><br />
 
-		<p>这一部分将对three.js来做一个简要的介绍;我们将开始搭建一个场景,其中包含一个正在旋转的立方体。页面下方有一个已经完成的例子,当你遇到麻烦,或者需要帮助的时候,可以看一看。</p>
+		<p>这一部分将对three.js来做一个简要的介绍;我们将开始搭建一个场景,其中包含一个正在旋转的立方体。页面下方有一个已经完成的例子,当你遇到麻烦,或者需要帮助的时候,可以看一看。</p>
 
 		<h2>开始之前</h2>
 		<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(材质)。
+		请记住,geometry(几何体)或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>

+ 0 - 2
editor/examples/arkanoid.app.json

@@ -3,8 +3,6 @@
 		"type": "App"
 	},
 	"project": {
-		"gammaInput": true,
-		"gammaOutput": true,
 		"shadows": true,
 		"vr": false
 	},

+ 0 - 2
editor/examples/camera.app.json

@@ -3,8 +3,6 @@
 		"type": "App"
 	},
 	"project": {
-		"gammaInput": true,
-		"gammaOutput": true,
 		"shadows": true,
 		"vr": false
 	},

+ 0 - 2
editor/examples/particles.app.json

@@ -3,8 +3,6 @@
 		"type": "App"
 	},
 	"project": {
-		"gammaInput": true,
-		"gammaOutput": true,
 		"shadows": true,
 		"vr": false
 	},

+ 0 - 2
editor/examples/pong.app.json

@@ -3,8 +3,6 @@
 		"type": "App"
 	},
 	"project": {
-		"gammaInput": true,
-		"gammaOutput": true,
 		"shadows": true,
 		"vr": false
 	},

+ 0 - 2
editor/examples/shaders.app.json

@@ -3,8 +3,6 @@
 		"type": "App"
 	},
 	"project": {
-		"gammaInput": true,
-		"gammaOutput": true,
 		"shadows": true,
 		"vr": false
 	},

+ 1 - 0
editor/index.html

@@ -141,6 +141,7 @@
 		<script src="js/Sidebar.Geometry.SphereGeometry.js"></script>
 		<script src="js/Sidebar.Geometry.TorusGeometry.js"></script>
 		<script src="js/Sidebar.Geometry.TorusKnotGeometry.js"></script>
+		<script src="js/Sidebar.Geometry.TubeGeometry.js"></script>
 		<script src="../examples/js/geometries/TeapotBufferGeometry.js"></script>
 		<script src="js/Sidebar.Geometry.TeapotBufferGeometry.js"></script>
 		<script src="js/Sidebar.Geometry.LatheGeometry.js"></script>

+ 0 - 2
editor/js/Config.js

@@ -17,8 +17,6 @@ var Config = function () {
 
 		'project/renderer': 'WebGLRenderer',
 		'project/renderer/antialias': true,
-		'project/renderer/gammaInput': false,
-		'project/renderer/gammaOutput': false,
 		'project/renderer/shadows': true,
 
 		'project/vr': false,

+ 22 - 8
editor/js/Editor.js

@@ -93,6 +93,9 @@ var Editor = function () {
 	this.textures = {};
 	this.scripts = {};
 
+	this.animations = {};
+	this.mixer = new THREE.AnimationMixer( this.scene );
+
 	this.selected = null;
 	this.helpers = {};
 
@@ -239,6 +242,16 @@ Editor.prototype = {
 
 	},
 
+	addAnimation: function ( object, animations ) {
+
+		if ( animations.length > 0 ) {
+
+			this.animations[ object.uuid ] = animations;
+
+		}
+
+	},
+
 	//
 
 	addHelper: function () {
@@ -250,27 +263,27 @@ Editor.prototype = {
 
 			var helper;
 
-			if ( object instanceof THREE.Camera ) {
+			if ( object.isCamera ) {
 
 				helper = new THREE.CameraHelper( object, 1 );
 
-			} else if ( object instanceof THREE.PointLight ) {
+			} else if ( object.isPointLight ) {
 
 				helper = new THREE.PointLightHelper( object, 1 );
 
-			} else if ( object instanceof THREE.DirectionalLight ) {
+			} else if ( object.isDirectionalLight ) {
 
 				helper = new THREE.DirectionalLightHelper( object, 1 );
 
-			} else if ( object instanceof THREE.SpotLight ) {
+			} else if ( object.isSpotLight ) {
 
 				helper = new THREE.SpotLightHelper( object, 1 );
 
-			} else if ( object instanceof THREE.HemisphereLight ) {
+			} else if ( object.isHemisphereLight ) {
 
 				helper = new THREE.HemisphereLightHelper( object, 1 );
 
-			} else if ( object instanceof THREE.SkinnedMesh ) {
+			} else if ( object.isSkinnedMesh ) {
 
 				helper = new THREE.SkeletonHelper( object );
 
@@ -460,6 +473,9 @@ Editor.prototype = {
 		this.textures = {};
 		this.scripts = {};
 
+		this.animations = {};
+		this.mixer.stopAllAction();
+
 		this.deselect();
 
 		this.signals.editorCleared.dispatch();
@@ -519,8 +535,6 @@ Editor.prototype = {
 
 			metadata: {},
 			project: {
-				gammaInput: this.config.getKey( 'project/renderer/gammaInput' ),
-				gammaOutput: this.config.getKey( 'project/renderer/gammaOutput' ),
 				shadows: this.config.getKey( 'project/renderer/shadows' ),
 				vr: this.config.getKey( 'project/vr' )
 			},

+ 25 - 10
editor/js/Loader.js

@@ -34,7 +34,7 @@ var Loader = function ( editor ) {
 
 			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;
 
 					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.sourceFile = file.name;
@@ -180,6 +180,7 @@ var Loader = function ( editor ) {
 
 					collada.scene.name = filename;
 
+					editor.addAnimation( collada.scene, collada.animations );
 					editor.execute( new AddObjectCommand( collada.scene ) );
 
 				}, false );
@@ -196,6 +197,7 @@ var Loader = function ( editor ) {
 					var loader = new THREE.FBXLoader( manager );
 					var object = loader.parse( contents );
 
+					editor.addAnimation( object, object.animations );
 					editor.execute( new AddObjectCommand( object ) );
 
 				}, false );
@@ -215,8 +217,11 @@ var Loader = function ( editor ) {
 					loader.setDRACOLoader( new THREE.DRACOLoader() );
 					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 +250,11 @@ var Loader = function ( editor ) {
 
 					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 +352,7 @@ var Loader = function ( editor ) {
 					mesh.mixer = new THREE.AnimationMixer( mesh );
 					mesh.name = filename;
 
+					editor.addAnimation( mesh, geometry.animations );
 					editor.execute( new AddObjectCommand( mesh ) );
 
 				}, false );
@@ -450,7 +459,7 @@ var Loader = function ( editor ) {
 
 					var group = new THREE.Group();
 					group.scale.multiplyScalar( 0.1 );
-					group.scale.y *= -1;
+					group.scale.y *= - 1;
 
 					for ( var i = 0; i < paths.length; i ++ ) {
 
@@ -587,7 +596,7 @@ var Loader = function ( editor ) {
 
 				var result = loader.parse( data );
 
-				if ( result instanceof THREE.Scene ) {
+				if ( result.isScene ) {
 
 					editor.execute( new SetSceneCommand( result ) );
 
@@ -678,7 +687,10 @@ var Loader = function ( editor ) {
 					var loader = new THREE.GLTFLoader();
 					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 +701,10 @@ var Loader = function ( editor ) {
 					var loader = new THREE.GLTFLoader( manager );
 					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 ) );
 
 					} );
 

+ 41 - 18
editor/js/Menubar.Add.js

@@ -41,7 +41,7 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/plane' )  );
+	option.setTextContent( strings.getKey( 'menubar/add/plane' ) );
 	option.onClick( function () {
 
 		var geometry = new THREE.PlaneBufferGeometry( 1, 1, 1, 1 );
@@ -58,7 +58,7 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/box' )  );
+	option.setTextContent( strings.getKey( 'menubar/add/box' ) );
 	option.onClick( function () {
 
 		var geometry = new THREE.BoxBufferGeometry( 1, 1, 1, 1, 1, 1 );
@@ -90,7 +90,7 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/cylinder' )  );
+	option.setTextContent( strings.getKey( 'menubar/add/cylinder' ) );
 	option.onClick( function () {
 
 		var geometry = new THREE.CylinderBufferGeometry( 1, 1, 1, 8, 1, false, 0, Math.PI * 2 );
@@ -106,7 +106,7 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/sphere' )  );
+	option.setTextContent( strings.getKey( 'menubar/add/sphere' ) );
 	option.onClick( function () {
 
 		var geometry = new THREE.SphereBufferGeometry( 1, 8, 6, 0, Math.PI * 2, 0, Math.PI );
@@ -122,7 +122,7 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/icosahedron' )  );
+	option.setTextContent( strings.getKey( 'menubar/add/icosahedron' ) );
 	option.onClick( function () {
 
 		var geometry = new THREE.IcosahedronBufferGeometry( 1, 0 );
@@ -138,7 +138,7 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/torus' )  );
+	option.setTextContent( strings.getKey( 'menubar/add/torus' ) );
 	option.onClick( function () {
 
 		var geometry = new THREE.TorusBufferGeometry( 1, 0.4, 8, 6, Math.PI * 2 );
@@ -154,7 +154,7 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/torusknot' )  );
+	option.setTextContent( strings.getKey( 'menubar/add/torusknot' ) );
 	option.onClick( function () {
 
 		var geometry = new THREE.TorusKnotBufferGeometry( 1, 0.4, 64, 8, 2, 3 );
@@ -166,6 +166,29 @@ Menubar.Add = function ( editor ) {
 	} );
 	options.add( option );
 
+	// Tube
+
+	var option = new UI.Row();
+	option.setClass( 'option' );
+	option.setTextContent( strings.getKey( 'menubar/add/tube' ) );
+	option.onClick( function () {
+
+		var path = new THREE.CatmullRomCurve3( [
+			new THREE.Vector3( 2, 2, - 2 ),
+			new THREE.Vector3( 2, - 2, - 0.6666666666666667 ),
+			new THREE.Vector3( - 2, - 2, 0.6666666666666667 ),
+			new THREE.Vector3( - 2, 2, 2 )
+		] );
+
+		var geometry = new THREE.TubeBufferGeometry( path, 64, 1, 8, false );
+		var mesh = new THREE.Mesh( geometry, new THREE.MeshStandardMaterial() );
+		mesh.name = 'Tube';
+
+		editor.execute( new AddObjectCommand( mesh ) );
+
+	} );
+	options.add( option );
+
 	/*
 	// Teapot
 
@@ -199,8 +222,8 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/lathe' )  );
-	option.onClick( function() {
+	option.setTextContent( strings.getKey( 'menubar/add/lathe' ) );
+	option.onClick( function () {
 
 		var points = [
 			new THREE.Vector2( 0, 0 ),
@@ -229,7 +252,7 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/sprite' )  );
+	option.setTextContent( strings.getKey( 'menubar/add/sprite' ) );
 	option.onClick( function () {
 
 		var sprite = new THREE.Sprite( new THREE.SpriteMaterial() );
@@ -248,7 +271,7 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/pointlight' )  );
+	option.setTextContent( strings.getKey( 'menubar/add/pointlight' ) );
 	option.onClick( function () {
 
 		var color = 0xffffff;
@@ -267,7 +290,7 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/spotlight' )  );
+	option.setTextContent( strings.getKey( 'menubar/add/spotlight' ) );
 	option.onClick( function () {
 
 		var color = 0xffffff;
@@ -291,7 +314,7 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/directionallight' )  );
+	option.setTextContent( strings.getKey( 'menubar/add/directionallight' ) );
 	option.onClick( function () {
 
 		var color = 0xffffff;
@@ -312,7 +335,7 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/hemispherelight' )  );
+	option.setTextContent( strings.getKey( 'menubar/add/hemispherelight' ) );
 	option.onClick( function () {
 
 		var skyColor = 0x00aaff;
@@ -333,8 +356,8 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/ambientlight' )  );
-	option.onClick( function() {
+	option.setTextContent( strings.getKey( 'menubar/add/ambientlight' ) );
+	option.onClick( function () {
 
 		var color = 0x222222;
 
@@ -354,8 +377,8 @@ Menubar.Add = function ( editor ) {
 
 	var option = new UI.Row();
 	option.setClass( 'option' );
-	option.setTextContent( strings.getKey( 'menubar/add/perspectivecamera' )  );
-	option.onClick( function() {
+	option.setTextContent( strings.getKey( 'menubar/add/perspectivecamera' ) );
+	option.onClick( function () {
 
 		var camera = new THREE.PerspectiveCamera( 50, 1, 1, 10000 );
 		camera.name = 'PerspectiveCamera';

+ 1 - 1
editor/js/Menubar.Edit.js

@@ -151,7 +151,7 @@ Menubar.Edit = function ( editor ) {
 
 			var material = object.material;
 
-			if ( material instanceof THREE.ShaderMaterial ) {
+			if ( material.isShaderMaterial ) {
 
 				try {
 

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

@@ -5,19 +5,79 @@
 Sidebar.Animation = function ( editor ) {
 
 	var signals = editor.signals;
+	var mixer = editor.mixer;
 
-	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();
 	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() );
 
-	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;
 

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

@@ -17,7 +17,7 @@ Sidebar.Geometry.BufferGeometry = function ( editor ) {
 
 		var geometry = object.geometry;
 
-		if ( geometry instanceof THREE.BufferGeometry ) {
+		if ( geometry && geometry.isBufferGeometry ) {
 
 			container.clear();
 			container.setDisplay( 'block' );

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

@@ -39,7 +39,7 @@ Sidebar.Geometry.Geometry = function ( editor ) {
 
 		var geometry = object.geometry;
 
-		if ( geometry instanceof THREE.Geometry ) {
+		if ( geometry && geometry.isGeometry ) {
 
 			container.setDisplay( 'block' );
 

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

@@ -17,7 +17,7 @@ Sidebar.Geometry.Modifiers = function ( editor, object ) {
 
 		geometry.computeVertexNormals();
 
-		if ( geometry instanceof THREE.BufferGeometry ) {
+		if ( geometry.isBufferGeometry ) {
 
 			geometry.attributes.normal.needsUpdate = true;
 

+ 185 - 0
editor/js/Sidebar.Geometry.TubeGeometry.js

@@ -0,0 +1,185 @@
+/**
+ * @author Temdog007 / http://github.com/Temdog007
+ */
+
+Sidebar.Geometry.TubeGeometry = function ( editor, object ) {
+
+	var strings = editor.strings;
+
+	var signals = editor.signals;
+
+	var container = new UI.Row();
+
+	var geometry = object.geometry;
+	var parameters = geometry.parameters;
+
+	// points
+
+	var lastPointIdx = 0;
+	var pointsUI = [];
+
+	var pointsRow = new UI.Row();
+	pointsRow.add( new UI.Text( strings.getKey( 'sidebar/geometry/tube_geometry/path' ) ).setWidth( '90px' ) );
+
+	var points = new UI.Span().setDisplay( 'inline-block' );
+	pointsRow.add( points );
+
+	var pointsList = new UI.Div();
+	points.add( pointsList );
+
+	var parameterPoints = parameters.path.points;
+	for ( var i = 0; i < parameterPoints.length; i ++ ) {
+
+		var point = parameterPoints[ i ];
+		pointsList.add( createPointRow( point.x, point.y, point.z ) );
+
+	}
+
+	var addPointButton = new UI.Button( '+' ).onClick( function () {
+
+		if ( pointsUI.length === 0 ) {
+
+			pointsList.add( createPointRow( 0, 0, 0 ) );
+
+		} else {
+
+			var point = pointsUI[ pointsUI.length - 1 ];
+
+			pointsList.add( createPointRow( point.x.getValue(), point.y.getValue(), point.z.getValue() ) );
+
+		}
+
+		update();
+
+	} );
+	points.add( addPointButton );
+
+	container.add( pointsRow );
+
+	// radius
+
+	var radiusRow = new UI.Row();
+	var radius = new UI.Number( parameters.radius ).onChange( update );
+
+	radiusRow.add( new UI.Text( strings.getKey( 'sidebar/geometry/tube_geometry/radius' ) ).setWidth( '90px' ) );
+	radiusRow.add( radius );
+
+	container.add( radiusRow );
+
+	// tubularSegments
+
+	var tubularSegmentsRow = new UI.Row();
+	var tubularSegments = new UI.Integer( parameters.tubularSegments ).onChange( update );
+
+	tubularSegmentsRow.add( new UI.Text( strings.getKey( 'sidebar/geometry/tube_geometry/tubularsegments' ) ).setWidth( '90px' ) );
+	tubularSegmentsRow.add( tubularSegments );
+
+	container.add( tubularSegmentsRow );
+
+	// radialSegments
+
+	var radialSegmentsRow = new UI.Row();
+	var radialSegments = new UI.Integer( parameters.radialSegments ).onChange( update );
+
+	radialSegmentsRow.add( new UI.Text( strings.getKey( 'sidebar/geometry/tube_geometry/radialsegments' ) ).setWidth( '90px' ) );
+	radialSegmentsRow.add( radialSegments );
+
+	container.add( radialSegmentsRow );
+
+	// closed
+
+	var closedRow = new UI.Row();
+	var closed = new UI.Checkbox( parameters.closed ).onChange( update );
+
+	closedRow.add( new UI.Text( strings.getKey( 'sidebar/geometry/tube_geometry/closed' ) ).setWidth( '90px' ) );
+	closedRow.add( closed );
+
+	container.add( closedRow );
+
+	// curveType
+
+	var curveTypeRow = new UI.Row();
+	var curveType = new UI.Select().setOptions( { centripetal: 'centripetal', chordal: 'chordal', catmullrom: 'catmullrom' } ).setValue( parameters.path.curveType ).onChange( update );
+
+	curveTypeRow.add( new UI.Text( strings.getKey( 'sidebar/geometry/tube_geometry/curvetype' ) ).setWidth( '90px' ), curveType );
+
+	container.add( curveTypeRow );
+
+	// tension
+
+	var tensionRow = new UI.Row().setDisplay( curveType.getValue() == 'catmullrom' ? '' : 'none' );
+	var tension = new UI.Number( parameters.path.tension ).setStep( 0.01 ).onChange( update );
+
+	tensionRow.add( new UI.Text( strings.getKey( 'sidebar/geometry/tube_geometry/tension' ) ).setWidth( '90px' ), tension );
+
+	container.add( tensionRow );
+
+	//
+
+	function update() {
+
+		var points = [];
+		var count = 0;
+
+		for ( var i = 0; i < pointsUI.length; i ++ ) {
+
+			var pointUI = pointsUI[ i ];
+
+			if ( ! pointUI ) continue;
+
+			points.push( new THREE.Vector3( pointUI.x.getValue(), pointUI.y.getValue(), pointUI.z.getValue() ) );
+			count ++;
+			pointUI.lbl.setValue( count );
+
+		}
+
+		tensionRow.setDisplay( curveType.getValue() == 'catmullrom' ? '' : 'none' );
+
+		editor.execute( new SetGeometryCommand( object, new THREE[ geometry.type ](
+			new THREE.CatmullRomCurve3( points, closed.getValue(), curveType.getValue(), tension.getValue() ),
+			tubularSegments.getValue(),
+			radius.getValue(),
+			radialSegments.getValue(),
+			closed.getValue()
+		) ) );
+
+	}
+
+	function createPointRow( x, y, z ) {
+
+		var pointRow = new UI.Div();
+		var lbl = new UI.Text( lastPointIdx + 1 ).setWidth( '20px' );
+		var txtX = new UI.Number( x ).setWidth( '30px' ).onChange( update );
+		var txtY = new UI.Number( y ).setWidth( '30px' ).onChange( update );
+		var txtZ = new UI.Number( z ).setWidth( '30px' ).onChange( update );
+		var idx = lastPointIdx;
+		var btn = new UI.Button( '-' ).onClick( function () {
+
+			deletePointRow( idx );
+
+		} );
+
+		pointsUI.push( { row: pointRow, lbl: lbl, x: txtX, y: txtY, z: txtZ } );
+		lastPointIdx ++;
+		pointRow.add( lbl, txtX, txtY, txtZ, btn );
+
+		return pointRow;
+
+	}
+
+	function deletePointRow( idx ) {
+
+		if ( ! pointsUI[ idx ] ) return;
+
+		pointsList.remove( pointsUI[ idx ].row );
+		pointsUI[ idx ] = null;
+
+		update();
+
+	}
+
+	return container;
+
+};
+
+Sidebar.Geometry.TubeBufferGeometry = Sidebar.Geometry.TubeGeometry;

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

@@ -55,7 +55,7 @@ Sidebar.Geometry = function ( editor ) {
 
 			case 'Convert':
 
-				if ( geometry instanceof THREE.Geometry ) {
+				if ( geometry && geometry.isGeometry ) {
 
 					editor.execute( new SetGeometryCommand( object, new THREE.BufferGeometry().fromGeometry( geometry ) ) );
 

+ 3 - 3
editor/js/Sidebar.Material.js

@@ -525,9 +525,9 @@ Sidebar.Material = function ( editor ) {
 		var textureWarning = false;
 		var objectHasUvs = false;
 
-		if ( object instanceof THREE.Sprite ) objectHasUvs = true;
-		if ( geometry instanceof THREE.Geometry && geometry.faceVertexUvs[ 0 ].length > 0 ) objectHasUvs = true;
-		if ( geometry instanceof THREE.BufferGeometry && geometry.attributes.uv !== undefined ) objectHasUvs = true;
+		if ( object.isSprite ) objectHasUvs = true;
+		if ( geometry.isGeometry && geometry.faceVertexUvs[ 0 ].length > 0 ) objectHasUvs = true;
+		if ( geometry.isBufferGeometry && geometry.attributes.uv !== undefined ) objectHasUvs = true;
 
 		if ( material ) {
 

+ 2 - 2
editor/js/Sidebar.Object.js

@@ -542,8 +542,8 @@ Sidebar.Object = function ( editor ) {
 
 	function updateTransformRows( object ) {
 
-		if ( object instanceof THREE.Light ||
-		   ( object instanceof THREE.Object3D && object.userData.targetInverse ) ) {
+		if ( object.isLight ||
+		   ( object.isObject3D && object.userData.targetInverse ) ) {
 
 			objectRotationRow.setDisplay( 'none' );
 			objectScaleRow.setDisplay( 'none' );

+ 5 - 28
editor/js/Sidebar.Project.js

@@ -119,45 +119,22 @@ Sidebar.Project = function ( editor ) {
 	} );
 	rendererPropertiesRow.add( rendererShadows );
 
-	rendererPropertiesRow.add( new UI.Break() );
-
-	// Renderer / Gamma input
-
-	var rendererGammaInput = new UI.THREE.Boolean( config.getKey( 'project/renderer/gammaInput' ), strings.getKey( 'sidebar/project/gammainput' ) ).onChange( function () {
-
-		config.setKey( 'project/renderer/gammaInput', this.getValue() );
-		updateRenderer();
-
-	} );
-	rendererPropertiesRow.add( rendererGammaInput );
-
-	// Renderer / Gamma output
-
-	var rendererGammaOutput = new UI.THREE.Boolean( config.getKey( 'project/renderer/gammaOutput' ), strings.getKey( 'sidebar/project/gammaoutput' ) ).onChange( function () {
-
-		config.setKey( 'project/renderer/gammaOutput', this.getValue() );
-		updateRenderer();
-
-	} );
-	rendererPropertiesRow.add( rendererGammaOutput );
-
 	container.add( rendererPropertiesRow );
 
 	//
 
 	function updateRenderer() {
 
-		createRenderer( rendererType.getValue(), rendererAntialias.getValue(), rendererShadows.getValue(), rendererGammaInput.getValue(), rendererGammaOutput.getValue() );
+		createRenderer( rendererType.getValue(), rendererAntialias.getValue() );
 
 	}
 
-	function createRenderer( type, antialias, shadows, gammaIn, gammaOut ) {
+	function createRenderer( type, antialias, shadows ) {
 
 		rendererPropertiesRow.setDisplay( type === 'WebGLRenderer' ? '' : 'none' );
 
-		var renderer = new rendererTypes[ type ]( { antialias: antialias} );
-		renderer.gammaInput = gammaIn;
-		renderer.gammaOutput = gammaOut;
+		var renderer = new rendererTypes[ type ]( { antialias: antialias } );
+
 		if ( shadows && renderer.shadowMap ) {
 
 			renderer.shadowMap.enabled = true;
@@ -169,7 +146,7 @@ Sidebar.Project = function ( editor ) {
 
 	}
 
-	createRenderer( config.getKey( 'project/renderer' ), config.getKey( 'project/renderer/antialias' ), config.getKey( 'project/renderer/shadows' ), config.getKey( 'project/renderer/gammaInput' ), config.getKey( 'project/renderer/gammaOutput' ) );
+	createRenderer( config.getKey( 'project/renderer' ), config.getKey( 'project/renderer/antialias' ), config.getKey( 'project/renderer/shadows' ) );
 
 	return container;
 

+ 3 - 3
editor/js/Sidebar.Scene.js

@@ -59,7 +59,7 @@ Sidebar.Scene = function ( editor ) {
 
 		var html = '<span class="type ' + object.type + '"></span> ' + escapeHTML( object.name );
 
-		if ( object instanceof THREE.Mesh ) {
+		if ( object.isMesh ) {
 
 			var geometry = object.geometry;
 			var material = object.material;
@@ -231,13 +231,13 @@ Sidebar.Scene = function ( editor ) {
 
 			fogColor.setHexValue( scene.fog.color.getHex() );
 
-			if ( scene.fog instanceof THREE.Fog ) {
+			if ( scene.fog.isFog ) {
 
 				fogType.setValue( "Fog" );
 				fogNear.setValue( scene.fog.near );
 				fogFar.setValue( scene.fog.far );
 
-			} else if ( scene.fog instanceof THREE.FogExp2 ) {
+			} else if ( scene.fog.isFogExp2 ) {
 
 				fogType.setValue( "FogExp2" );
 				fogDensity.setValue( scene.fog.density );

+ 10 - 4
editor/js/Strings.js

@@ -41,6 +41,7 @@ var Strings = function ( config ) {
 			'menubar/add/sphere': 'Sphere',
 			'menubar/add/icosahedron': 'Icosahedron',
 			'menubar/add/torus': 'Torus',
+			'menubar/add/tube': 'Tube',
 			'menubar/add/torusknot': 'TorusKnot',
 			'menubar/add/lathe': 'Lathe',
 			'menubar/add/sprite': 'Sprite',
@@ -162,6 +163,15 @@ var Strings = function ( config ) {
 			'sidebar/geometry/torusKnot_geometry/p': 'P',
 			'sidebar/geometry/torusKnot_geometry/q': 'Q',
 
+			'sidebar/geometry/tube_geometry/path': 'Path',
+			'sidebar/geometry/tube_geometry/radius': 'Radius',
+			'sidebar/geometry/tube_geometry/tube': 'Tube',
+			'sidebar/geometry/tube_geometry/tubularsegments': 'Tubular segments',
+			'sidebar/geometry/tube_geometry/radialsegments': 'Radial segments',
+			'sidebar/geometry/tube_geometry/closed': 'Closed',
+			'sidebar/geometry/tube_geometry/curvetype': 'Curve Type',
+			'sidebar/geometry/tube_geometry/tension': 'Tension',
+
 			'sidebar/material/new': 'New',
 			'sidebar/material/copy': 'Copy',
 			'sidebar/material/paste': 'Paste',
@@ -226,8 +236,6 @@ var Strings = function ( config ) {
 			'sidebar/project/renderer': 'Renderer',
 			'sidebar/project/antialias': 'antialias',
 			'sidebar/project/shadows': 'shadows',
-			'sidebar/project/gammainput': 'γ input',
-			'sidebar/project/gammaoutput': 'γ output',
 
 			'sidebar/settings': 'Settings',
 			'sidebar/settings/language': 'Language',
@@ -475,8 +483,6 @@ var Strings = function ( config ) {
 			'sidebar/project/renderer': '渲染器',
 			'sidebar/project/antialias': '抗锯齿',
 			'sidebar/project/shadows': '阴影',
-			'sidebar/project/gammainput': 'γ输入',
-			'sidebar/project/gammaoutput': 'γ输出',
 
 			'sidebar/settings': '设置',
 			'sidebar/settings/language': '语言',

+ 3 - 3
editor/js/Viewport.Info.js

@@ -46,16 +46,16 @@ Viewport.Info = function ( editor ) {
 
 				objects ++;
 
-				if ( object instanceof THREE.Mesh ) {
+				if ( object.isMesh ) {
 
 					var geometry = object.geometry;
 
-					if ( geometry instanceof THREE.Geometry ) {
+					if ( geometry.isGeometry ) {
 
 						vertices += geometry.vertices.length;
 						triangles += geometry.faces.length;
 
-					} else if ( geometry instanceof THREE.BufferGeometry ) {
+					} else if ( geometry.isBufferGeometry ) {
 
 						vertices += geometry.attributes.position.count;
 

+ 27 - 3
editor/js/Viewport.js

@@ -312,6 +312,7 @@ var Viewport = function ( editor ) {
 
 		renderer.autoClear = false;
 		renderer.autoUpdateScene = false;
+		renderer.gammaOutput = true;
 		renderer.setPixelRatio( window.devicePixelRatio );
 		renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight );
 
@@ -393,7 +394,7 @@ var Viewport = function ( editor ) {
 
 		}
 
-		if ( object instanceof THREE.PerspectiveCamera ) {
+		if ( object.isPerspectiveCamera ) {
 
 			object.updateProjectionMatrix();
 
@@ -477,13 +478,13 @@ var Viewport = function ( editor ) {
 
 		}
 
-		if ( scene.fog instanceof THREE.Fog ) {
+		if ( scene.fog.isFog ) {
 
 			scene.fog.color.setHex( fogColor );
 			scene.fog.near = fogNear;
 			scene.fog.far = fogFar;
 
-		} else if ( scene.fog instanceof THREE.FogExp2 ) {
+		} else if ( scene.fog.isFogExp2 ) {
 
 			scene.fog.color.setHex( fogColor );
 			scene.fog.density = fogDensity;
@@ -519,6 +520,29 @@ var Viewport = function ( editor ) {
 
 	} );
 
+	// animations
+
+	var prevTime = performance.now();
+
+	function animate( time ) {
+
+		requestAnimationFrame( animate );
+
+		var mixer = editor.mixer;
+
+		if ( mixer.stats.actions.inUse > 0 ) {
+
+			mixer.update( ( time - prevTime ) / 1000 );
+			render();
+
+		}
+
+		prevTime = time;
+
+	}
+
+	requestAnimationFrame( animate );
+
 	//
 
 	function render() {

+ 1 - 2
editor/js/libs/app.js

@@ -21,13 +21,12 @@ var APP = {
 		this.load = function ( json ) {
 
 			renderer = new THREE.WebGLRenderer( { antialias: true } );
+			renderer.gammaOutput = true;
 			renderer.setClearColor( 0x000000 );
 			renderer.setPixelRatio( window.devicePixelRatio );
 
 			var project = json.project;
 
-			if ( project.gammaInput ) renderer.gammaInput = true;
-			if ( project.gammaOutput ) renderer.gammaOutput = true;
 			if ( project.shadows ) renderer.shadowMap.enabled = true;
 			if ( project.vr ) renderer.vr.enabled = true;
 

+ 1 - 5
editor/js/libs/tern-threejs/threejs.js

@@ -4621,11 +4621,7 @@
     "WebGLRenderTargetCube": {
       "!url": "http://threejs.org/docs/#Reference/renderers/WebGLRenderTargetCube",
       "prototype": {
-        "!proto": "THREE.WebGLRenderTarget.prototype",
-        "activeCubeFace": {
-          "!type": "integer",
-          "!doc": "The activeCubeFace property corresponds to a cube side (PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5) and is\n\t\tused and set internally by the [page:CubeCamera]."
-        }
+        "!proto": "THREE.WebGLRenderTarget.prototype"
       },
       "!doc": "[page:CubeCamera] uses this as its [page:WebGLRenderTarget]",
       "!type": "fn(width: number, height: number, options: object)"

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

@@ -115,8 +115,8 @@ UI.Element.prototype = {
 // properties
 
 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 ) {
 
@@ -863,9 +863,9 @@ UI.Integer.prototype.setValue = function ( value ) {
 };
 
 UI.Integer.prototype.setStep = function ( step ) {
-	
-	this.step = parseInt( step ); 
-	
+
+	this.step = parseInt( step );
+
 	return this;
 
 };

+ 8 - 2
examples/js/GPUComputationRenderer.js

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

+ 200 - 64
examples/js/MarchingCubes.js

@@ -1,6 +1,7 @@
 /**
  * @author alteredq / http://alteredqualia.com/
  * @author mrdoob / http://mrdoob.com
+ * @author chaht01 / http://hyuntak.com
  * Port of http://webglsamples.org/blob/blob.html
  */
 
@@ -14,6 +15,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 	var vlist = new Float32Array( 12 * 3 );
 	var nlist = new Float32Array( 12 * 3 );
+	var clist = new Float32Array( 12 * 3 );
 
 	this.enableUvs = enableUvs !== undefined ? enableUvs : false;
 	this.enableColors = enableColors !== undefined ? enableColors : false;
@@ -45,6 +47,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 		this.field = new Float32Array( this.size3 );
 		this.normal_cache = new Float32Array( this.size3 * 3 );
+		this.palette = new Float32Array( this.size3 * 3 );
 
 		// immediate render mode simulator
 
@@ -83,7 +86,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 	}
 
-	function VIntX( q, offset, isol, x, y, z, valp1, valp2 ) {
+	function VIntX( q, offset, isol, x, y, z, valp1, valp2, c_offset1, c_offset2 ) {
 
 		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
 			nc = scope.normal_cache;
@@ -96,9 +99,13 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 		nlist[ offset + 1 ] = lerp( nc[ q + 1 ], nc[ q + 4 ], mu );
 		nlist[ offset + 2 ] = lerp( nc[ q + 2 ], nc[ q + 5 ], mu );
 
+		clist[ offset + 0 ] = lerp( scope.palette[ c_offset1 * 3 + 0 ], scope.palette[ c_offset2 * 3 + 0 ], mu );
+		clist[ offset + 1 ] = lerp( scope.palette[ c_offset1 * 3 + 1 ], scope.palette[ c_offset2 * 3 + 1 ], mu );
+		clist[ offset + 2 ] = lerp( scope.palette[ c_offset1 * 3 + 2 ], scope.palette[ c_offset2 * 3 + 2 ], mu );
+
 	}
 
-	function VIntY( q, offset, isol, x, y, z, valp1, valp2 ) {
+	function VIntY( q, offset, isol, x, y, z, valp1, valp2, c_offset1, c_offset2 ) {
 
 		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
 			nc = scope.normal_cache;
@@ -113,9 +120,13 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 		nlist[ offset + 1 ] = lerp( nc[ q + 1 ], nc[ q2 + 1 ], mu );
 		nlist[ offset + 2 ] = lerp( nc[ q + 2 ], nc[ q2 + 2 ], mu );
 
+		clist[ offset + 0 ] = lerp( scope.palette[ c_offset1 * 3 + 0 ], scope.palette[ c_offset2 * 3 + 0 ], mu );
+		clist[ offset + 1 ] = lerp( scope.palette[ c_offset1 * 3 + 1 ], scope.palette[ c_offset2 * 3 + 1 ], mu );
+		clist[ offset + 2 ] = lerp( scope.palette[ c_offset1 * 3 + 2 ], scope.palette[ c_offset2 * 3 + 2 ], mu );
+
 	}
 
-	function VIntZ( q, offset, isol, x, y, z, valp1, valp2 ) {
+	function VIntZ( q, offset, isol, x, y, z, valp1, valp2, c_offset1, c_offset2 ) {
 
 		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
 			nc = scope.normal_cache;
@@ -130,6 +141,10 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 		nlist[ offset + 1 ] = lerp( nc[ q + 1 ], nc[ q2 + 1 ], mu );
 		nlist[ offset + 2 ] = lerp( nc[ q + 2 ], nc[ q2 + 2 ], mu );
 
+		clist[ offset + 0 ] = lerp( scope.palette[ c_offset1 * 3 + 0 ], scope.palette[ c_offset2 * 3 + 0 ], mu );
+		clist[ offset + 1 ] = lerp( scope.palette[ c_offset1 * 3 + 1 ], scope.palette[ c_offset2 * 3 + 1 ], mu );
+		clist[ offset + 2 ] = lerp( scope.palette[ c_offset1 * 3 + 2 ], scope.palette[ c_offset2 * 3 + 2 ], mu );
+
 	}
 
 	function compNorm( q ) {
@@ -139,8 +154,10 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 		if ( scope.normal_cache[ q3 ] === 0.0 ) {
 
 			scope.normal_cache[ q3 + 0 ] = scope.field[ q - 1 ] - scope.field[ q + 1 ];
-			scope.normal_cache[ q3 + 1 ] = scope.field[ q - scope.yd ] - scope.field[ q + scope.yd ];
-			scope.normal_cache[ q3 + 2 ] = scope.field[ q - scope.zd ] - scope.field[ q + scope.zd ];
+			scope.normal_cache[ q3 + 1 ] =
+				scope.field[ q - scope.yd ] - scope.field[ q + scope.yd ];
+			scope.normal_cache[ q3 + 2 ] =
+				scope.field[ q - scope.zd ] - scope.field[ q + scope.zd ];
 
 		}
 
@@ -195,7 +212,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 			compNorm( q );
 			compNorm( q1 );
-			VIntX( q * 3, 0, isol, fx, fy, fz, field0, field1 );
+			VIntX( q * 3, 0, isol, fx, fy, fz, field0, field1, q, q1 );
 
 		}
 
@@ -203,7 +220,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 			compNorm( q1 );
 			compNorm( q1y );
-			VIntY( q1 * 3, 3, isol, fx2, fy, fz, field1, field3 );
+			VIntY( q1 * 3, 3, isol, fx2, fy, fz, field1, field3, q1, q1y );
 
 		}
 
@@ -211,7 +228,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 			compNorm( qy );
 			compNorm( q1y );
-			VIntX( qy * 3, 6, isol, fx, fy2, fz, field2, field3 );
+			VIntX( qy * 3, 6, isol, fx, fy2, fz, field2, field3, qy, q1y );
 
 		}
 
@@ -219,7 +236,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 			compNorm( q );
 			compNorm( qy );
-			VIntY( q * 3, 9, isol, fx, fy, fz, field0, field2 );
+			VIntY( q * 3, 9, isol, fx, fy, fz, field0, field2, q, qy );
 
 		}
 
@@ -229,7 +246,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 			compNorm( qz );
 			compNorm( q1z );
-			VIntX( qz * 3, 12, isol, fx, fy, fz2, field4, field5 );
+			VIntX( qz * 3, 12, isol, fx, fy, fz2, field4, field5, qz, q1z );
 
 		}
 
@@ -237,7 +254,18 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 			compNorm( q1z );
 			compNorm( q1yz );
-			VIntY( q1z * 3, 15, isol, fx2, fy, fz2, field5, field7 );
+			VIntY(
+				q1z * 3,
+				15,
+				isol,
+				fx2,
+				fy,
+				fz2,
+				field5,
+				field7,
+				q1z,
+				q1yz
+			);
 
 		}
 
@@ -245,7 +273,18 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 			compNorm( qyz );
 			compNorm( q1yz );
-			VIntX( qyz * 3, 18, isol, fx, fy2, fz2, field6, field7 );
+			VIntX(
+				qyz * 3,
+				18,
+				isol,
+				fx,
+				fy2,
+				fz2,
+				field6,
+				field7,
+				qyz,
+				q1yz
+			);
 
 		}
 
@@ -253,17 +292,16 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 			compNorm( qz );
 			compNorm( qyz );
-			VIntY( qz * 3, 21, isol, fx, fy, fz2, field4, field6 );
+			VIntY( qz * 3, 21, isol, fx, fy, fz2, field4, field6, qz, qyz );
 
 		}
 
 		// vertical lines of the cube
-
 		if ( bits & 256 ) {
 
 			compNorm( q );
 			compNorm( qz );
-			VIntZ( q * 3, 24, isol, fx, fy, fz, field0, field4 );
+			VIntZ( q * 3, 24, isol, fx, fy, fz, field0, field4, q, qz );
 
 		}
 
@@ -271,7 +309,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 			compNorm( q1 );
 			compNorm( q1z );
-			VIntZ( q1 * 3, 27, isol, fx2, fy, fz, field1, field5 );
+			VIntZ( q1 * 3, 27, isol, fx2, fy, fz, field1, field5, q1, q1z );
 
 		}
 
@@ -279,7 +317,18 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 			compNorm( q1y );
 			compNorm( q1yz );
-			VIntZ( q1y * 3, 30, isol, fx2, fy2, fz, field3, field7 );
+			VIntZ(
+				q1y * 3,
+				30,
+				isol,
+				fx2,
+				fy2,
+				fz,
+				field3,
+				field7,
+				q1y,
+				q1yz
+			);
 
 		}
 
@@ -287,13 +336,17 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 			compNorm( qy );
 			compNorm( qyz );
-			VIntZ( qy * 3, 33, isol, fx, fy2, fz, field2, field6 );
+			VIntZ( qy * 3, 33, isol, fx, fy2, fz, field2, field6, qy, qyz );
 
 		}
 
 		cubeindex <<= 4; // re-purpose cubeindex into an offset into triTable
 
-		var o1, o2, o3, numtris = 0, i = 0;
+		var o1,
+			o2,
+			o3,
+			numtris = 0,
+			i = 0;
 
 		// here is where triangles are created
 
@@ -303,11 +356,15 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 			o2 = o1 + 1;
 			o3 = o1 + 2;
 
-			posnormtriv( vlist, nlist,
+			posnormtriv(
+				vlist,
+				nlist,
+				clist,
 				3 * THREE.triTable[ o1 ],
 				3 * THREE.triTable[ o2 ],
 				3 * THREE.triTable[ o3 ],
-				renderCallback );
+				renderCallback
+			);
 
 			i += 3;
 			numtris ++;
@@ -322,7 +379,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 	// Immediate render mode simulator
 	/////////////////////////////////////
 
-	function posnormtriv( pos, norm, o1, o2, o3, renderCallback ) {
+	function posnormtriv( pos, norm, colors, o1, o2, o3, renderCallback ) {
 
 		var c = scope.count * 3;
 
@@ -360,7 +417,6 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 			scope.normalArray[ c + 7 ] = ny;
 			scope.normalArray[ c + 8 ] = nz;
 
-
 		} else {
 
 			scope.normalArray[ c + 0 ] = norm[ o1 + 0 ];
@@ -398,17 +454,17 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 		if ( scope.enableColors ) {
 
-			scope.colorArray[ c + 0 ] = pos[ o1 + 0 ];
-			scope.colorArray[ c + 1 ] = pos[ o1 + 1 ];
-			scope.colorArray[ c + 2 ] = pos[ o1 + 2 ];
+			scope.colorArray[ c + 0 ] = colors[ o1 + 0 ];
+			scope.colorArray[ c + 1 ] = colors[ o1 + 1 ];
+			scope.colorArray[ c + 2 ] = colors[ o1 + 2 ];
 
-			scope.colorArray[ c + 3 ] = pos[ o2 + 0 ];
-			scope.colorArray[ c + 4 ] = pos[ o2 + 1 ];
-			scope.colorArray[ c + 5 ] = pos[ o2 + 2 ];
+			scope.colorArray[ c + 3 ] = colors[ o2 + 0 ];
+			scope.colorArray[ c + 4 ] = colors[ o2 + 1 ];
+			scope.colorArray[ c + 5 ] = colors[ o2 + 2 ];
 
-			scope.colorArray[ c + 6 ] = pos[ o3 + 0 ];
-			scope.colorArray[ c + 7 ] = pos[ o3 + 1 ];
-			scope.colorArray[ c + 8 ] = pos[ o3 + 2 ];
+			scope.colorArray[ c + 6 ] = colors[ o3 + 0 ];
+			scope.colorArray[ c + 7 ] = colors[ o3 + 1 ];
+			scope.colorArray[ c + 8 ] = colors[ o3 + 2 ];
 
 		}
 
@@ -484,10 +540,35 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 	// Adds a reciprocal ball (nice and blobby) that, to be fast, fades to zero after
 	// a fixed distance, determined by strength and subtract.
 
-	this.addBall = function ( ballx, bally, ballz, strength, subtract ) {
+	this.addBall = function ( ballx, bally, ballz, strength, subtract, colors ) {
 
 		var sign = Math.sign( strength );
 		strength = Math.abs( strength );
+		var userDefineColor = ! ( colors === undefined || colors === null );
+		var ballColor = new THREE.Color( ballx, bally, ballz );
+		if ( userDefineColor ) {
+
+			try {
+
+				ballColor =
+					colors instanceof THREE.Color
+						? colors
+						: Array.isArray( colors )
+							? new THREE.Color(
+								Math.min( Math.abs( colors[ 0 ] ), 1 ),
+								Math.min( Math.abs( colors[ 1 ] ), 1 ),
+								Math.min( Math.abs( colors[ 2 ] ), 1 )
+						  )
+							: new THREE.Color( colors );
+
+			} catch ( err ) {
+
+				userDefineColor = false;
+				ballColor = new THREE.Color( ballx, bally, ballz );
+
+			}
+
+		}
 
 		// Let's solve the equation to find the radius:
 		// 1.0 / (0.000001 + radius^2) * strength - subtract = 0
@@ -501,19 +582,23 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 			ys = bally * this.size,
 			xs = ballx * this.size;
 
-		var min_z = Math.floor( zs - radius ); if ( min_z < 1 ) min_z = 1;
-		var max_z = Math.floor( zs + radius ); if ( max_z > this.size - 1 ) max_z = this.size - 1;
-		var min_y = Math.floor( ys - radius ); if ( min_y < 1 ) min_y = 1;
-		var max_y = Math.floor( ys + radius ); if ( max_y > this.size - 1 ) max_y = this.size - 1;
-		var min_x = Math.floor( xs - radius ); if ( min_x < 1 ) min_x = 1;
-		var max_x = Math.floor( xs + radius ); if ( max_x > this.size - 1 ) max_x = this.size - 1;
-
+		var min_z = Math.floor( zs - radius );
+		if ( min_z < 1 ) min_z = 1;
+		var max_z = Math.floor( zs + radius );
+		if ( max_z > this.size - 1 ) max_z = this.size - 1;
+		var min_y = Math.floor( ys - radius );
+		if ( min_y < 1 ) min_y = 1;
+		var max_y = Math.floor( ys + radius );
+		if ( max_y > this.size - 1 ) max_y = this.size - 1;
+		var min_x = Math.floor( xs - radius );
+		if ( min_x < 1 ) min_x = 1;
+		var max_x = Math.floor( xs + radius );
+		if ( max_x > this.size - 1 ) max_x = this.size - 1;
 
 		// Don't polygonize in the outer layer because normals aren't
 		// well-defined there.
 
 		var x, y, z, y_offset, z_offset, fx, fy, fz, fz2, fy2, val;
-
 		for ( z = min_z; z < max_z; z ++ ) {
 
 			z_offset = this.size2 * z;
@@ -530,7 +615,21 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 					fx = x / this.size - ballx;
 					val = strength / ( 0.000001 + fx * fx + fy2 + fz2 ) - subtract;
-					if ( val > 0.0 ) this.field[ y_offset + x ] += val * sign;
+					if ( val > 0.0 ) {
+
+						this.field[ y_offset + x ] += val * sign;
+
+						// optimization
+						// http://www.geisswerks.com/ryan/BLOBS/blobs.html
+						const ratio =
+							Math.sqrt( ( x - xs ) * ( x - xs ) + ( y - ys ) * ( y - ys ) + ( z - zs ) * ( z - zs ) ) / radius;
+						const contrib =
+							1 - ratio * ratio * ratio * ( ratio * ( ratio * 6 - 15 ) + 10 );
+						this.palette[ ( y_offset + x ) * 3 + 0 ] += ballColor.r * contrib;
+						this.palette[ ( y_offset + x ) * 3 + 1 ] += ballColor.g * contrib;
+						this.palette[ ( y_offset + x ) * 3 + 2 ] += ballColor.b * contrib;
+
+					}
 
 				}
 
@@ -542,14 +641,18 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 	this.addPlaneX = function ( strength, subtract ) {
 
-		var x, y, z, xx, val, xdiv, cxy,
-
+		var x,
+			y,
+			z,
+			xx,
+			val,
+			xdiv,
+			cxy,
 			// cache attribute lookups
 			size = this.size,
 			yd = this.yd,
 			zd = this.zd,
 			field = this.field,
-
 			dist = size * Math.sqrt( strength / subtract );
 
 		if ( dist > size ) dist = size;
@@ -582,14 +685,19 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 	this.addPlaneY = function ( strength, subtract ) {
 
-		var x, y, z, yy, val, ydiv, cy, cxy,
-
+		var x,
+			y,
+			z,
+			yy,
+			val,
+			ydiv,
+			cy,
+			cxy,
 			// cache attribute lookups
 			size = this.size,
 			yd = this.yd,
 			zd = this.zd,
 			field = this.field,
-
 			dist = size * Math.sqrt( strength / subtract );
 
 		if ( dist > size ) dist = size;
@@ -608,8 +716,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 					cxy = cy + x;
 
-					for ( z = 0; z < size; z ++ )
-						field[ zd * z + cxy ] += val;
+					for ( z = 0; z < size; z ++ ) field[ zd * z + cxy ] += val;
 
 				}
 
@@ -621,14 +728,19 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 	this.addPlaneZ = function ( strength, subtract ) {
 
-		var x, y, z, zz, val, zdiv, cz, cyz,
-
+		var x,
+			y,
+			z,
+			zz,
+			val,
+			zdiv,
+			cz,
+			cyz,
 			// cache attribute lookups
 			size = this.size,
 			yd = this.yd,
 			zd = this.zd,
 			field = this.field,
-
 			dist = size * Math.sqrt( strength / subtract );
 
 		if ( dist > size ) dist = size;
@@ -646,8 +758,7 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 					cyz = cz + y * yd;
 
-					for ( x = 0; x < size; x ++ )
-						field[ cyz + x ] += val;
+					for ( x = 0; x < size; x ++ ) field[ cyz + x ] += val;
 
 				}
 
@@ -671,6 +782,9 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 			this.normal_cache[ i * 3 ] = 0.0;
 			this.field[ i ] = 0.0;
+			this.palette[ i * 3 ] = this.palette[ i * 3 + 1 ] = this.palette[
+				i * 3 + 2
+			] = 0.0;
 
 		}
 
@@ -713,7 +827,9 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 	this.generateGeometry = function () {
 
-		console.warn( 'THREE.MarchingCubes: generateGeometry() now returns THREE.BufferGeometry' );
+		console.warn(
+			"THREE.MarchingCubes: generateGeometry() now returns THREE.BufferGeometry"
+		);
 		return this.generateBufferGeometry();
 
 	};
@@ -738,10 +854,26 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 		var geo_callback = function ( object ) {
 
-			if ( scope.hasPositions ) posArray = concatenate( posArray, object.positionArray, object.count * 3 );
-			if ( scope.hasNormals ) normArray = concatenate( normArray, object.normalArray, object.count * 3 );
-			if ( scope.hasColors ) colorArray = concatenate( colorArray, object.colorArray, object.count * 3 );
-			if ( scope.hasUvs ) uvArray = concatenate( uvArray, object.uvArray, object.count * 2 );
+			if ( scope.hasPositions )
+				posArray = concatenate(
+					posArray,
+					object.positionArray,
+					object.count * 3
+				);
+			if ( scope.hasNormals )
+				normArray = concatenate(
+					normArray,
+					object.normalArray,
+					object.count * 3
+				);
+			if ( scope.hasColors )
+				colorArray = concatenate(
+					colorArray,
+					object.colorArray,
+					object.count * 3
+				);
+			if ( scope.hasUvs )
+				uvArray = concatenate( uvArray, object.uvArray, object.count * 2 );
 
 			object.count = 0;
 
@@ -749,10 +881,14 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 
 		this.render( geo_callback );
 
-		if ( this.hasPositions ) geo.addAttribute( 'position', new THREE.BufferAttribute( posArray, 3 ) );
-		if ( this.hasNormals ) geo.addAttribute( 'normal', new THREE.BufferAttribute( normArray, 3 ) );
-		if ( this.hasColors ) geo.addAttribute( 'color', new THREE.BufferAttribute( colorArray, 3 ) );
-		if ( this.hasUvs ) geo.addAttribute( 'uv', new THREE.BufferAttribute( uvArray, 2 ) );
+		if ( this.hasPositions )
+			geo.addAttribute( "position", new THREE.BufferAttribute( posArray, 3 ) );
+		if ( this.hasNormals )
+			geo.addAttribute( "normal", new THREE.BufferAttribute( normArray, 3 ) );
+		if ( this.hasColors )
+			geo.addAttribute( "color", new THREE.BufferAttribute( colorArray, 3 ) );
+		if ( this.hasUvs )
+			geo.addAttribute( "uv", new THREE.BufferAttribute( uvArray, 2 ) );
 
 		return geo;
 

+ 39 - 14
examples/js/Ocean.js

@@ -212,6 +212,8 @@ THREE.Ocean.prototype.generateMesh = function () {
 
 THREE.Ocean.prototype.render = function () {
 
+	var currentRenderTarget = this.renderer.getRenderTarget();
+
 	this.scene.overrideMaterial = null;
 
 	if ( this.changed )
@@ -223,9 +225,11 @@ THREE.Ocean.prototype.render = function () {
 	this.renderNormalMap();
 	this.scene.overrideMaterial = null;
 
+	this.renderer.setRenderTarget( currentRenderTarget );
+
 };
 
-THREE.Ocean.prototype.generateSeedPhaseTexture = function() {
+THREE.Ocean.prototype.generateSeedPhaseTexture = function () {
 
 	// Setup the seed texture
 	this.pingPhase = true;
@@ -234,7 +238,7 @@ THREE.Ocean.prototype.generateSeedPhaseTexture = function() {
 
 		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 + 2 ] = 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.materialInitialSpectrum.uniforms.u_wind.value.set( this.windX, this.windY );
 	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.initial = false;
 
-	}else {
+	} else {
 
 		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_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;
 
 };
@@ -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_choppiness.value = this.choppiness;
 	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
 	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_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 ) {
 
 			this.materialOceanHorizontal.uniforms.u_input.value = this.pingTransformFramebuffer.texture;
 			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 {
 
 			this.materialOceanHorizontal.uniforms.u_input.value = this.pongTransformFramebuffer.texture;
 			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_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 ) {
 
 			this.materialOceanVertical.uniforms.u_input.value = this.pingTransformFramebuffer.texture;
 			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 {
 
 			this.materialOceanVertical.uniforms.u_input.value = this.pongTransformFramebuffer.texture;
 			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;
 	if ( this.changed ) this.materialNormal.uniforms.u_size.value = this.size;
 	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 ) {
 
+		var currentRenderTarget = renderer.getRenderTarget();
+
 		renderer.clear();
 
 		// Render scene into texture
 
 		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
 
 		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
 
+		renderer.setRenderTarget( null );
 		renderer.render( this.postprocessing.scene, this.postprocessing.camera );
 
+		renderer.setRenderTarget( currentRenderTarget );
+
 	}
 
 };

+ 16 - 8
examples/js/controls/OrbitControls.js

@@ -537,36 +537,44 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	function handleKeyDown( event ) {
 
-		//console.log( 'handleKeyDown' );
+		// console.log( 'handleKeyDown' );
 
-		// prevent the browser from scrolling on cursor up/down
-
-		event.preventDefault();
+		var needsUpdate = false;
 
 		switch ( event.keyCode ) {
 
 			case scope.keys.UP:
 				pan( 0, scope.keyPanSpeed );
-				scope.update();
+				needsUpdate = true;
 				break;
 
 			case scope.keys.BOTTOM:
 				pan( 0, - scope.keyPanSpeed );
-				scope.update();
+				needsUpdate = true;
 				break;
 
 			case scope.keys.LEFT:
 				pan( scope.keyPanSpeed, 0 );
-				scope.update();
+				needsUpdate = true;
 				break;
 
 			case scope.keys.RIGHT:
 				pan( - scope.keyPanSpeed, 0 );
-				scope.update();
+				needsUpdate = true;
 				break;
 
 		}
 
+		if ( needsUpdate ) {
+
+			// prevent the browser from scrolling on cursor keys
+			event.preventDefault();
+
+			scope.update();
+
+		}
+
+
 	}
 
 	function handleTouchStartRotate( event ) {

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

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

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

@@ -1,4 +1,4 @@
-function Transition ( sceneA, sceneB ) {
+function Transition( sceneA, sceneB ) {
 
 	this.scene = new THREE.Scene();
 
@@ -157,7 +157,9 @@ function Transition ( sceneA, sceneB ) {
 
 			this.sceneA.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 ) {
 
+		var currentRenderTarget = renderer.getRenderTarget();
+
 		scene.updateMatrixWorld();
 
 		if ( camera.parent === null ) camera.updateMatrixWorld();
 
 		_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.setRenderTarget( currentRenderTarget );
+
 	};
 
 	this.dispose = function () {

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

@@ -402,11 +402,32 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 	}
 
-	this.render = function ( scene, camera, renderTarget, forceClear ) {
+	this.render = function ( scene, camera ) {
+
+		var renderTarget = null;
+		var forceClear = false;
+
+		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 ) {
 
-			renderer.render( scene, camera, renderTarget, forceClear );
+			renderer.render( scene, camera );
 			return;
 
 		}
@@ -415,7 +436,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 		renderer.autoClear = this.autoClear;
 
 		// 1. render normally
-		renderer.render( scene, camera, renderTarget, forceClear );
+		renderer.render( scene, camera );
 
 		// 2. render outline
 		var currentSceneAutoUpdate = scene.autoUpdate;
@@ -429,7 +450,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 		scene.traverse( setOutlineMaterial );
 
-		renderer.render( scene, camera, renderTarget );
+		renderer.render( scene, camera );
 
 		scene.traverse( restoreOriginalMaterial );
 
@@ -478,9 +499,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 );
 
-		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 );
 
 	};

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

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

+ 3 - 1
examples/js/exporters/GLTFExporter.js

@@ -1079,6 +1079,8 @@ THREE.GLTFExporter.prototype = {
 
 				if ( ! geometry.isBufferGeometry ) {
 
+					console.warn( 'GLTFExporter: Exporting THREE.Geometry will increase file size. Use THREE.BufferGeometry instead.' );
+
 					var geometryTemp = new THREE.BufferGeometry();
 					geometryTemp.fromGeometry( geometry );
 					geometry = geometryTemp;
@@ -1408,7 +1410,7 @@ THREE.GLTFExporter.prototype = {
 				gltfCamera.perspective = {
 
 					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,
 					znear: camera.near < 0 ? 0 : camera.near
 

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

@@ -169,12 +169,13 @@ THREE.AssimpJSONLoader.prototype = {
 
 						// prop.semantic gives the type of the texture
 						// 1: diffuse
-						// 2: specular mao
+						// 2: specular map
+						// 4: emissive map
 						// 5: height map (bumps)
 						// 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;
 
@@ -186,6 +187,9 @@ THREE.AssimpJSONLoader.prototype = {
 								case 2:
 									keyname = 'specularMap';
 									break;
+								case 4:
+									keyname = 'emissiveMap';
+									break;
 								case 5:
 									keyname = 'bumpMap';
 									break;

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

@@ -1506,7 +1506,7 @@ THREE.ColladaLoader.prototype = {
 
 			}
 
-			material.name = data.name;
+			material.name = data.name || '';
 
 			function getTexture( textureObject ) {
 
@@ -1834,7 +1834,7 @@ THREE.ColladaLoader.prototype = {
 
 			}
 
-			camera.name = data.name;
+			camera.name = data.name || '';
 
 			return camera;
 

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

@@ -11,6 +11,8 @@ THREE.CubemapGenerator = function ( renderer ) {
 
 THREE.CubemapGenerator.prototype.fromEquirectangular = function ( texture, options ) {
 
+	options = options || {};
+
 	var scene = new THREE.Scene();
 
 	var shader = {
@@ -92,9 +94,9 @@ THREE.CubemapGenerator.prototype.fromEquirectangular = function ( texture, optio
 		type: texture.type,
 		format: texture.format,
 		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 );
@@ -120,6 +122,8 @@ THREE.EquirectangularToCubeGenerator = ( function () {
 
 	var EquirectangularToCubeGenerator = function ( sourceTexture, options ) {
 
+		options = options || {};
+
 		this.sourceTexture = sourceTexture;
 		this.resolution = options.resolution || 512;
 
@@ -152,22 +156,26 @@ THREE.EquirectangularToCubeGenerator = ( function () {
 
 		update: function ( renderer ) {
 
+			var currentRenderTarget = renderer.getRenderTarget();
+
 			boxMesh.material.uniforms.equirectangularMap.value = this.sourceTexture;
 
 			for ( var i = 0; i < 6; i ++ ) {
 
-				this.renderTarget.activeCubeFace = i;
-
 				var v = this.views[ i ];
 
 				camera.position.set( 0, 0, 0 );
 				camera.up.set( v.u[ 0 ], v.u[ 1 ], v.u[ 2 ] );
 				camera.lookAt( v.t[ 0 ], v.t[ 1 ], v.t[ 2 ] );
 
-				renderer.render( scene, camera, this.renderTarget, true );
+				renderer.setRenderTarget( this.renderTarget, i );
+				renderer.clear();
+				renderer.render( scene, camera );
 
 			}
 
+			renderer.setRenderTarget( currentRenderTarget );
+
 			return this.renderTarget.texture;
 
 		},

+ 17 - 3
examples/js/loaders/FBXLoader.js

@@ -44,6 +44,7 @@ THREE.FBXLoader = ( function () {
 			var path = ( self.path === undefined ) ? THREE.LoaderUtils.extractUrlBase( url ) : self.path;
 
 			var loader = new THREE.FileLoader( this.manager );
+			loader.setPath( self.path );
 			loader.setResponseType( 'arraybuffer' );
 
 			loader.load( url, function ( buffer ) {
@@ -498,7 +499,7 @@ THREE.FBXLoader = ( function () {
 					break;
 				default:
 					console.warn( 'THREE.FBXLoader: unknown material type "%s". Defaulting to MeshPhongMaterial.', type );
-					material = new THREE.MeshPhongMaterial( { color: 0x3300ff } );
+					material = new THREE.MeshPhongMaterial();
 					break;
 
 			}
@@ -531,11 +532,13 @@ THREE.FBXLoader = ( function () {
 				parameters.color = new THREE.Color().fromArray( materialNode.DiffuseColor.value );
 
 			}
+
 			if ( materialNode.DisplacementFactor ) {
 
 				parameters.displacementScale = materialNode.DisplacementFactor.value;
 
 			}
+
 			if ( materialNode.Emissive ) {
 
 				parameters.emissive = new THREE.Color().fromArray( materialNode.Emissive.value );
@@ -546,31 +549,37 @@ THREE.FBXLoader = ( function () {
 				parameters.emissive = new THREE.Color().fromArray( materialNode.EmissiveColor.value );
 
 			}
+
 			if ( materialNode.EmissiveFactor ) {
 
 				parameters.emissiveIntensity = parseFloat( materialNode.EmissiveFactor.value );
 
 			}
+
 			if ( materialNode.Opacity ) {
 
 				parameters.opacity = parseFloat( materialNode.Opacity.value );
 
 			}
+
 			if ( parameters.opacity < 1.0 ) {
 
 				parameters.transparent = true;
 
 			}
+
 			if ( materialNode.ReflectionFactor ) {
 
 				parameters.reflectivity = materialNode.ReflectionFactor.value;
 
 			}
+
 			if ( materialNode.Shininess ) {
 
 				parameters.shininess = materialNode.Shininess.value;
 
 			}
+
 			if ( materialNode.Specular ) {
 
 				parameters.specular = new THREE.Color().fromArray( materialNode.Specular.value );
@@ -593,7 +602,12 @@ THREE.FBXLoader = ( function () {
 						parameters.bumpMap = self.getTexture( textureMap, child.ID );
 						break;
 
+					case 'Maya|TEX_ao_map':
+						parameters.aoMap = self.getTexture( textureMap, child.ID );
+						break;
+
 					case 'DiffuseColor':
+					case 'Maya|TEX_color_map':
 						parameters.map = self.getTexture( textureMap, child.ID );
 						break;
 
@@ -601,12 +615,12 @@ THREE.FBXLoader = ( function () {
 						parameters.displacementMap = self.getTexture( textureMap, child.ID );
 						break;
 
-
 					case 'EmissiveColor':
 						parameters.emissiveMap = self.getTexture( textureMap, child.ID );
 						break;
 
 					case 'NormalMap':
+					case 'Maya|TEX_normal_map':
 						parameters.normalMap = self.getTexture( textureMap, child.ID );
 						break;
 
@@ -2509,7 +2523,7 @@ THREE.FBXLoader = ( function () {
 
 										sceneGraph.traverse( function ( child ) {
 
-											if ( child.ID = rawModel.id ) {
+											if ( child.ID === rawModel.id ) {
 
 												node.transform = child.matrix;
 

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

@@ -189,7 +189,7 @@ THREE.GLTFLoader = ( function () {
 							break;
 
 						case EXTENSIONS.MSFT_TEXTURE_DDS:
-							extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] = new GLTFTextureDDSExtension( json );
+							extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] = new GLTFTextureDDSExtension();
 							break;
 
 						case EXTENSIONS.KHR_TEXTURE_TRANSFORM:
@@ -1202,6 +1202,7 @@ THREE.GLTFLoader = ( function () {
 	var ATTRIBUTES = {
 		POSITION: 'position',
 		NORMAL: 'normal',
+		TANGENT: 'tangent',
 		TEXCOORD_0: 'uv',
 		TEXCOORD_1: 'uv2',
 		COLOR_0: 'color',
@@ -1361,8 +1362,10 @@ THREE.GLTFLoader = ( function () {
 				var accessor = target.POSITION !== undefined
 					? parser.getDependency( 'accessor', target.POSITION )
 						.then( function ( accessor ) {
+
 							// Cloning not to pollute original accessor below
 							return cloneBufferAttribute( accessor );
+
 						} )
 					: geometry.attributes.position;
 
@@ -1376,7 +1379,9 @@ THREE.GLTFLoader = ( function () {
 				var accessor = target.NORMAL !== undefined
 					? parser.getDependency( 'accessor', target.NORMAL )
 						.then( function ( accessor ) {
+
 							return cloneBufferAttribute( accessor );
+
 						} )
 					: geometry.attributes.normal;
 
@@ -1514,30 +1519,6 @@ THREE.GLTFLoader = ( function () {
 		}
 
 	}
-
-	function isPrimitiveEqual( a, b ) {
-
-		var dracoExtA = a.extensions ? a.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] : undefined;
-		var dracoExtB = b.extensions ? b.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] : undefined;
-
-		if ( dracoExtA && dracoExtB ) {
-
-			if ( dracoExtA.bufferView !== dracoExtB.bufferView ) return false;
-
-			return isObjectEqual( dracoExtA.attributes, dracoExtB.attributes );
-
-		}
-
-		if ( a.indices !== b.indices ) {
-
-			return false;
-
-		}
-
-		return isObjectEqual( a.attributes, b.attributes );
-
-	}
-
 	function isObjectEqual( a, b ) {
 
 		if ( Object.keys( a ).length !== Object.keys( b ).length ) return false;
@@ -1552,59 +1533,68 @@ THREE.GLTFLoader = ( function () {
 
 	}
 
-	function isArrayEqual( a, b ) {
+	function createPrimitiveKey( primitiveDef ) {
 
-		if ( a.length !== b.length ) return false;
+		var dracoExtension = primitiveDef.extensions && primitiveDef.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ];
+		var geometryKey;
 
-		for ( var i = 0, il = a.length; i < il; i ++ ) {
+		if ( dracoExtension ) {
+
+			geometryKey = 'draco:' + dracoExtension.bufferView
+				+ ':' + dracoExtension.indices
+				+ ':' + createAttributesKey( dracoExtension.attributes );
 
-			if ( a[ i ] !== b[ i ] ) return false;
+		} else {
+
+			geometryKey = primitiveDef.indices + ':' + createAttributesKey( primitiveDef.attributes ) + ':' + primitiveDef.mode;
 
 		}
 
-		return true;
+		return geometryKey;
 
 	}
 
-	function getCachedGeometry( cache, newPrimitive ) {
+	function createAttributesKey( attributes ) {
 
-		for ( var i = 0, il = cache.length; i < il; i ++ ) {
+		var attributesKey = '';
 
-			var cached = cache[ i ];
+		var keys = Object.keys( attributes ).sort();
 
-			if ( isPrimitiveEqual( cached.primitive, newPrimitive ) ) return cached.promise;
+		for ( var i = 0, il = keys.length; i < il; i ++ ) {
+
+			attributesKey += keys[ i ] + ':' + attributes[ keys[ i ] ] + ';';
 
 		}
 
-		return null;
+		return attributesKey;
 
 	}
 
-	function getCachedCombinedGeometry( cache, geometries ) {
+	function createArrayKeyBufferGeometry( a ) {
 
-		for ( var i = 0, il = cache.length; i < il; i ++ ) {
+		var arrayKey = '';
 
-			var cached = cache[ i ];
+		for ( var i = 0, il = a.length; i < il; i ++ ) {
 
-			if ( isArrayEqual( geometries, cached.baseGeometries ) ) return cached.geometry;
+			arrayKey += ':' + a[ i ].uuid;
 
 		}
 
-		return null;
+		return arrayKey;
 
 	}
 
-	function getCachedMultiPassGeometry( cache, geometry, primitives ) {
+	function createMultiPassGeometryKey( geometry, primitives ) {
 
-		for ( var i = 0, il = cache.length; i < il; i ++ ) {
+		var key = geometry.uuid;
 
-			var cached = cache[ i ];
+		for ( var i = 0, il = primitives.length; i < il; i ++ ) {
 
-			if ( geometry === cached.baseGeometry && isArrayEqual( primitives, cached.primitives ) ) return cached.geometry;
+			key += i + createPrimitiveKey( primitives[ i ] );
 
 		}
 
-		return null;
+		return key;
 
 	}
 
@@ -1687,9 +1677,9 @@ THREE.GLTFLoader = ( function () {
 		this.cache = new GLTFRegistry();
 
 		// BufferGeometry caching
-		this.primitiveCache = [];
-		this.multiplePrimitivesCache = [];
-		this.multiPassGeometryCache = [];
+		this.primitiveCache = {};
+		this.multiplePrimitivesCache = {};
+		this.multiPassGeometryCache = {};
 
 		this.textureLoader = new THREE.TextureLoader( this.options.manager );
 		this.textureLoader.setCrossOrigin( this.options.crossOrigin );
@@ -2232,6 +2222,18 @@ THREE.GLTFLoader = ( function () {
 
 		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 ] ) {
 
 				var transform = mapDef.extensions !== undefined ? mapDef.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] : undefined;
@@ -2397,14 +2399,6 @@ THREE.GLTFLoader = ( function () {
 
 			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.
 			if ( material.map ) material.map.encoding = THREE.sRGBEncoding;
 			if ( material.emissiveMap ) material.emissiveMap.encoding = THREE.sRGBEncoding;
@@ -2529,14 +2523,15 @@ THREE.GLTFLoader = ( function () {
 		for ( var i = 0, il = primitives.length; i < il; i ++ ) {
 
 			var primitive = primitives[ i ];
+			var cacheKey = createPrimitiveKey( primitive );
 
 			// See if we've already created this geometry
-			var cached = getCachedGeometry( cache, primitive );
+			var cached = cache[ cacheKey ];
 
 			if ( cached ) {
 
 				// Use the cached geometry if it exists
-				pending.push( cached );
+				pending.push( cached.promise );
 
 			} else {
 
@@ -2555,7 +2550,7 @@ THREE.GLTFLoader = ( function () {
 				}
 
 				// Cache this geometry
-				cache.push( { primitive: primitive, promise: geometryPromise } );
+				cache[ cacheKey ] = { primitive: primitive, promise: geometryPromise };
 
 				pending.push( geometryPromise );
 
@@ -2571,7 +2566,8 @@ THREE.GLTFLoader = ( function () {
 
 				// See if we've already created this combined geometry
 				var cache = parser.multiPassGeometryCache;
-				var cached = getCachedMultiPassGeometry( cache, baseGeometry, originalPrimitives );
+				var cacheKey = createMultiPassGeometryKey( baseGeometry, originalPrimitives );
+				var cached = cache[ cacheKey ];
 
 				if ( cached !== null ) return [ cached.geometry ];
 
@@ -2612,7 +2608,7 @@ THREE.GLTFLoader = ( function () {
 
 					geometry.setIndex( indices );
 
-					cache.push( { geometry: geometry, baseGeometry: baseGeometry, primitives: originalPrimitives } );
+					cache[ cacheKey ] = { geometry: geometry, baseGeometry: baseGeometry, primitives: originalPrimitives };
 
 					return [ geometry ];
 
@@ -2631,7 +2627,8 @@ THREE.GLTFLoader = ( function () {
 
 				// See if we've already created this combined geometry
 				var cache = parser.multiplePrimitivesCache;
-				var cached = getCachedCombinedGeometry( cache, geometries );
+				var cacheKey = createArrayKeyBufferGeometry( geometries );
+				var cached = cache[ cacheKey ];
 
 				if ( cached ) {
 
@@ -2641,7 +2638,7 @@ THREE.GLTFLoader = ( function () {
 
 					var geometry = THREE.BufferGeometryUtils.mergeBufferGeometries( geometries, true );
 
-					cache.push( { geometry: geometry, baseGeometries: geometries } );
+					cache[ cacheKey ] = { geometry: geometry, baseGeometries: geometries };
 
 					if ( geometry !== null ) return [ geometry ];
 
@@ -2762,6 +2759,7 @@ THREE.GLTFLoader = ( function () {
 
 					var materials = isMultiMaterial ? mesh.material : [ mesh.material ];
 
+					var useVertexTangents = geometry.attributes.tangent !== undefined;
 					var useVertexColors = geometry.attributes.color !== undefined;
 					var useFlatShading = geometry.attributes.normal === undefined;
 					var useSkinning = mesh.isSkinnedMesh === true;
@@ -2814,12 +2812,13 @@ THREE.GLTFLoader = ( function () {
 						}
 
 						// Clone the material if it will be modified
-						if ( useVertexColors || useFlatShading || useSkinning || useMorphTargets ) {
+						if ( useVertexTangents || useVertexColors || useFlatShading || useSkinning || useMorphTargets ) {
 
 							var cacheKey = 'ClonedMaterial:' + material.uuid + ':';
 
 							if ( material.isGLTFSpecularGlossinessMaterial ) cacheKey += 'specular-glossiness:';
 							if ( useSkinning ) cacheKey += 'skinning:';
+							if ( useVertexTangents ) cacheKey += 'vertex-tangents:';
 							if ( useVertexColors ) cacheKey += 'vertex-colors:';
 							if ( useFlatShading ) cacheKey += 'flat-shading:';
 							if ( useMorphTargets ) cacheKey += 'morph-targets:';
@@ -2834,6 +2833,7 @@ THREE.GLTFLoader = ( function () {
 									: material.clone();
 
 								if ( useSkinning ) cachedMaterial.skinning = true;
+								if ( useVertexTangents ) cachedMaterial.vertexTangents = true;
 								if ( useVertexColors ) cachedMaterial.vertexColors = THREE.VertexColors;
 								if ( useFlatShading ) cachedMaterial.flatShading = true;
 								if ( useMorphTargets ) cachedMaterial.morphTargets = true;
@@ -3327,7 +3327,7 @@ THREE.GLTFLoader = ( function () {
 
 						mesh.bind( new THREE.Skeleton( bones, boneInverses ), mesh.matrixWorld );
 
-					};
+					}
 
 					return node;
 

+ 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 );
 
 		},
 
-		isAtTheEnd: function() {
+		isAtTheEnd: function () {
 
 			return this.currentCharIndex >= this.lineLength;
 
@@ -86,21 +86,27 @@ THREE.LDrawLoader = ( 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 ) {
+
 			return 0;
+
 		}
+
 		if ( a.colourCode < b.colourCode ) {
-			return -1;
+
+			return - 1;
+
 		}
+
 		return 1;
 
 	}
@@ -149,14 +155,14 @@ THREE.LDrawLoader = ( function () {
 				index0 = iElem * elementSize;
 				numGroupVerts = elementSize;
 
-			}
-			else {
+			} else {
 
 				numGroupVerts += elementSize;
 
 			}
 
 		}
+
 		if ( numGroupVerts > 0 ) {
 
 			bufferGeometry.addGroup( index0, Infinity, materials.length - 1 );
@@ -166,12 +172,12 @@ THREE.LDrawLoader = ( function () {
 		bufferGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
 
 		var object3d = null;
+
 		if ( elementSize === 2 ) {
 
 			object3d = new THREE.LineSegments( bufferGeometry, materials );
 
-		}
-		else if ( elementSize === 3 ) {
+		} else if ( elementSize === 3 ) {
 
 			bufferGeometry.computeVertexNormals();
 
@@ -259,7 +265,7 @@ THREE.LDrawLoader = ( function () {
 
 			var fileLoader = new THREE.FileLoader( this.manager );
 			fileLoader.setPath( this.path );
-			fileLoader.load( url, function( text ) {
+			fileLoader.load( url, function ( text ) {
 
 				processObject( text, onLoad );
 
@@ -308,10 +314,10 @@ THREE.LDrawLoader = ( function () {
 							finalizeObject();
 
 						}
+
 					}
 
-				}
-				else {
+				} else {
 
 					// No subobjects, finish object
 					finalizeObject();
@@ -349,7 +355,7 @@ THREE.LDrawLoader = ( function () {
 
 				}
 
-				function loadSubobject ( subobject, sync ) {
+				function loadSubobject( subobject, sync ) {
 
 					parseScope.mainColourCode = subobject.material.userData.code;
 					parseScope.mainEdgeColourCode = subobject.material.userData.edgeMaterial.userData.code;
@@ -416,8 +422,7 @@ THREE.LDrawLoader = ( function () {
 								// Try absolute path
 								newLocationState = LDrawLoader.FILE_LOCATION_NOT_FOUND;
 
-							}
-							else {
+							} else {
 
 								// Next attempt is lower case
 								subobject.fileName = subobject.fileName.toLowerCase();
@@ -442,8 +447,7 @@ THREE.LDrawLoader = ( function () {
 								scope.removeScopeLevel();
 								onProcessed( objGroup );
 
-							}
-							else {
+							} else {
 
 								// Load next subobject
 								loadSubobject( parseScope.subobjects[ parseScope.subobjectIndex ] );
@@ -485,8 +489,7 @@ THREE.LDrawLoader = ( function () {
 
 						loadSubobject( parseScope.subobjects[ parseScope.subobjectIndex ] );
 
-					}
-					else {
+					} else {
 
 						finalizeObject();
 
@@ -494,7 +497,7 @@ THREE.LDrawLoader = ( function () {
 
 				}
 
-				function addSubobject ( subobject, subobjectGroup ) {
+				function addSubobject( subobject, subobjectGroup ) {
 
 					if ( scope.separateObjects ) {
 
@@ -546,7 +549,7 @@ THREE.LDrawLoader = ( function () {
 
 		},
 
-		setFileMap: function( fileMap ) {
+		setFileMap: function ( fileMap ) {
 
 			this.fileMap = fileMap;
 
@@ -601,7 +604,7 @@ THREE.LDrawLoader = ( function () {
 
 		},
 
-		removeScopeLevel: function() {
+		removeScopeLevel: function () {
 
 			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 ];
 
@@ -736,9 +739,10 @@ THREE.LDrawLoader = ( function () {
 
 							colour = '#' + colour.substring( 2 );
 
-						}
-						else if ( ! colour.startsWith( '#' ) ) {
+						} else if ( ! colour.startsWith( '#' ) ) {
+
 							throw 'LDrawLoader: Invalid colour while parsing material' + lineParser.getLineNumberString() + ".";
+
 						}
 						break;
 
@@ -749,8 +753,7 @@ THREE.LDrawLoader = ( function () {
 
 							edgeColour = '#' + edgeColour.substring( 2 );
 
-						}
-						else if ( ! edgeColour.startsWith( '#' ) ) {
+						} else if ( ! edgeColour.startsWith( '#' ) ) {
 
 							// Try to see if edge colour is a colour code
 							edgeMaterial = this.getMaterial( edgeColour );
@@ -849,13 +852,13 @@ THREE.LDrawLoader = ( function () {
 						// Default plastic material with shiny specular
 						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
 						hsl.h = ( hsl.h + 0.5 ) % 1;
 						hsl.l = Math.min( 1, hsl.l + ( 1 - hsl.l ) * 0.7 );
 						shininess = 10;
+
 					}
 
 					specular.setHSL( hsl.h, hsl.s, hsl.l );
@@ -891,6 +894,7 @@ THREE.LDrawLoader = ( function () {
 				default:
 					// Should not happen
 					break;
+
 			}
 
 			// 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;
 
 			if ( luminance !== 0 ) {
+
 				material.emissive.set( material.color ).multiplyScalar( luminance );
+
 			}
 
 			if ( ! edgeMaterial ) {
+
 				// This is the material used for edges
 				edgeMaterial = new THREE.LineBasicMaterial( { color: edgeColour } );
 				edgeMaterial.userData.code = code;
 				edgeMaterial.name = name + " - Edge";
 				edgeMaterial.userData.canHaveEnvMap = false;
+
 			}
 
 			material.userData.code = code;
@@ -948,8 +956,7 @@ THREE.LDrawLoader = ( function () {
 				triangles = [];
 				lineSegments = [];
 
-			}
-			else {
+			} else {
 
 				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() ) );
 
@@ -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
 			for ( lineIndex = 0; lineIndex < numLines; lineIndex ++ ) {
 
-				line = lines[ lineIndex ];
+				var line = lines[ lineIndex ];
 
 				if ( line.length === 0 ) continue;
 
@@ -1060,8 +1053,7 @@ THREE.LDrawLoader = ( function () {
 						currentEmbeddedFileName = line.substring( 7 );
 						currentEmbeddedText = '';
 
-					}
-					else {
+					} else {
 
 						currentEmbeddedText += line + '\n';
 
@@ -1076,8 +1068,10 @@ THREE.LDrawLoader = ( function () {
 				lp.seekNonSpace();
 
 				if ( lp.isAtTheEnd() ) {
+
 					// Empty line
 					continue;
+
 				}
 
 				// Parse the line type
@@ -1102,10 +1096,9 @@ THREE.LDrawLoader = ( function () {
 
 										this.addMaterial( material );
 
-									}
-									else {
+									}	else {
 
-										console.warn( 'LDrawLoader: Error parsing material' + lineParser.getLineNumberString() );
+										console.warn( 'LDrawLoader: Error parsing material' + lp.getLineNumberString() );
 
 									}
 									break;
@@ -1117,22 +1110,22 @@ THREE.LDrawLoader = ( function () {
 
 								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;
 
 								case 'FILE':
@@ -1190,16 +1183,14 @@ THREE.LDrawLoader = ( function () {
 							// Found the subobject path in the preloaded file path map
 							fileName = scope.fileMap[ fileName ];
 
-						}
-						else {
+						}	else {
 
 							// Standardized subfolders
 							if ( fileName.startsWith( 's/' ) ) {
 
 								fileName = 'parts/' + fileName;
 
-							}
-							else if ( fileName.startsWith( '48/' ) ) {
+							} else if ( fileName.startsWith( '48/' ) ) {
 
 								fileName = 'p/' + fileName;
 
@@ -1316,8 +1307,7 @@ THREE.LDrawLoader = ( function () {
 
 				}
 
-			}
-			else {
+			} else {
 
 				groupObject = this.currentGroupObject;
 

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

@@ -162,6 +162,7 @@ THREE.SVGLoader.prototype = {
 							} else {
 								path.lineTo( point.x, point.y );
 							}
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -172,6 +173,7 @@ THREE.SVGLoader.prototype = {
 							control.x = point.x;
 							control.y = point.y;
 							path.lineTo( point.x, point.y );
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -182,6 +184,7 @@ THREE.SVGLoader.prototype = {
 							control.x = point.x;
 							control.y = point.y;
 							path.lineTo( point.x, point.y );
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -193,6 +196,7 @@ THREE.SVGLoader.prototype = {
 							control.x = point.x;
 							control.y = point.y;
 							path.lineTo( point.x, point.y );
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -211,6 +215,7 @@ THREE.SVGLoader.prototype = {
 							control.y = numbers[ j + 3 ];
 							point.x = numbers[ j + 4 ];
 							point.y = numbers[ j + 5 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -229,6 +234,7 @@ THREE.SVGLoader.prototype = {
 							control.y = numbers[ j + 1 ];
 							point.x = numbers[ j + 2 ];
 							point.y = numbers[ j + 3 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -245,6 +251,7 @@ THREE.SVGLoader.prototype = {
 							control.y = numbers[ j + 1 ];
 							point.x = numbers[ j + 2 ];
 							point.y = numbers[ j + 3 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -263,6 +270,7 @@ THREE.SVGLoader.prototype = {
 							control.y = ry;
 							point.x = numbers[ j + 0 ];
 							point.y = numbers[ j + 1 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -277,6 +285,7 @@ THREE.SVGLoader.prototype = {
 							parseArcCommand(
 								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;
 
@@ -294,6 +303,7 @@ THREE.SVGLoader.prototype = {
 							} else {
 								path.lineTo( point.x, point.y );
 							}
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -304,6 +314,7 @@ THREE.SVGLoader.prototype = {
 							control.x = point.x;
 							control.y = point.y;
 							path.lineTo( point.x, point.y );
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -314,6 +325,7 @@ THREE.SVGLoader.prototype = {
 							control.x = point.x;
 							control.y = point.y;
 							path.lineTo( point.x, point.y );
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -325,6 +337,7 @@ THREE.SVGLoader.prototype = {
 							control.x = point.x;
 							control.y = point.y;
 							path.lineTo( point.x, point.y );
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -343,6 +356,7 @@ THREE.SVGLoader.prototype = {
 							control.y = point.y + numbers[ j + 3 ];
 							point.x += numbers[ j + 4 ];
 							point.y += numbers[ j + 5 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -361,6 +375,7 @@ THREE.SVGLoader.prototype = {
 							control.y = point.y + numbers[ j + 1 ];
 							point.x += numbers[ j + 2 ];
 							point.y += numbers[ j + 3 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -377,6 +392,7 @@ THREE.SVGLoader.prototype = {
 							control.y = point.y + numbers[ j + 1 ];
 							point.x += numbers[ j + 2 ];
 							point.y += numbers[ j + 3 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -395,6 +411,7 @@ THREE.SVGLoader.prototype = {
 							control.y = ry;
 							point.x = point.x + numbers[ j + 0 ];
 							point.y = point.y + numbers[ j + 1 ];
+							if ( j === 0 && doSetFirstPoint === true ) firstPoint.copy( point );
 						}
 						break;
 
@@ -409,6 +426,7 @@ THREE.SVGLoader.prototype = {
 							parseArcCommand(
 								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;
 
@@ -432,10 +450,7 @@ THREE.SVGLoader.prototype = {
 
 				// 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.height = header.height;
 
@@ -534,7 +536,7 @@ THREE.TGALoader.prototype = {
 
 		context.putImageData( imageData, 0, 0 );
 
-		return canvas;
+		return useOffscreen ? canvas.transferToImageBitmap() : canvas;
 
 	},
 

+ 29 - 11
examples/js/loaders/VRMLLoader.js

@@ -932,7 +932,7 @@ THREE.VRMLLoader.prototype = {
 
 						if ( data.coordIndex ) {
 
-							function triangulateIndexArray( indexArray, ccw ) {
+							function triangulateIndexArray( indexArray, ccw, colorPerVertex ) {
 
 								if ( ccw === undefined ) {
 
@@ -946,21 +946,37 @@ THREE.VRMLLoader.prototype = {
 
 								for ( i = 0, il = indexArray.length; i < il; i ++ ) {
 
-									var indexedFace = indexArray[ i ];
+									if ( colorPerVertex === false ) {
 
-									// VRML support multipoint indexed face sets (more then 3 vertices). You must calculate the composing triangles here
+										var colorIndices = indexArray[ i ];
 
-									skip = 0;
+										for ( j = 0, jl = colorIndices.length; j < jl; j ++ ) {
 
-									while ( indexedFace.length >= 3 && skip < ( indexedFace.length - 2 ) ) {
+											var index = colorIndices[ j ];
 
-										var i1 = indexedFace[ 0 ];
-										var i2 = indexedFace[ skip + ( ccw ? 1 : 2 ) ];
-										var i3 = indexedFace[ skip + ( ccw ? 2 : 1 ) ];
+											triangulatedIndexArray.push( index, index, index );
 
-										triangulatedIndexArray.push( i1, i2, i3 );
+										}
 
-										skip ++;
+									} else {
+
+										var indexedFace = indexArray[ i ];
+
+										// VRML support multipoint indexed face sets (more then 3 vertices). You must calculate the composing triangles here
+
+										skip = 0;
+
+										while ( indexedFace.length >= 3 && skip < ( indexedFace.length - 2 ) ) {
+
+											var i1 = indexedFace[ 0 ];
+											var i2 = indexedFace[ skip + ( ccw ? 1 : 2 ) ];
+											var i3 = indexedFace[ skip + ( ccw ? 2 : 1 ) ];
+
+											triangulatedIndexArray.push( i1, i2, i3 );
+
+											skip ++;
+
+										}
 
 									}
 
@@ -972,7 +988,7 @@ THREE.VRMLLoader.prototype = {
 
 							var positionIndexes = data.coordIndex ? triangulateIndexArray( data.coordIndex, data.ccw ) : [];
 							var normalIndexes = data.normalIndex ? triangulateIndexArray( data.normalIndex, data.ccw ) : positionIndexes;
-							var colorIndexes = data.colorIndex ? triangulateIndexArray( data.colorIndex, data.ccw ) : positionIndexes;
+							var colorIndexes = data.colorIndex ? triangulateIndexArray( data.colorIndex, data.ccw, data.colorPerVertex ) : positionIndexes;
 							var uvIndexes = data.texCoordIndex ? triangulateIndexArray( data.texCoordIndex, data.ccw ) : positionIndexes;
 
 							var newIndexes = [];
@@ -1095,6 +1111,8 @@ THREE.VRMLLoader.prototype = {
 
 							geometry.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
 
+							parent.material.vertexColors = THREE.VertexColors;
+
 						}
 
 						if ( uvs.length > 0 ) {

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

@@ -491,8 +491,8 @@ THREE.LegacyGLTFLoader = ( function () {
 	};
 
 	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?
 	};
 
@@ -566,8 +566,10 @@ THREE.LegacyGLTFLoader = ( function () {
 
 	function _each( object, callback, thisObj ) {
 
-		if ( !object ) {
+		if ( ! object ) {
+
 			return Promise.resolve();
+
 		}
 
 		var results;
@@ -589,11 +591,11 @@ THREE.LegacyGLTFLoader = ( function () {
 
 					if ( value instanceof Promise ) {
 
-						value.then( function( key, value ) {
+						value.then( function ( key, value ) {
 
 							results[ key ] = value;
 
-						}.bind( this, idx ));
+						}.bind( this, idx ) );
 
 					} else {
 
@@ -621,11 +623,11 @@ THREE.LegacyGLTFLoader = ( function () {
 
 						if ( value instanceof Promise ) {
 
-							value.then( function( key, value ) {
+							value.then( function ( key, value ) {
 
 								results[ key ] = value;
 
-							}.bind( this, key ));
+							}.bind( this, key ) );
 
 						} else {
 
@@ -641,11 +643,11 @@ THREE.LegacyGLTFLoader = ( function () {
 
 		}
 
-		return Promise.all( fns ).then( function() {
+		return Promise.all( fns ).then( function () {
 
 			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 ];
 
@@ -1515,7 +1517,7 @@ THREE.LegacyGLTFLoader = ( function () {
 
 					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 ];
 
@@ -1523,13 +1525,13 @@ THREE.LegacyGLTFLoader = ( function () {
 
 				delete materialParams.diffuse;
 
-				if ( typeof( materialValues.reflective ) === 'string' ) {
+				if ( typeof ( materialValues.reflective ) === 'string' ) {
 
 					materialParams.envMap = dependencies.textures[ materialValues.reflective ];
 
 				}
 
-				if ( typeof( materialValues.bump ) === 'string' ) {
+				if ( typeof ( materialValues.bump ) === 'string' ) {
 
 					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 ) {
 
@@ -1565,7 +1567,7 @@ THREE.LegacyGLTFLoader = ( function () {
 
 					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 ];
 
@@ -1670,9 +1672,9 @@ THREE.LegacyGLTFLoader = ( function () {
 
 									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 );
 
@@ -2217,8 +2219,10 @@ THREE.LegacyGLTFLoader = ( function () {
 					if ( child.material && child.material.isRawShaderMaterial ) {
 
 						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 );
+
 						};
 
 					}

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

@@ -72,7 +72,9 @@ RTTNode.prototype.updateFramesaveTo = function ( frame ) {
 
 	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 );
 
 		}
 

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

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

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

@@ -342,7 +342,8 @@ THREE.Fire = function ( geometry, options ) {
 
 		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;
 
@@ -356,7 +357,8 @@ THREE.Fire = function ( geometry, options ) {
 
 		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;
 
@@ -370,7 +372,8 @@ THREE.Fire = function ( geometry, options ) {
 
 		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;
 
@@ -386,7 +389,8 @@ THREE.Fire = function ( geometry, options ) {
 
 		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;
 
@@ -398,7 +402,8 @@ THREE.Fire = function ( geometry, options ) {
 
 		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;
 			this.field1 = this.fieldProj;
@@ -417,7 +422,8 @@ THREE.Fire = function ( geometry, options ) {
 
 		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;
 

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

@@ -162,7 +162,7 @@ THREE.Lensflare = function () {
 
 	this.onBeforeRender = function ( renderer, scene, camera ) {
 
-		viewport.copy( renderer.getCurrentViewport() );
+		renderer.getCurrentViewport( viewport );
 
 		var invAspect = viewport.w / viewport.z;
 		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 target = new THREE.Vector3();
 	var q = new THREE.Vector4();
+	var size = new THREE.Vector2();
 
 	var textureMatrix = new THREE.Matrix4();
 	var virtualCamera = new THREE.PerspectiveCamera();
@@ -160,7 +161,9 @@ THREE.Reflector = function ( geometry, options ) {
 		renderer.vr.enabled = false; // Avoid camera modification and recursion
 		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.shadowMap.autoUpdate = currentShadowAutoUpdate;
@@ -173,7 +176,7 @@ THREE.Reflector = function ( geometry, options ) {
 
 		if ( bounds !== undefined ) {
 
-			var size = renderer.getSize();
+			renderer.getSize( size );
 			var pixelRatio = renderer.getPixelRatio();
 
 			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 viewport = new THREE.Vector4();
+		var size = new THREE.Vector2();
 
 		return function render( renderer, scene, camera ) {
 
@@ -199,7 +200,9 @@ THREE.Refractor = function ( geometry, options ) {
 			renderer.vr.enabled = false; // avoid camera modification
 			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.shadowMap.autoUpdate = currentShadowAutoUpdate;
@@ -211,7 +214,7 @@ THREE.Refractor = function ( geometry, options ) {
 
 			if ( bounds !== undefined ) {
 
-				var size = renderer.getSize();
+				renderer.getSize( size );
 				var pixelRatio = renderer.getPixelRatio();
 
 				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.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;
 

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

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

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

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

+ 35 - 27
examples/js/postprocessing/AdaptiveToneMappingPass.js

@@ -49,7 +49,7 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 
 	this.adaptLuminanceShader = {
 		defines: {
-			"MIP_LEVEL_1X1" : ( Math.log( this.resolution ) / Math.log( 2.0 ) ).toFixed( 1 )
+			"MIP_LEVEL_1X1": ( Math.log( this.resolution ) / Math.log( 2.0 ) ).toFixed( 1 )
 		},
 		uniforms: {
 			"lastLum": { value: null },
@@ -63,8 +63,8 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 
 			"void main() {",
 
-				"vUv = uv;",
-				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+			"	vUv = uv;",
+			"	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
 
 			"}"
 		].join( '\n' ),
@@ -79,20 +79,20 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 
 			"void main() {",
 
-				"vec4 lastLum = texture2D( lastLum, vUv, MIP_LEVEL_1X1 );",
-				"vec4 currentLum = texture2D( currentLum, vUv, MIP_LEVEL_1X1 );",
+			"	vec4 lastLum = texture2D( lastLum, vUv, MIP_LEVEL_1X1 );",
+			"	vec4 currentLum = texture2D( currentLum, vUv, MIP_LEVEL_1X1 );",
 
-				"float fLastLum = max( minLuminance, lastLum.r );",
-				"float fCurrentLum = max( minLuminance, currentLum.r );",
+			"	float fLastLum = max( minLuminance, lastLum.r );",
+			"	float fCurrentLum = max( minLuminance, currentLum.r );",
 
-				//The adaption seems to work better in extreme lighting differences
-				//if the input luminance is squared.
-				"fCurrentLum *= fCurrentLum;",
+			//The adaption seems to work better in extreme lighting differences
+			//if the input luminance is squared.
+			"	fCurrentLum *= fCurrentLum;",
 
-				// Adapt the luminance using Pattanaik's technique
-				"float fAdaptedLum = fLastLum + (fCurrentLum - fLastLum) * (1.0 - exp(-delta * tau));",
-				// "fAdaptedLum = sqrt(fAdaptedLum);",
-				"gl_FragColor.r = fAdaptedLum;",
+			// Adapt the luminance using Pattanaik's technique
+			"	float fAdaptedLum = fLastLum + (fCurrentLum - fLastLum) * (1.0 - exp(-delta * tau));",
+			// "fAdaptedLum = sqrt(fAdaptedLum);",
+			"	gl_FragColor.r = fAdaptedLum;",
 			"}"
 		].join( '\n' )
 	};
@@ -118,7 +118,7 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 	} );
 
 	this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
-	this.scene  = new THREE.Scene();
+	this.scene = new THREE.Scene();
 
 	this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
 	this.quad.frustumCulled = false; // Avoid getting clipped
@@ -148,7 +148,8 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 			//Render the luminance of the current scene into a render target with mipmapping enabled
 			this.quad.material = this.materialLuminance;
 			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
 			//adapt the luminance over time.
@@ -156,12 +157,14 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 			this.materialAdaptiveLum.uniforms.delta.value = deltaTime;
 			this.materialAdaptiveLum.uniforms.lastLum.value = this.previousLuminanceRT.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.
 			this.quad.material = this.materialCopy;
 			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,17 +173,22 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 		if ( this.renderToScreen ) {
 
+			renderer.setRenderTarget( null );
 			renderer.render( this.scene, this.camera );
 
 		} else {
 
-			renderer.render( this.scene, this.camera, writeBuffer, this.clear );
+			renderer.setRenderTarget( writeBuffer );
+
+			if ( this.clear ) renderer.clear();
+
+			renderer.render( this.scene, this.camera );
 
 		}
 
 	},
 
-	reset: function( renderer ) {
+	reset: function ( renderer ) {
 
 		// render targets
 		if ( this.luminanceRT ) {
@@ -232,7 +240,7 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 	},
 
-	setAdaptive: function( adaptive ) {
+	setAdaptive: function ( adaptive ) {
 
 		if ( adaptive ) {
 
@@ -251,7 +259,7 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 	},
 
-	setAdaptionRate: function( rate ) {
+	setAdaptionRate: function ( rate ) {
 
 		if ( rate ) {
 
@@ -261,7 +269,7 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 	},
 
-	setMinLuminance: function( minLum ) {
+	setMinLuminance: function ( minLum ) {
 
 		if ( minLum ) {
 
@@ -272,7 +280,7 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 	},
 
-	setMaxLuminance: function( maxLum ) {
+	setMaxLuminance: function ( maxLum ) {
 
 		if ( maxLum ) {
 
@@ -282,7 +290,7 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 	},
 
-	setAverageLuminance: function( avgLum ) {
+	setAverageLuminance: function ( avgLum ) {
 
 		if ( avgLum ) {
 
@@ -292,7 +300,7 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 	},
 
-	setMiddleGrey: function( middleGrey ) {
+	setMiddleGrey: function ( middleGrey ) {
 
 		if ( middleGrey ) {
 
@@ -302,7 +310,7 @@ THREE.AdaptiveToneMappingPass.prototype = Object.assign( Object.create( THREE.Pa
 
 	},
 
-	dispose: function() {
+	dispose: function () {
 
 		if ( this.luminanceRT ) {
 

+ 18 - 10
examples/js/postprocessing/AfterimagePass.js

@@ -42,7 +42,7 @@ THREE.AfterimagePass = function ( damp ) {
 	this.sceneComp = new THREE.Scene();
 	this.scene = new THREE.Scene();
 
-	this.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 );
+	this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
 	this.camera.position.z = 1;
 
 	var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
@@ -50,7 +50,7 @@ THREE.AfterimagePass = function ( damp ) {
 	this.quadComp = new THREE.Mesh( geometry, this.shaderMaterial );
 	this.sceneComp.add( this.quadComp );
 
-	var material = new THREE.MeshBasicMaterial( { 
+	var material = new THREE.MeshBasicMaterial( {
 		map: this.textureComp.texture
 	} );
 
@@ -70,17 +70,25 @@ THREE.AfterimagePass.prototype = Object.assign( Object.create( THREE.Pass.protot
 
 		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 ) {
-			
+
+			renderer.setRenderTarget( null );
 			renderer.render( this.scene, this.camera );
-			
+
 		} else {
-			
-			renderer.render( this.scene, this.camera, writeBuffer, this.clear );
-			
+
+			renderer.setRenderTarget( writeBuffer );
+
+			if ( this.clear ) renderer.clear();
+
+			renderer.render( this.scene, this.camera );
+
 		}
 
 	}

+ 11 - 5
examples/js/postprocessing/BloomPass.js

@@ -56,7 +56,7 @@ THREE.BloomPass = function ( strength, kernelSize, sigma, resolution ) {
 	this.materialConvolution = new THREE.ShaderMaterial( {
 
 		uniforms: this.convolutionUniforms,
-		vertexShader:  convolutionShader.vertexShader,
+		vertexShader: convolutionShader.vertexShader,
 		fragmentShader: convolutionShader.fragmentShader,
 		defines: {
 			"KERNEL_SIZE_FLOAT": kernelSize.toFixed( 1 ),
@@ -68,7 +68,7 @@ THREE.BloomPass = function ( strength, kernelSize, sigma, resolution ) {
 	this.needsSwap = false;
 
 	this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
-	this.scene  = new THREE.Scene();
+	this.scene = new THREE.Scene();
 
 	this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
 	this.quad.frustumCulled = false; // Avoid getting clipped
@@ -91,7 +91,9 @@ THREE.BloomPass.prototype = Object.assign( Object.create( THREE.Pass.prototype )
 		this.convolutionUniforms[ "tDiffuse" ].value = readBuffer.texture;
 		this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurX;
 
-		renderer.render( this.scene, this.camera, this.renderTargetX, true );
+		renderer.setRenderTarget( this.renderTargetX );
+		renderer.clear();
+		renderer.render( this.scene, this.camera );
 
 
 		// Render quad with blured scene into texture (convolution pass 2)
@@ -99,7 +101,9 @@ THREE.BloomPass.prototype = Object.assign( Object.create( THREE.Pass.prototype )
 		this.convolutionUniforms[ "tDiffuse" ].value = this.renderTargetX.texture;
 		this.convolutionUniforms[ "uImageIncrement" ].value = THREE.BloomPass.blurY;
 
-		renderer.render( this.scene, this.camera, this.renderTargetY, true );
+		renderer.setRenderTarget( this.renderTargetY );
+		renderer.clear();
+		renderer.render( this.scene, this.camera );
 
 		// Render original scene with superimposed blur to texture
 
@@ -109,7 +113,9 @@ THREE.BloomPass.prototype = Object.assign( Object.create( THREE.Pass.prototype )
 
 		if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST );
 
-		renderer.render( this.scene, this.camera, readBuffer, this.clear );
+		renderer.setRenderTarget( readBuffer );
+		if ( this.clear ) renderer.clear();
+		renderer.render( this.scene, this.camera );
 
 	}
 

+ 9 - 4
examples/js/postprocessing/BokehPass.js

@@ -67,7 +67,7 @@ THREE.BokehPass = function ( scene, camera, params ) {
 	this.needsSwap = false;
 
 	this.camera2 = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
-	this.scene2  = new THREE.Scene();
+	this.scene2 = new THREE.Scene();
 
 	this.quad2 = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
 	this.quad2.frustumCulled = false; // Avoid getting clipped
@@ -97,7 +97,9 @@ THREE.BokehPass.prototype = Object.assign( Object.create( THREE.Pass.prototype )
 
 		renderer.setClearColor( 0xffffff );
 		renderer.setClearAlpha( 1.0 );
-		renderer.render( this.scene, this.camera, this.renderTargetDepth, true );
+		renderer.setRenderTarget( this.renderTargetDepth );
+		renderer.clear();
+		renderer.render( this.scene, this.camera );
 
 		// Render bokeh composite
 
@@ -107,11 +109,14 @@ THREE.BokehPass.prototype = Object.assign( Object.create( THREE.Pass.prototype )
 
 		if ( this.renderToScreen ) {
 
+			renderer.setRenderTarget( null );
 			renderer.render( this.scene2, this.camera2 );
 
 		} else {
 
-			renderer.render( this.scene2, this.camera2, writeBuffer, this.clear );
+			renderer.setRenderTarget( writeBuffer );
+			renderer.clear();
+			renderer.render( this.scene2, this.camera2 );
 
 		}
 
@@ -119,7 +124,7 @@ THREE.BokehPass.prototype = Object.assign( Object.create( THREE.Pass.prototype )
 		renderer.setClearColor( this.oldClearColor );
 		renderer.setClearAlpha( this.oldClearAlpha );
 		renderer.autoClear = this.oldAutoClear;
-	
+
 	}
 
 } );

+ 3 - 1
examples/js/postprocessing/CubeTexturePass.js

@@ -48,7 +48,9 @@ THREE.CubeTexturePass.prototype = Object.assign( Object.create( THREE.Pass.proto
 		this.cubeMesh.material.uniforms[ "opacity" ].value = this.opacity;
 		this.cubeMesh.material.transparent = ( this.opacity < 1.0 );
 
-		renderer.render( this.cubeScene, this.cubeCamera, this.renderToScreen ? null : readBuffer, this.clear );
+		renderer.setRenderTarget( this.renderToScreen ? null : readBuffer );
+		if ( this.clear ) renderer.clear();
+		renderer.render( this.cubeScene, this.cubeCamera );
 
 		renderer.autoClear = oldAutoClear;
 

+ 5 - 2
examples/js/postprocessing/DotScreenPass.js

@@ -26,7 +26,7 @@ THREE.DotScreenPass = function ( center, angle, scale ) {
 	} );
 
 	this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
-	this.scene  = new THREE.Scene();
+	this.scene = new THREE.Scene();
 
 	this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
 	this.quad.frustumCulled = false; // Avoid getting clipped
@@ -47,11 +47,14 @@ THREE.DotScreenPass.prototype = Object.assign( Object.create( THREE.Pass.prototy
 
 		if ( this.renderToScreen ) {
 
+			renderer.setRenderTarget( null );
 			renderer.render( this.scene, this.camera );
 
 		} else {
 
-			renderer.render( this.scene, this.camera, writeBuffer, this.clear );
+			renderer.setRenderTarget( writeBuffer );
+			if ( this.clear ) renderer.clear();
+			renderer.render( this.scene, this.camera );
 
 		}
 

+ 7 - 3
examples/js/postprocessing/EffectComposer.js

@@ -15,7 +15,7 @@ THREE.EffectComposer = function ( renderer, renderTarget ) {
 			stencilBuffer: false
 		};
 
-		var size = renderer.getDrawingBufferSize();
+		var size = renderer.getDrawingBufferSize( new THREE.Vector2() );
 		renderTarget = new THREE.WebGLRenderTarget( size.width, size.height, parameters );
 		renderTarget.texture.name = 'EffectComposer.rt1';
 
@@ -64,7 +64,7 @@ Object.assign( THREE.EffectComposer.prototype, {
 
 		this.passes.push( pass );
 
-		var size = this.renderer.getDrawingBufferSize();
+		var size = this.renderer.getDrawingBufferSize( new THREE.Vector2() );
 		pass.setSize( size.width, size.height );
 
 	},
@@ -87,6 +87,8 @@ Object.assign( THREE.EffectComposer.prototype, {
 
 		this._previousFrameTime = Date.now();
 
+		var currentRenderTarget = this.renderer.getRenderTarget();
+
 		var maskActive = false;
 
 		var pass, i, il = this.passes.length;
@@ -133,13 +135,15 @@ Object.assign( THREE.EffectComposer.prototype, {
 
 		}
 
+		this.renderer.setRenderTarget( currentRenderTarget );
+
 	},
 
 	reset: function ( renderTarget ) {
 
 		if ( renderTarget === undefined ) {
 
-			var size = this.renderer.getDrawingBufferSize();
+			var size = this.renderer.getDrawingBufferSize( new THREE.Vector2() );
 
 			renderTarget = this.renderTarget1.clone();
 			renderTarget.setSize( size.width, size.height );

+ 5 - 2
examples/js/postprocessing/FilmPass.js

@@ -27,7 +27,7 @@ THREE.FilmPass = function ( noiseIntensity, scanlinesIntensity, scanlinesCount,
 	if ( scanlinesCount !== undefined ) this.uniforms.sCount.value = scanlinesCount;
 
 	this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
-	this.scene  = new THREE.Scene();
+	this.scene = new THREE.Scene();
 
 	this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
 	this.quad.frustumCulled = false; // Avoid getting clipped
@@ -48,11 +48,14 @@ THREE.FilmPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ),
 
 		if ( this.renderToScreen ) {
 
+			renderer.setRenderTarget( null );
 			renderer.render( this.scene, this.camera );
 
 		} else {
 
-			renderer.render( this.scene, this.camera, writeBuffer, this.clear );
+			renderer.setRenderTarget( writeBuffer );
+			if ( this.clear ) renderer.clear();
+			renderer.render( this.scene, this.camera );
 
 		}
 

+ 7 - 4
examples/js/postprocessing/GlitchPass.js

@@ -24,7 +24,7 @@ THREE.GlitchPass = function ( dt_size ) {
 	} );
 
 	this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
-	this.scene  = new THREE.Scene();
+	this.scene = new THREE.Scene();
 
 	this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
 	this.quad.frustumCulled = false; // Avoid getting clipped
@@ -77,23 +77,26 @@ THREE.GlitchPass.prototype = Object.assign( Object.create( THREE.Pass.prototype
 
 		if ( this.renderToScreen ) {
 
+			renderer.setRenderTarget( null );
 			renderer.render( this.scene, this.camera );
 
 		} else {
 
-			renderer.render( this.scene, this.camera, writeBuffer, this.clear );
+			renderer.setRenderTarget( writeBuffer );
+			if ( this.clear ) renderer.clear();
+			renderer.render( this.scene, this.camera );
 
 		}
 
 	},
 
-	generateTrigger: function() {
+	generateTrigger: function () {
 
 		this.randX = THREE.Math.randInt( 120, 240 );
 
 	},
 
-	generateHeightmap: function( dt_size ) {
+	generateHeightmap: function ( dt_size ) {
 
 		var data_arr = new Float32Array( dt_size * dt_size * 3 );
 		var length = dt_size * dt_size;

+ 7 - 4
examples/js/postprocessing/HalftonePass.js

@@ -30,7 +30,7 @@ THREE.HalftonePass = function ( width, height, params ) {
 
 		if ( params.hasOwnProperty( key ) && this.uniforms.hasOwnProperty( key ) ) {
 
-			this.uniforms[key].value = params[key];
+			this.uniforms[ key ].value = params[ key ];
 
 		}
 
@@ -42,9 +42,9 @@ THREE.HalftonePass = function ( width, height, params ) {
  	this.quad.frustumCulled = false;
  	this.scene.add( this.quad );
 
- };
+};
 
- THREE.HalftonePass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
+THREE.HalftonePass.prototype = Object.assign( Object.create( THREE.Pass.prototype ), {
 
 	constructor: THREE.HalftonePass,
 
@@ -55,11 +55,14 @@ THREE.HalftonePass = function ( width, height, params ) {
 
  		if ( this.renderToScreen ) {
 
+ 			renderer.setRenderTarget( null );
  			renderer.render( this.scene, this.camera );
 
 		} else {
 
-			renderer.render( this.scene, this.camera, writeBuffer, this.clear );
+ 			renderer.setRenderTarget( writeBuffer );
+ 			if ( this.clear ) renderer.clear();
+			renderer.render( this.scene, this.camera );
 
 		}
 

+ 8 - 3
examples/js/postprocessing/MaskPass.js

@@ -58,8 +58,13 @@ THREE.MaskPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ),
 
 		// draw into the stencil buffer
 
-		renderer.render( this.scene, this.camera, readBuffer, this.clear );
-		renderer.render( this.scene, this.camera, writeBuffer, this.clear );
+		renderer.setRenderTarget( readBuffer );
+		if ( this.clear ) renderer.clear();
+		renderer.render( this.scene, this.camera );
+
+		renderer.setRenderTarget( writeBuffer );
+		if ( this.clear ) renderer.clear();
+		renderer.render( this.scene, this.camera );
 
 		// unlock color and depth buffer for subsequent rendering
 
@@ -68,7 +73,7 @@ THREE.MaskPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ),
 
 		// only render where stencil is set to 1
 
-		state.buffers.stencil.setFunc( context.EQUAL, 1, 0xffffffff );  // draw if == 1
+		state.buffers.stencil.setFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1
 		state.buffers.stencil.setOp( context.KEEP, context.KEEP, context.KEEP );
 
 	}

+ 27 - 9
examples/js/postprocessing/OutlinePass.js

@@ -277,7 +277,9 @@ THREE.OutlinePass.prototype = Object.assign( Object.create( THREE.Pass.prototype
 
 			// 1. Draw Non Selected objects in the depth buffer
 			this.renderScene.overrideMaterial = this.depthMaterial;
-			renderer.render( this.renderScene, this.renderCamera, this.renderTargetDepthBuffer, true );
+			renderer.setRenderTarget( this.renderTargetDepthBuffer );
+			renderer.clear();
+			renderer.render( this.renderScene, this.renderCamera );
 
 			// Make selected objects visible
 			this.changeVisibilityOfSelectedObjects( true );
@@ -291,7 +293,9 @@ THREE.OutlinePass.prototype = Object.assign( Object.create( THREE.Pass.prototype
 			this.prepareMaskMaterial.uniforms[ "cameraNearFar" ].value = new THREE.Vector2( this.renderCamera.near, this.renderCamera.far );
 			this.prepareMaskMaterial.uniforms[ "depthTexture" ].value = this.renderTargetDepthBuffer.texture;
 			this.prepareMaskMaterial.uniforms[ "textureMatrix" ].value = this.textureMatrix;
-			renderer.render( this.renderScene, this.renderCamera, this.renderTargetMaskBuffer, true );
+			renderer.setRenderTarget( this.renderTargetMaskBuffer );
+			renderer.clear();
+			renderer.render( this.renderScene, this.renderCamera );
 			this.renderScene.overrideMaterial = null;
 			this.changeVisibilityOfNonSelectedObjects( true );
 
@@ -300,7 +304,9 @@ THREE.OutlinePass.prototype = Object.assign( Object.create( THREE.Pass.prototype
 			// 2. Downsample to Half resolution
 			this.quad.material = this.materialCopy;
 			this.copyUniforms[ "tDiffuse" ].value = this.renderTargetMaskBuffer.texture;
-			renderer.render( this.scene, this.camera, this.renderTargetMaskDownSampleBuffer, true );
+			renderer.setRenderTarget( this.renderTargetMaskDownSampleBuffer );
+			renderer.clear();
+			renderer.render( this.scene, this.camera );
 
 			this.tempPulseColor1.copy( this.visibleEdgeColor );
 			this.tempPulseColor2.copy( this.hiddenEdgeColor );
@@ -319,26 +325,36 @@ THREE.OutlinePass.prototype = Object.assign( Object.create( THREE.Pass.prototype
 			this.edgeDetectionMaterial.uniforms[ "texSize" ].value = new THREE.Vector2( this.renderTargetMaskDownSampleBuffer.width, this.renderTargetMaskDownSampleBuffer.height );
 			this.edgeDetectionMaterial.uniforms[ "visibleEdgeColor" ].value = this.tempPulseColor1;
 			this.edgeDetectionMaterial.uniforms[ "hiddenEdgeColor" ].value = this.tempPulseColor2;
-			renderer.render( this.scene, this.camera, this.renderTargetEdgeBuffer1, true );
+			renderer.setRenderTarget( this.renderTargetEdgeBuffer1 );
+			renderer.clear();
+			renderer.render( this.scene, this.camera );
 
 			// 4. Apply Blur on Half res
 			this.quad.material = this.separableBlurMaterial1;
 			this.separableBlurMaterial1.uniforms[ "colorTexture" ].value = this.renderTargetEdgeBuffer1.texture;
 			this.separableBlurMaterial1.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionX;
 			this.separableBlurMaterial1.uniforms[ "kernelRadius" ].value = this.edgeThickness;
-			renderer.render( this.scene, this.camera, this.renderTargetBlurBuffer1, true );
+			renderer.setRenderTarget( this.renderTargetBlurBuffer1 );
+			renderer.clear();
+			renderer.render( this.scene, this.camera );
 			this.separableBlurMaterial1.uniforms[ "colorTexture" ].value = this.renderTargetBlurBuffer1.texture;
 			this.separableBlurMaterial1.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionY;
-			renderer.render( this.scene, this.camera, this.renderTargetEdgeBuffer1, true );
+			renderer.setRenderTarget( this.renderTargetEdgeBuffer1 );
+			renderer.clear();
+			renderer.render( this.scene, this.camera );
 
 			// Apply Blur on quarter res
 			this.quad.material = this.separableBlurMaterial2;
 			this.separableBlurMaterial2.uniforms[ "colorTexture" ].value = this.renderTargetEdgeBuffer1.texture;
 			this.separableBlurMaterial2.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionX;
-			renderer.render( this.scene, this.camera, this.renderTargetBlurBuffer2, true );
+			renderer.setRenderTarget( this.renderTargetBlurBuffer2 );
+			renderer.clear();
+			renderer.render( this.scene, this.camera );
 			this.separableBlurMaterial2.uniforms[ "colorTexture" ].value = this.renderTargetBlurBuffer2.texture;
 			this.separableBlurMaterial2.uniforms[ "direction" ].value = THREE.OutlinePass.BlurDirectionY;
-			renderer.render( this.scene, this.camera, this.renderTargetEdgeBuffer2, true );
+			renderer.setRenderTarget( this.renderTargetEdgeBuffer2 );
+			renderer.clear();
+			renderer.render( this.scene, this.camera );
 
 			// Blend it additively over the input texture
 			this.quad.material = this.overlayMaterial;
@@ -353,7 +369,8 @@ THREE.OutlinePass.prototype = Object.assign( Object.create( THREE.Pass.prototype
 
 			if ( maskActive ) renderer.context.enable( renderer.context.STENCIL_TEST );
 
-			renderer.render( this.scene, this.camera, readBuffer, false );
+			renderer.setRenderTarget( readBuffer );
+			renderer.render( this.scene, this.camera );
 
 			renderer.setClearColor( this.oldClearColor, this.oldClearAlpha );
 			renderer.autoClear = oldAutoClear;
@@ -364,6 +381,7 @@ THREE.OutlinePass.prototype = Object.assign( Object.create( THREE.Pass.prototype
 
 			this.quad.material = this.materialCopy;
 			this.copyUniforms[ "tDiffuse" ].value = readBuffer.texture;
+			renderer.setRenderTarget( null );
 			renderer.render( this.scene, this.camera );
 
 		}

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