Mr.doob 6 年之前
父节点
当前提交
43e1d84781
共有 100 个文件被更改,包括 5116 次插入3434 次删除
  1. 8 2
      build/three.js
  2. 218 218
      build/three.min.js
  3. 8 2
      build/three.module.js
  4. 0 1
      docs/api/en/cameras/CubeCamera.html
  5. 0 3
      docs/api/en/core/Geometry.html
  6. 13 0
      docs/api/en/core/Object3D.html
  7. 0 1
      docs/api/en/core/Raycaster.html
  8. 0 6
      docs/api/en/extras/curves/EllipseCurve.html
  9. 15 13
      docs/api/en/geometries/BoxBufferGeometry.html
  10. 15 15
      docs/api/en/geometries/BoxGeometry.html
  11. 0 1
      docs/api/en/helpers/AxesHelper.html
  12. 1 1
      docs/api/en/helpers/RectAreaLightHelper.html
  13. 1 1
      docs/api/en/lights/RectAreaLight.html
  14. 0 1
      docs/api/en/loaders/CubeTextureLoader.html
  15. 0 4
      docs/api/en/loaders/FileLoader.html
  16. 0 1
      docs/api/en/loaders/ObjectLoader.html
  17. 0 1
      docs/api/en/materials/LineBasicMaterial.html
  18. 0 13
      docs/api/en/materials/Material.html
  19. 0 2
      docs/api/en/materials/PointsMaterial.html
  20. 0 1
      docs/api/en/materials/ShaderMaterial.html
  21. 42 26
      docs/api/en/objects/SkinnedMesh.html
  22. 1 1
      docs/api/en/renderers/WebGLRenderer.html
  23. 13 2
      docs/api/zh/core/Object3D.html
  24. 1 2
      docs/api/zh/core/Raycaster.html
  25. 4 4
      docs/api/zh/core/bufferAttributeTypes/BufferAttributeTypes.html
  26. 6 6
      docs/api/zh/extras/Earcut.html
  27. 12 15
      docs/api/zh/extras/ShapeUtils.html
  28. 15 15
      docs/api/zh/extras/core/CurvePath.html
  29. 18 16
      docs/api/zh/extras/core/Font.html
  30. 12 12
      docs/api/zh/extras/core/Interpolations.html
  31. 52 54
      docs/api/zh/extras/core/Path.html
  32. 21 22
      docs/api/zh/extras/core/Shape.html
  33. 28 29
      docs/api/zh/extras/core/ShapePath.html
  34. 7 7
      docs/api/zh/extras/curves/ArcCurve.html
  35. 19 18
      docs/api/zh/extras/curves/CatmullRomCurve3.html
  36. 22 21
      docs/api/zh/extras/curves/CubicBezierCurve.html
  37. 25 25
      docs/api/zh/extras/curves/CubicBezierCurve3.html
  38. 31 38
      docs/api/zh/extras/curves/EllipseCurve.html
  39. 15 14
      docs/api/zh/extras/curves/LineCurve.html
  40. 16 15
      docs/api/zh/extras/curves/LineCurve3.html
  41. 19 19
      docs/api/zh/extras/curves/QuadraticBezierCurve.html
  42. 19 19
      docs/api/zh/extras/curves/QuadraticBezierCurve3.html
  43. 13 14
      docs/api/zh/extras/curves/SplineCurve.html
  44. 2 2
      docs/api/zh/extras/objects/ImmediateRenderObject.html
  45. 1 1
      docs/api/zh/geometries/CircleBufferGeometry.html
  46. 1 1
      docs/api/zh/geometries/LatheBufferGeometry.html
  47. 7 7
      docs/api/zh/geometries/ParametricBufferGeometry.html
  48. 7 7
      docs/api/zh/geometries/ParametricGeometry.html
  49. 1 1
      docs/api/zh/geometries/PlaneBufferGeometry.html
  50. 1 1
      docs/api/zh/geometries/SphereGeometry.html
  51. 1 1
      docs/api/zh/geometries/TorusGeometry.html
  52. 1 1
      docs/api/zh/geometries/TorusKnotBufferGeometry.html
  53. 0 1
      docs/api/zh/loaders/ObjectLoader.html
  54. 0 11
      docs/api/zh/materials/Material.html
  55. 1 1
      docs/api/zh/math/Matrix4.html
  56. 1 1
      docs/api/zh/math/Quaternion.html
  57. 67 75
      docs/api/zh/math/Ray.html
  58. 39 43
      docs/api/zh/math/Sphere.html
  59. 38 41
      docs/api/zh/math/Triangle.html
  60. 1 1
      docs/api/zh/math/Vector2.html
  61. 41 23
      docs/api/zh/objects/SkinnedMesh.html
  62. 2 2
      docs/manual/en/introduction/Browser-support.html
  63. 3 2
      docs/manual/en/introduction/Loading-3D-models.html
  64. 4 4
      docs/manual/en/introduction/Useful-links.html
  65. 60 69
      docs/manual/zh/buildTools/Testing-with-NPM.html
  66. 49 53
      docs/manual/zh/introduction/Animation-system.html
  67. 3 3
      docs/manual/zh/introduction/Browser-support.html
  68. 1 1
      docs/manual/zh/introduction/Drawing-lines.html
  69. 5 6
      docs/manual/zh/introduction/FAQ.html
  70. 0 56
      docs/manual/zh/introduction/How-to-run-things-locally.html
  71. 33 34
      docs/manual/zh/introduction/How-to-update-things.html
  72. 53 13
      docs/manual/zh/introduction/Loading-3D-models.html
  73. 14 14
      docs/manual/zh/introduction/Matrix-transformations.html
  74. 5 5
      docs/manual/zh/introduction/Useful-links.html
  75. 1 1
      docs/manual/zh/introduction/WebGL-compatibility-check.html
  76. 34 25
      docs/scenes/bones-browser.html
  77. 1 1
      editor/js/Sidebar.Object.js
  78. 4 2
      examples/files.js
  79. 29 0
      examples/files/ldraw_org_logo/LDraw.org_logo_LICENSE.txt
  80. 二进制
      examples/files/ldraw_org_logo/Stamp145.png
  81. 0 2138
      examples/js/Octree.js
  82. 3 1
      examples/js/VolumeSlice.js
  83. 13 13
      examples/js/animation/MMDPhysics.js
  84. 3 2
      examples/js/controls/EditorControls.js
  85. 28 17
      examples/js/exporters/ColladaExporter.js
  86. 66 19
      examples/js/exporters/GLTFExporter.js
  87. 1005 0
      examples/js/geometries/LightningStrike.js
  88. 23 1
      examples/js/loaders/ColladaLoader.js
  89. 1 0
      examples/js/loaders/FBXLoader.js
  90. 30 13
      examples/js/loaders/GLTFLoader.js
  91. 18 24
      examples/js/loaders/KTXLoader.js
  92. 1340 0
      examples/js/loaders/LDrawLoader.js
  93. 16 1
      examples/js/loaders/MTLLoader.js
  94. 6 8
      examples/js/loaders/SVGLoader.js
  95. 46 2
      examples/js/loaders/XLoader.js
  96. 1 1
      examples/js/nodes/math/Math1Node.js
  97. 1 0
      examples/js/nodes/math/Math3Node.js
  98. 1069 0
      examples/js/objects/Fire.js
  99. 6 3
      examples/js/objects/Lensflare.js
  100. 240 0
      examples/js/objects/LightningStorm.js

文件差异内容过多而无法显示
+ 8 - 2
build/three.js


文件差异内容过多而无法显示
+ 218 - 218
build/three.min.js


文件差异内容过多而无法显示
+ 8 - 2
build/three.module.js


+ 0 - 1
docs/api/en/cameras/CubeCamera.html

@@ -17,7 +17,6 @@
 		<h2>Examples</h2>
 
 		<p>[example:webgl_materials_cubemap_dynamic materials / cubemap / dynamic ]</p>
-		<p>[example:webgl_materials_cubemap_dynamic2 materials / cubemap / dynamic2 ]</p>
 		<p>[example:webgl_shading_physical shading / physical ]</p>
 
 		<code>// Create cube camera

+ 0 - 3
docs/api/en/core/Geometry.html

@@ -32,7 +32,6 @@
 		<div>[example:webgl_interactive_lines WebGL / interactive / lines ]</div>
 		<div>[example:webgl_interactive_raycasting_points WebGL / interactive / raycasting / points ]</div>
 		<div>[example:webgl_interactive_voxelpainter WebGL / interactive / voxelpainter ]</div>
-		<div>[example:webgl_morphnormals WebGL / morphNormals ]</div>
 
 
 		<code>var geometry = new THREE.Geometry();
@@ -123,8 +122,6 @@
 		<p>
 		Array of morph normals. Morph normals have similar structure as morph targets, each normal set is a Javascript object:
 		<code>morphNormal = { name: "NormalName", normals: [ new THREE.Vector3(), ... ] }</code>
-
-		See the [example:webgl_morphnormals WebGL / morphNormals] example.
 		</p>
 
 		<h3>[property:String name]</h3>

+ 13 - 0
docs/api/en/core/Object3D.html

@@ -36,6 +36,19 @@
 		<h3>[property:Object3D children]</h3>
 		<p>Array with object's children. See [page:Group] for info on manually grouping objects.</p>
 
+		<h3>[property:Material customDepthMaterial]</h3>
+		<p>
+		Custom depth material to be used when rendering to the depth map. Can only be used in context of meshes.
+		When shadow-casting with a [page:DirectionalLight] or [page:SpotLight], if you are (a) modifying vertex positions in the vertex shader,
+		(b) using a displacement map, (c) using an alpha map with alphaTest, or (d) using a transparent texture with alphaTest,
+		you must specify a customDepthMaterial for proper shadows. Default is *undefined*.
+		</p>
+
+		<h3>[property:Material customDistanceMaterial]</h3>
+		<p>
+		Same as customDepthMaterial, but used with [page:PointLight]. Default is *undefined*.
+		</p>
+
 		<h3>[property:Boolean frustumCulled]</h3>
 		<p>
 		When this is set, it checks every frame if the object is in the frustum of the camera before rendering the object.

+ 0 - 1
docs/api/en/core/Raycaster.html

@@ -61,7 +61,6 @@
 			[example:webgl_interactive_lines Raycasting to a Line]<br />
 			[example:webgl_interactive_raycasting_points Raycasting to Points]<br />
 			[example:webgl_geometry_terrain_raycast Terrain raycasting]<br />
-			[example:webgl_octree_raycasting Raycasting using an octree]<br />
 			[example:webgl_interactive_voxelpainter Raycasting to paint voxels]<br />
 			[example:webgl_raycast_texture Raycast to a Texture]
 		</div>

+ 0 - 6
docs/api/en/extras/curves/EllipseCurve.html

@@ -88,12 +88,6 @@ var ellipse = new THREE.Line( geometry, material );
 		<h3>[property:Float aRotation]</h3>
 		<p>The rotation angle of the ellipse in radians, counterclockwise from the positive X axis (optional). Default is *0*.</p>
 
-		<h3>[property:Boolean isEllipseCurve]</h3>
-		<p>
-			Used to check whether this or derived classes are ellipses. Default is *true*.<br /><br />
-
-			You should not change this, as it used internally for optimisation.
-		</p>
 
 		<h2>Methods</h2>
 		<p>See the base [page:Curve] class for common methods.</p>

+ 15 - 13
docs/api/en/geometries/BoxBufferGeometry.html

@@ -44,29 +44,31 @@
 
 		<h3>[name]([param:Float width], [param:Float height], [param:Float depth], [param:Integer widthSegments], [param:Integer heightSegments], [param:Integer depthSegments])</h3>
 		<p>
-		width — Width of the sides on the X axis. Default is 1.<br />
-		height — Height of the sides on the Y axis. Default is 1.<br />
-		depth — Depth of the sides on the Z axis. Default is 1.<br />
-		widthSegments — Optional. Number of segmented faces along the width of the sides. Default is 1.<br />
-		heightSegments — Optional. Number of segmented faces along the height of the sides. Default is 1.<br />
-		depthSegments — Optional. Number of segmented faces along the depth of the sides. Default is 1.
+		width — Width; that is, the length of the edges parallel to the X axis. Optional; defaults to 1.<br />
+		height — Height; that is, the length of the edges parallel to the Y axis. Optional; defaults to 1.<br />
+		depth — Depth; that is, the length of the edges parallel to the Z axis. Optional; defaults to 1.<br />
+		widthSegments — Number of segmented rectangular faces along the width of the sides. Optional; defaults to 1.<br />
+		heightSegments — Number of segmented rectangular faces along the height of the sides. Optional; defaults to 1.<br />
+		depthSegments — Number of segmented rectangular faces along the depth of the sides. Optional; defaults to 1.<br />
 		</p>
 
 		<h2>Properties</h2>
-
+	
 		<h3>[property:Object parameters]</h3>
 		<p>
 		An object with a property for each of the constructor parameters. Any modification after instantiation does not change the geometry.
 		</p>
  		<p>
-			Using the above example code above as our basis:
-			<code>
-		geometry.parameters; // outputs an object {width: 1, height: 1, depth: 1, widthSegments: undefined, heightSegments: undefined}
+		Using the above example:
+		<code>
+		geometry.parameters; // {width: 1, height: 1, depth: 1, widthSegments: undefined, heightSegments: undefined, depthSegments: undefined}
 		cube.geometry.parameters; // as above
 		cube.geometry.parameters.width; // === 1
-		cube.geometry.parameters.widthSegments // === undefined.
-			</code>
- 		</p>
+		cube.geometry.parameters.widthSegments; // === undefined.
+		</code>
+		</p>
+		
+		<h2>Methods</h2>	
 
 		<h2>Source</h2>
 

+ 15 - 15
docs/api/en/geometries/BoxGeometry.html

@@ -12,8 +12,8 @@
 
 		<h1>[name]</h1>
 
-		<p class="desc">BoxGeometry is the quadrilateral primitive geometry class. It is typically used for creating a cube or irregular quadrilateral of the dimensions provided with the 'width', 'height', and 'depth' constructor arguments.</p>
-
+		<p class="desc">BoxGeometry is a geometry class for a [link:https://en.wikipedia.org/wiki/Cuboid rectangular cuboid] with a given 'width', 'height', and 'depth'. On creation, the cuboid is centred on the origin, with each edge parallel to one of the axes.</p>
+		
 		<iframe id="scene" src="scenes/geometry-browser.html#BoxGeometry"></iframe>
 
 		<script>
@@ -44,12 +44,12 @@
 
 		<h3>[name]([param:Float width], [param:Float height], [param:Float depth], [param:Integer widthSegments], [param:Integer heightSegments], [param:Integer depthSegments])</h3>
 		<p>
-		width — Width of the sides on the X axis. Default is 1.<br />
-		height — Height of the sides on the Y axis. Default is 1.<br />
-		depth — Depth of the sides on the Z axis. Default is 1.<br />
-		widthSegments — Optional. Number of segmented faces along the width of the sides. Default is 1.<br />
-		heightSegments — Optional. Number of segmented faces along the height of the sides. Default is 1.<br />
-		depthSegments — Optional. Number of segmented faces along the depth of the sides. Default is 1.
+		width — Width; that is, the length of the edges parallel to the X axis. Optional; defaults to 1.<br />
+		height — Height; that is, the length of the edges parallel to the Y axis. Optional; defaults to 1.<br />
+		depth — Depth; that is, the length of the edges parallel to the Z axis. Optional; defaults to 1.<br />
+		widthSegments — Number of segmented rectangular faces along the width of the sides. Optional; defaults to 1.<br />
+		heightSegments — Number of segmented rectangular faces along the height of the sides. Optional; defaults to 1.<br />
+		depthSegments — Number of segmented rectangular faces along the depth of the sides. Optional; defaults to 1.<br />
 		</p>
 
 		<h2>Properties</h2>
@@ -59,13 +59,13 @@
 		An object with a property for each of the constructor parameters. Any modification after instantiation does not change the geometry.
 		</p>
  		<p>
-			Using the above example code above as our basis:
-			<code>
-				geometry.parameters; // outputs an object {width: 1, height: 1, depth: 1, widthSegments: undefined, heightSegments: undefined}
-				cube.geometry.parameters; // as above
-				cube.geometry.parameters.width; // === 1
-				cube.geometry.parameters.widthSegments // === undefined.
-			</code>
+		Using the above example:
+		<code>
+		geometry.parameters; // {width: 1, height: 1, depth: 1, widthSegments: undefined, heightSegments: undefined, depthSegments: undefined}
+		cube.geometry.parameters; // as above
+		cube.geometry.parameters.width; // === 1
+		cube.geometry.parameters.widthSegments; // === undefined.
+		</code>
  		</p>
 
 		<h2>Source</h2>

+ 0 - 1
docs/api/en/helpers/AxesHelper.html

@@ -19,7 +19,6 @@
 		<h2>Example</h2>
 
 		<div>[example:webgl_geometries WebGL / geometries]</div>
-		<div>[example:webgl_geometries2 WebGL / geometries2]</div>
 		<div>[example:webgl_geometry_convex WebGL / geometry / convex]</div>
 		<div>[example:webgl_geometry_spline_editor WebGL / geometry / spline / editor]</div>
 

+ 1 - 1
docs/api/en/helpers/RectAreaLightHelper.html

@@ -23,7 +23,7 @@ var light = new THREE.RectAreaLight( 0xffffbb, 1.0, 5, 5 );
 
 var helper = new THREE.RectAreaLightHelper( light );
 
-scene.add( helper );
+light.add( helper ); // helper must be added as a child of the light
 		</code>
 
 

+ 1 - 1
docs/api/en/lights/RectAreaLight.html

@@ -41,7 +41,7 @@ rectLight.lookAt( 0, 0, 0 );
 scene.add( rectLight )
 
 rectLightHelper = new THREE.RectAreaLightHelper( rectLight );
-scene.add( rectLightHelper );
+rectLight.add( rectLightHelper );
 
 			</code>
 		</p>

+ 0 - 1
docs/api/en/loaders/CubeTextureLoader.html

@@ -22,7 +22,6 @@
 			[example:webgl_materials_cubemap_balls_reflection materials / cubemap / balls / reflection]<br />
 			[example:webgl_materials_cubemap_balls_refraction materials / cubemap / balls / refraction]<br />
 			[example:webgl_materials_cubemap_dynamic materials / cubemap / dynamic]<br />
-			[example:webgl_materials_cubemap_dynamic2 materials / cubemap / dynamic2]<br />
 			[example:webgl_materials_cubemap_refraction materials / cubemap / refraction]
 		</p>
 

+ 0 - 4
docs/api/en/loaders/FileLoader.html

@@ -17,10 +17,6 @@
 		</p>
 
 		<h2>Example</h2>
-		<p>
-			[example:webgl_loader_msgpack WebGL / loader / msgpack]<br />
-			[example:webgl_morphtargets_human WebGL / morphtargets / human]<br />
-		</p>
 		<code>
 		var loader = new THREE.FileLoader();
 

+ 0 - 1
docs/api/en/loaders/ObjectLoader.html

@@ -19,7 +19,6 @@
 		<h2>Example</h2>
 
 		<p>
-			[example:webgl_animation_skinning_blending WebGL / animation / skinning / blending]<br />
 			[example:webgl_loader_json_claraio WebGL / loader / json / claraio]<br />
 			[example:webgl_materials_lightmap WebGL / materials / lightmap]
 		</p>

+ 0 - 1
docs/api/en/materials/LineBasicMaterial.html

@@ -29,7 +29,6 @@
 			[example:webgl_lines_colors WebGL / lines / colors]<br />
 			[example:webgl_lines_dashed WebGL / lines / dashed]<br />
 			[example:webgl_lines_sphere WebGL / lines / sphere]<br />
-			[example:webgl_lines_splines WebGL / lines / splines]<br />
 			[example:webgl_materials WebGL / materials]<br />
 			[example:webgl_physics_rope WebGL / phyics / rope]
 		</p>

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

@@ -101,19 +101,6 @@
 		This can be used in conjunction with a mesh's [page:Integer renderOrder] property to create invisible objects that occlude other objects. Default is *true*.
 		</p>
 
-		<h3>[property:Material customDepthMaterial]</h3>
-		<p>
-		Custom depth material to be used by this material when rendering to the depth map.
-		When shadow-casting with a [page:DirectionalLight] or [page:SpotLight], if you are (a) modifying vertex positions in the vertex shader,
-		(b) using a displacement map, (c) using an alpha map with alphaTest, or (d) using a transparent texture with alphaTest,
-		you must specify a customDepthMaterial for proper shadows. Default is *undefined*.
-		</p>
-
-		<h3>[property:Material customDistanceMaterial]</h3>
-		<p>
-		Same as customDepthMaterial, but used with [page:PointLight]. Default is *undefined*.
-		</p>
-
 		<h3>[property:Object defines]</h3>
 		<p>
 		Custom defines to be injected into the shader. These are passed in form of an object literal, with key/value pairs. { MY_CUSTOM_DEFINE: '' , PI2: Math.PI * 2 }. The pairs are defined in both vertex and fragment shaders.  Default is *undefined*.

+ 0 - 2
docs/api/en/materials/PointsMaterial.html

@@ -26,9 +26,7 @@
 			[example:webgl_interactive_raycasting_points WebGL / interactive / raycasting / points]<br />
 			[example:webgl_multiple_elements_text WebGL / multiple / elements / text]<br />
 			[example:webgl_points_billboards WebGL / points / billboards]<br />
-			[example:webgl_points_billboards_colors WebGL / points / billboards / colors]<br />
 			[example:webgl_points_dynamic WebGL / points / dynamic]<br />
-			[example:webgl_points_random WebGL / points / random]<br />
 			[example:webgl_points_sprites WebGL / points / sprites]<br />
 			[example:webgl_trails WebGL / trails]
 		</p>

+ 0 - 1
docs/api/en/materials/ShaderMaterial.html

@@ -96,7 +96,6 @@
 			[example:webgl_materials_parallaxmap webgl / materials / parallaxmap]<br />
 			[example:webgl_materials_shaders_fresnel webgl / materials / shaders / fresnel]<br />
 			[example:webgl_materials_skin webgl / materials / skin]<br />
-			[example:webgl_materials_texture_hdr webgl / materials / texture / hdr]<br />
 			[example:webgl_materials_wireframe webgl / materials / wireframe]<br />
 			[example:webgl_modifier_tessellation webgl / modifier / tessellation]<br />
 			[example:webgl_nearestneighbour webgl / nearestneighbour]<br />

+ 42 - 26
docs/api/en/objects/SkinnedMesh.html

@@ -38,41 +38,60 @@
 		<h2>Example</h2>
 
 		<code>
-		var geometry = new THREE.CylinderGeometry( 5, 5, 5, 5, 15, 5, 30 );
+		var geometry = new THREE.CylinderBufferGeometry( 5, 5, 5, 5, 15, 5, 30 );
 
-		//Create the skin indices and skin weights
-		for ( var i = 0; i < geometry.vertices.length; i ++ ) {
+		// create the skin indices and skin weights
 
-			// Imaginary functions to calculate the indices and weights
-			// This part will need to be changed depending your skeleton and model
-			var skinIndex = calculateSkinIndex( geometry.vertices, i );
-			var skinWeight = calculateSkinWeight( geometry.vertices, i );
+		var position = geometry.attributes.position;
 
-			// Ease between each bone
-			geometry.skinIndices.push( new THREE.Vector4( skinIndex, skinIndex + 1, 0, 0 ) );
-			geometry.skinWeights.push( new THREE.Vector4( 1 - skinWeight, skinWeight, 0, 0 ) );
+		var vertex = new THREE.Vector3();
+
+		var skinIndices = [];
+		var skinWeights = [];
+
+		for ( var i = 0; i < position.count; i ++ ) {
+
+			vertex.fromBufferAttribute( position, i );
+
+			// compute skinIndex and skinWeight based on some configuration data
+
+			var y = ( vertex.y + sizing.halfHeight );
+
+			var skinIndex = Math.floor( y / sizing.segmentHeight );
+			var skinWeight = ( y % sizing.segmentHeight ) / sizing.segmentHeight;
+
+			skinIndices.push( skinIndex, skinIndex + 1, 0, 0 );
+			skinWeights.push( 1 - skinWeight, skinWeight, 0, 0 );
 
 		}
 
+		geometry.addAttribute( 'skinIndex', new THREE.Uint16BufferAttribute( skinIndices, 4 ) );
+		geometry.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( skinWeights, 4 ) );
+
+		// create skinned mesh and skeleton
+
 		var mesh = new THREE.SkinnedMesh( geometry, material );
+		var skeleton = new THREE.Skeleton( bones );
 
-		// See example from THREE.Skeleton for the armSkeleton
-		var rootBone = armSkeleton.bones[ 0 ];
+		// see example from THREE.Skeleton
+
+		var rootBone = skeleton.bones[ 0 ];
 		mesh.add( rootBone );
 
-		// Bind the skeleton to the mesh
-		mesh.bind( armSkeleton );
+		// bind the skeleton to the mesh
+
+		mesh.bind( skeleton );
+
+		// move the bones and manipulate the model
 
-		// Move the bones and manipulate the model
-		armSkeleton.bones[ 0 ].rotation.x = -0.1;
-		armSkeleton.bones[ 1 ].rotation.x = 0.2;
+		skeleton.bones[ 0 ].rotation.x = -0.1;
+		skeleton.bones[ 1 ].rotation.x = 0.2;
 		</code>
 
 		<h2>Constructor</h2>
-		<h3>[name]( [param:Geometry geometry], [param:Material material] )</h3>
+		<h3>[name]( [param:BufferGeometry geometry], [param:Material material] )</h3>
 		<p>
-    [page:Geometry geometry] - an instance of [page:Geometry] or [page:BufferGeometry] (recommended).
-		[page:Geometry.skinIndices skinIndices] and [page:Geometry.skinWeights skinWeights] should be set to true on the geometry.<br />
+    [page:Geometry geometry] - an instance of [page:BufferGeometry].<br />
     [page:Material material] - (optional) an instance of [page:Material]. Default is a new [page:MeshBasicMaterial].
 		</p>
 
@@ -109,8 +128,7 @@
 
 		<h3>[property:Skeleton skeleton]</h3>
 		<p>
-		[page:Skeleton] created from the [page:Geometry.bones bones] of the [page:Geometry] passed in the
-		constructor.
+		[page:Skeleton] representing the bone hierachy of the skinned mesh.
 		</p>
 
 
@@ -124,9 +142,7 @@
 		[page:Matrix4 bindMatrix] - [page:Matrix4] that represents the base transform of the skeleton.<br /><br />
 
 		Bind a skeleton to the skinned mesh. The bindMatrix gets saved to .bindMatrix property
-		and the .bindMatrixInverse gets calculated. This is called automatically in the constructor, and the skeleton
-		is created from the [page:Geometry.bones bones] of the [page:Geometry] passed in the
-		constructor.
+		and the .bindMatrixInverse gets calculated.
 		</p>
 
 		<h3>[method:SkinnedMesh clone]()</h3>
@@ -136,7 +152,7 @@
 
 		<h3>[method:null normalizeSkinWeights]()</h3>
 		<p>
-		Normalizes the [page:Geometry.skinWeights] vectors. Does not affect [page:BufferGeometry].
+		Normalizes the skin weights.
 		</p>
 
 		<h3>[method:null pose]()</h3>

+ 1 - 1
docs/api/en/renderers/WebGLRenderer.html

@@ -253,7 +253,7 @@
 
 		Note: Sorting is used to attempt to properly render objects that have some degree of transparency.
 		By definition, sorting objects may not work in all cases.  Depending on the needs of application,
-		it may be neccessary to turn off sorting and use other methods to deal with transparency
+		it may be necessary to turn off sorting and use other methods to deal with transparency
 		rendering e.g. manually determining each object's rendering order.
 		</p>
 

+ 13 - 2
docs/api/zh/core/Object3D.html

@@ -36,6 +36,17 @@
 	<h3>[property:Object3D children]</h3>
 	<p>含有对象的子级的数组。请参阅[page:Group]来了解将手动对象进行分组的相关信息。</p>
 
+	<h3>[property:Material customDepthMaterial]</h3>
+	<p>渲染到深度贴图时此材质要使用的自定义深度材质。
+	    当使用[page:DirectionalLight]或[page:SpotLight]进行阴影投射时,如果您正在(a)修改顶点着色器中的顶点位置,
+	    (b)使用位移贴图,(c)alphaTest中使用alpha贴图,或(d)alphaTest中使用透明纹理,
+	    您必须指定customDepthMaterial以得到合适的阴影。默认值*undefined*。
+	</p>
+
+	<h3>[property:Material customDistanceMaterial]</h3>
+	<p>与customDepthMaterial相同,但与[page:PointLight]一起使用。默认值为*undefined*。
+	</p>
+
 	<h3>[property:Boolean frustumCulled]</h3>
 	<p>
 		当这个属性被设置的时候,它将在渲染物体之前,检查每一帧的物体是否在摄像机的视锥体中。
@@ -334,7 +345,7 @@
 	<h3>[method:null setRotationFromMatrix]( [param:Matrix4 m] )</h3>
 	<p>
 		m -- 通过该矩阵中的旋转分量来旋转四元数。<br />
-			
+
 		调用[page:.quaternion]中的[page:Quaternion.setFromRotationMatrix setFromRotationMatrix]( [page:Matrix4 m])。
 		<br /><br />
 
@@ -411,4 +422,4 @@
 	[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 </body>
 
-</html>
+</html>

+ 1 - 2
docs/api/zh/core/Raycaster.html

@@ -59,7 +59,6 @@
 			[example:webgl_interactive_lines Raycasting to a Line]<br />
 			[example:webgl_interactive_raycasting_points Raycasting to Points]<br />
 			[example:webgl_geometry_terrain_raycast Terrain raycasting]<br />
-			[example:webgl_octree_raycasting Raycasting using an octree]<br />
 			[example:webgl_interactive_voxelpainter Raycasting to paint voxels]<br />
 			[example:webgl_raycast_texture Raycast to a Texture]
 		</div>
@@ -136,7 +135,7 @@
 		<h3>[method:null setFromCamera]( [param:Vector2 coords], [param:Camera camera] )</h3>
 		<p>
 		[page:Vector2 coords] —— 在标准化设备坐标中鼠标的二维坐标 —— X分量与Y分量应当在-1到1之间。<br />
-								
+
 		[page:Camera camera] —— 射线所来源的摄像机。
 		</p>
 		<p>

+ 4 - 4
docs/api/zh/core/bufferAttributeTypes/BufferAttributeTypes.html

@@ -31,14 +31,14 @@
 
 		<h2>构造函数</h2>
 
-		All of the above are called in the same way.
+		所有上述内容都以相同的方式调用。
 		<h3>TypedBufferAttribute( [param:Array array], [param:Integer itemSize], [param:Boolean normalized] )</h3>
 		<p>
-			array -- this can be a typed or untyped (normal) array. It will be converted to the Type specified.<br /><br />
+			array -- 这可以是类型化或非类型化的(普通)数组。它将被转换为指定的类型。<br /><br />
 
-			itemSize -- the number of values of the array that should be associated with a particular vertex.<br /><br />
+			itemSize -- 应与特定顶点关联的数组值的数量。<br /><br />
 
-			normalized -- (optional) indicates how the underlying data in the buffer maps to the values in the GLSL code.
+			normalized -- (可选)表示缓冲区中的基础数据如何映射到GLSL代码中的值。
 		</p>
 
 		<h2>属性</h2>

+ 6 - 6
docs/api/zh/extras/Earcut.html

@@ -11,20 +11,20 @@
 		<h1>[name]</h1>
 
 		<p class="desc">
-		An implementation of the earcut polygon triangulation algorithm. The code is a port of [link:https://github.com/mapbox/earcut mapbox/earcut].
+		切割多边形三角剖分算法的实现。这份代码是[link:https://github.com/mapbox/earcut mapbox/earcut]的一个端口。
 		</p>
 
-		<h2>Methods</h2>
+		<h2>方法</h2>
 
 		<h3>[method:Array triangulate]( data, holeIndices, dim )</h3>
 		<p>
-		data -- A flat array of vertice coordinates.<br /><br />
-		holeIndices -- An array of hole indices if any.<br /><br />
-		dim -- The number of coordinates per vertice in the input array.<br /><br />
+		data -- 一个顶点坐标的平面数组。<br /><br />
+		holeIndices -- 空洞索引的数组(如果有的话)。<br /><br />
+		dim -- 输入数组中每个顶点的坐标数。<br /><br />
 
 		</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 12 - 15
docs/api/zh/extras/ShapeUtils.html

@@ -11,43 +11,40 @@
 		<h1>[name]</h1>
 
 		<p class="desc">
-		A class containing utility functions for shapes.<br /><br />
+		一个包含形状实用函数的类。<br /><br />
 
-		Note that these are all linear functions so it is neccessary to calculate separately for
-		x, y (and z, w if present) components of a vector.
+		请注意,这些都是线性函数,因此有必要分别计算向量的x,y(和z,w,如果存在的话)分量。
 		</p>
 
 
-		<h2>Methods</h2>
+		<h2>方法</h2>
 
 		<h3>[method:Number area]( contour )</h3>
 		<p>
-		contour -- 2D polygon.<br /><br />
+		contour -- 2D多边形。<br /><br />
 
-		Calculate area of a ( 2D ) contour polygon.<br /><br />
+		计算(2D)轮廓多边形的面积。<br /><br />
 
 		</p>
 
 		<h3>[method:Boolean isClockwise]( pts )</h3>
 		<p>
-		pts -- points defining a 2D polygon<br /><br />
+		pts -- 定义2D多边形的点<br /><br />
 
-		Note that this is a linear function so it is neccessary to calculate separately for
-		x, y  components of a polygon.<br /><br />
+		请注意,这是一个线性函数,因此需要分别计算多边形的x,y分量。<br /><br />
 
-		Used internally by [page:Path Path],
-		[page:ExtrudeGeometry ExtrudeGeometry] and [page:ShapeGeometry ShapeGeometry].
+		由[page:Path Path],[page:ExtrudeGeometry ExtrudeGeometry]和[page:ShapeGeometry ShapeGeometry]内部使用。
 		</p>
 
 		<h3>[method:Array triangulateShape]( contour, holes )</h3>
 		<p>
-		contour -- 2D polygon.<br />
-		holes -- array of holes<br /><br />
+		contour -- 2D多边形。<br />
+		holes -- 空洞数组<br /><br />
 
-		Used internally by [page:ExtrudeGeometry ExtrudeGeometry] and [page:ShapeGeometry ShapeGeometry] to calculate faces in shapes with holes.
+		由[page:ExtrudeGeometry ExtrudeGeometry]和[page:ShapeGeometry ShapeGeometry]内部使用以计算带孔的形状中的面。
 		</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 15 - 15
docs/api/zh/extras/core/CurvePath.html

@@ -10,50 +10,50 @@
 	<body>
 		[page:Curve] &rarr;
 
-		<h1>[name]</h1>
+		<h1>曲线路径([name]</h1>
 
 		<p class="desc">
-		An abstract base class extending [page:Curve]. A CurvePath is simply an array of connected curves,
-		but retains the api of a curve.
+		
+		一个扩展了[page:Curve]的抽象基类。CurvePath仅仅是一个已连接的曲线的数组,但保留了曲线的API。
 		</p>
 
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]()</h3>
 		<p>
-		The constructor take no parameters.
+		构造函数中不传入参数。
 		</p>
 
 
-		<h2>Properties</h2>
-		<p>See the base [page:Curve] class for common properties.</p>
+		<h2>属性</h2>
+		<p>请参阅其基类[page:Curve]来了解共有属性。</p>
 
 		<h3>[property:array curves]</h3>
-		<p>The array of [page:Curve Curves].</p>
+		<p>[page:Curve Curves]数组。</p>
 
 		<h3>[property:boolean autoClose]</h3>
-		<p>Whether or not to automatically close the path.</p>
+		<p>是否自动闭合路径。</p>
 
 
 
 
 
-		<h2>Methods</h2>
-		<p>See the base [page:Curve] class for common methods.</p>
+		<h2>方法</h2>
+		<p>请参阅其基类[page:Curve]来了解共有方法。</p>
 
 		<h3>[method:null add]( [param:Curve curve] )</h3>
-		<p>Add a curve to the [page:.curves] array.</p>
+		<p>添加一条曲线到[page:.curves]数组中。</p>
 
 		<h3>[method:null closePath]()</h3>
-		<p>Adds a [page:LineCurve lineCurve] to close the path.</p>
+		<p>添加一条[page:LineCurve lineCurve]用于闭合路径。</p>
 
 		<h3>[method:Float getCurveLengths]()</h3>
-		<p>Adds together the lengths of the curves in the [page:.curves] array.</p>
+		<p>将[page:.curves]数组中曲线的长度相加。</p>
 
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 18 - 16
docs/api/zh/extras/core/Font.html

@@ -8,53 +8,55 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		<h1>[name]</h1>
+		<h1>字体([name]</h1>
 
 		<p class="desc">
-		Create a set of [page:Shape Shapes] representing a font loaded in JSON format.<br /><br />
+		以JSON格式,创建一系列的[page:Shape Shape](形状)来表示一个字体。
+		<br /><br />
 
-		This is used internally by the [page:FontLoader].
+		该类在内部由[page:FontLoader]所使用。
 		</p>
 
-		<h2>Examples</h2>
+		<h2>示例</h2>
 
 		<p>
 		[example:webgl_geometry_text_shapes geometry / text / shapes ]<br/>
 		[example:webgl_shaders_vector vector / text ]<br/>
 		</p>
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 		<h3>[name]( data )</h3>
 		<p>
-		data -- JSON data representing the font.<br /><br />
+		data -- 表示字体的JSON数据。<br /><br />
 
-		This constructor creates a new [name], which is an array of [page:Shape Shapes].
+		这一构造函数创建一个新的[name],它是一个[page:Shape Shapes]数组。
 		</p>
 
-		<h2>Properties</h2>
+		<h2>属性</h2>
 
 		<h3>[property:array data]</h3>
-		<p>The JSON data passed in the constructor.</p>
+		<p>传入到构造函数的JSON数据。</p>
 
 		<h3>[property:Boolean isFont]</h3>
 		<p>
-			Used to check whether this or derived classes are fonts. Default is *true*.<br /><br />
+			用于检查该类或者其派生类是否为字体。默认值为*true*。
+			<br /><br />
 
-			You should not change this, as it used internally by the renderer for optimisation.
+			你不应当对这一属性进行改变,它在内部由渲染器所使用,以用于优化。
 		</p>
 
-		<h2>Methods</h2>
+		<h2>方法</h2>
 
 		<h3>[method:null generateShapes]( [param:String text], [param:Float size] )</h3>
 		<p>
-			[page:String text] -- string of text.<br />
-			[page:Float size] -- (optional) scale for the [page:Shape Shapes]. Default is *100*.<br />
+			[page:String text] -- 文本字符串。<br />
+			[page:Float size] -- (可选)[page:Shape Shapes]的缩放,默认值为*100*。<br />
 
-			Creates an array of [page:Shape Shapes] representing the text in the font.
+			创建一个[page:Shape Shapes]数组,表示使用字体的文本。
 		</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 12 - 12
docs/api/zh/extras/core/Interpolations.html

@@ -8,39 +8,39 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		<h1>[name]</h1>
+		<h1>插值([name]</h1>
 
 		<p class="desc">
 		TODO
 		</p>
 
-		<h2>Methods</h2>
+		<h2>方法</h2>
 
 		<h3>[method:Float CatmullRom]( [param:Float t], [param:Float p0], [param:Float p1], [param:Float p2], [param:Float p3] )</h3>
 		<p>
-		t -- interpolation weight.<br />
-		p0, p1, p2, p3 -- the points defining the spline curve.<br /><br />
+		t -- 插值权重<br />
+		p0, p1, p2, p3 -- 定义了样条曲线的点。<br /><br />
 
-		Used internally by [page:SplineCurve SplineCurve].
+		在内部由[page:SplineCurve SplineCurve]所使用。
 		</p>
 
 		<h3>[method:Float QuadraticBezier]( [param:Float t], [param:Float p0], [param:Float p1], [param:Float p2] )</h3>
 		<p>
-		t -- interpolation weight.<br />
-		p0, p1, p2 -- the starting, control and end points defining the curve.<br /><br />
+		t -- 插值权重<br />
+		p0, p1, p2 -- 定义了该曲线的起始点、控制点和终止点。<br /><br />
 
-		Used internally by [page:QuadraticBezierCurve3 QuadraticBezierCurve3], [page:QuadraticBezierCurve QuadraticBezierCurve] and [page:Font Font].
+		在内部由[page:QuadraticBezierCurve3 QuadraticBezierCurve3]、[page:QuadraticBezierCurve QuadraticBezierCurve]和[page:Font Font]所使用。
 		</p>
 
 		<h3>[method:Float CubicBezier]( [param:Float t], [param:Float p0], [param:Float p1], [param:Float p2], [param:Float p3] )</h3>
 		<p>
-		t -- interpolation weight.<br />
-		p0, p1, p2, p3 -- the starting, control(twice) and end points defining the curve.<br /><br />
+		t -- 插值权重<br />
+		p0, p1, p2, p3 -- 定义了该曲线的起始点、两个控制点和终止点。<br /><br />
 
-		Used internally by [page:CubicBezierCurve3 CubicBezierCurve3], [page:CubicBezierCurve CubicBezierCurve] and [page:Font Font].
+		在内部由[page:CubicBezierCurve3 CubicBezierCurve3]、[page:CubicBezierCurve CubicBezierCurve]和[page:Font Font]所使用。
 		</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 52 - 54
docs/api/zh/extras/core/Path.html

@@ -10,13 +10,13 @@
 	<body>
 		[page:CurvePath] &rarr;
 
-		<h1>[name]</h1>
+		<h1>路径([name]</h1>
 
 		<p class="desc">
-		A 2D path representation. The class provides methods for creating paths and contours of 2D shapes similar to the 2D Canvas API.
+		该类定义了二维路径,提供了一些类似2D Canvas API的方法来创建或者构造二维路径。
 		</p>
 
-		<h2>Example</h2>
+		<h2>示例</h2>
 
 		<code>
 			var path = new THREE.Path();
@@ -35,110 +35,108 @@
 		</code>
 
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]( [param:Array points] )</h3>
 		<p>
-		points -- (optional) array of [page:Vector2 Vector2s].<br /><br />
+		points -- (可选)[page:Vector2 Vector2s]数组。<br /><br />
 
-		Creates a Path from the points. The first point defines the offset, then successive points
-		are added to the [page:CurvePath.curves curves] array as [page:LineCurve LineCurves].<br /><br />
+		从传入的点中创建一条Path。第一个点定义了偏移量,
+		接下来的点作为[page:LineCurve LineCurves]被添加到[page:CurvePath.curves curves]数组中。<br /><br />
 
-		If no points are specified, an empty path is created and the [page:.currentPoint] is set to
-		the origin.
+		倘若没有点被指定,一条空路径将会被创建,[page:.currentPoint]将被设置为原点。
 		</p>
 
 
-		<h2>Properties</h2>
-		<p>See the base [page:CurvePath] class for common properties.</p>
+		<h2>属性</h2>
+		<p>请参阅其基类[page:CurvePath]来了解共有属性。</p>
 
 		<h3>[property:array currentPoint]</h3>
-		<p>The current offset of the path. Any new [page:Curve] added will start here.</p>
+		<p>路径当前的偏移量,任何新被加入的[page:Curve]将会从这里开始。</p>
 
 
-		<h2>Methods</h2>
-		<p>See the base [page:CurvePath] class for common methods.</p>
+		<h2>方法</h2>
+		<p>请参阅其基类[page:CurvePath]来了解共有方法。</p>
 
 		<h3>[method:null absarc]( [param:Float x], [param:Float y], [param:Float radius], [param:Float startAngle], [param:Float endAngle], [param:Float clockwise] )</h3>
 		<p>
-			x, y -- The absolute center of the arc.<br />
-			radius -- The radius of the arc.<br />
-			startAngle -- The start angle in radians.<br />
-			endAngle -- The end angle in radians.<br />
-			clockwise -- Sweep the arc clockwise. Defaults to *false*.<br /><br />
+			x, y -- 弧线的绝对中心。<br />
+			radius -- 弧线的半径。<br />
+			startAngle -- 起始角,以弧度来表示。<br />
+			endAngle -- 终止角,以弧度来表示。<br />
+			clockwise -- 以顺时针方向创建(扫过)弧线。默认值为*false*。<br /><br />
 
-			Adds an absolutely positioned [page:EllipseCurve EllipseCurve] to the path.
+			添加一条绝对定位的[page:EllipseCurve EllipseCurve]到路径中。
 		</p>
 
 		<h3>[method:null absellipse]( [param:Float x], [param:Float y], [param:Float xRadius], [param:Float yRadius], [param:Float startAngle], [param:Float endAngle], [param:Float clockwise], [param:Float rotation] )</h3>
 		<p>
-			x, y -- The absolute center of the ellipse.<br />
-			xRadius -- The radius of the ellipse in the x axis.<br />
-			yRadius -- The radius of the ellipse in the y axis.<br />
-			startAngle -- The start angle in radians.<br />
-			endAngle -- The end angle in radians.<br />
-			clockwise -- Sweep the ellipse clockwise. Defaults to false.<br />
-			rotation -- The rotation angle of the ellipse in radians, counterclockwise from the positive X axis. Optional, defaults to 0.<br /><br />
-
-			Adds an absolutely positioned [page:EllipseCurve EllipseCurve] to the path.
+			x, y -- 椭圆的绝对中心。<br />
+			xRadius -- 椭圆x轴方向的半径。<br />
+			yRadius -- 椭圆y轴方向的半径。<br />
+			startAngle -- 起始角,以弧度来表示。<br />
+			endAngle -- 终止角,以弧度来表示。<br />
+			clockwise -- 以顺时针方向创建(扫过)椭圆。默认值为*false*。<br />
+			rotation -- 椭圆从X轴正方向逆时针的旋转角度(可选),以弧度表示,默认值为*0*。<br /><br />
+
+			添加一条绝对定位的[page:EllipseCurve EllipseCurve]到路径中。
 		</p>
 
 		<h3>[method:null arc]( [param:Float x], [param:Float y], [param:Float radius], [param:Float startAngle], [param:Float endAngle], [param:Float clockwise] )</h3>
 		<p>
-		x, y -- The center of the arc offset from the last call.<br />
-		radius -- The radius of the arc.<br />
-		startAngle -- The start angle in radians.<br />
-		endAngle -- The end angle in radians.<br />
-		clockwise -- Sweep the arc clockwise. Defaults to *false*.<br /><br />
+			x, y -- 弧线的中心来自上次调用后的偏移量。<br />
+			radius -- 弧线的半径。<br />
+			startAngle -- 起始角,以弧度来表示。<br />
+			endAngle -- 终止角,以弧度来表示。<br />
+			clockwise -- 以顺时针方向创建(扫过)弧线。默认值为*false*。<br /><br />
 
-		Adds an [page:EllipseCurve EllipseCurve] to the path, positioned relative to [page:.currentPoint].
+		添加一条[page:EllipseCurve EllipseCurve]到路径中,位置相对于[page:.currentPoint]。
 		</p>
 
 
 		<h3>[method:null bezierCurveTo]( [param:Float cp1X], [param:Float cp1Y], [param:Float cp2X], [param:Float cp2Y], [param:Float x], [param:Float y] )</h3>
-		<p>This creates a bezier curve from [page:.currentPoint] with (cp1X, cp1Y) and (cp2X, cp2Y) as control points and updates [page:.currentPoint] to x and y.</p>
+		<p>从[page:.currentPoint]创建一条贝塞尔曲线,以(cp1X, cp1Y)和(cp2X, cp2Y)作为控制点,并将[page:.currentPoint]更新到x,y。</p>
 
 		<h3>[method:null ellipse]( [param:Float x], [param:Float y], [param:Float xRadius], [param:Float yRadius], [param:Float startAngle], [param:Float endAngle], [param:Float clockwise], [param:Float rotation] )</h3>
 		<p>
-			x, y -- The center of the ellipse offset from the last call.<br />
-			xRadius -- The radius of the ellipse in the x axis.<br />
-			yRadius -- The radius of the ellipse in the y axis.<br />
-			startAngle -- The start angle in radians.<br />
-			endAngle -- The end angle in radians.<br />
-			clockwise -- Sweep the ellipse clockwise. Defaults to *false*.<br />
-			rotation -- The rotation angle of the ellipse in radians, counterclockwise from the positive X axis. Optional, defaults to *0*.<br /><br />
-
-			Adds an [page:EllipseCurve EllipseCurve] to the path, positioned relative to [page:.currentPoint].
+			x, y -- 椭圆的中心来自上次调用后的偏移量。The center of the ellipse offset from the last call.<br />
+			xRadius -- 椭圆x轴方向的半径。<br />
+			yRadius -- 椭圆y轴方向的半径。<br />
+			startAngle -- 起始角,以弧度来表示。<br />
+			endAngle -- 终止角,以弧度来表示。<br />
+			clockwise -- 以顺时针方向创建(扫过)椭圆。默认值为*false*。<br />
+			rotation -- 椭圆从X轴正方向逆时针的旋转角度(可选),以弧度表示,默认值为*0*。<br /><br />
+
+			添加一条[page:EllipseCurve EllipseCurve]到路径中,位置相对于[page:.currentPoint]。
 		</p>
 
 		<h3>[method:null lineTo]( [param:Float x], [param:Float y] )</h3>
-		<p>Connects a [page:LineCurve] from [page:.currentPoint] to x, y onto the path.</p>
+		<p>在当前路径上,从[page:.currentPoint]连接一条直线到x,y。</p>
 
 
 		<h3>[method:null moveTo]( [param:Float x], [param:Float y] )</h3>
-		<p>Move the [page:.currentPoint] to x, y.</p>
+		<p>将[page:.currentPoint]移动到x, y。</p>
 
 
 		<h3>[method:null quadraticCurveTo]( [param:Float cpX], [param:Float cpY], [param:Float x], [param:Float y] )</h3>
-		<p>Creates a quadratic curve from [page:.currentPoint] with cpX and cpY as control point and updates [page:.currentPoint] to x and y.</p>
+		<p>从[page:.currentPoint]创建一条二次曲线,以(cpX,cpY)作为控制点,并将[page:.currentPoint]更新到x,y。</p>
 
 		<h3>[method:null setFromPoints]( [param:Array vector2s] )</h3>
 		<p>
-			points --  array of [page:Vector2 Vector2s].<br /><br />
+			points -- [page:Vector2 Vector2]数组。<br /><br />
 
-			Points are added to the [page:CurvePath.curves curves]
-			array as [page:LineCurve LineCurves].
+			点将被作为[page:LineCurve LineCurves]加入到[page:CurvePath.curves curves]数组中。
 		</p>
 
 		<h3>[method:null splineThru] ( [param:Array points] ) </h3>
 		<p>
-			points - An array of [page:Vector2 Vector2s]<br /><br />
+			points -[page:Vector2 Vector2]数组。<br /><br />
 
-			Connects a new [page:SplineCurve] onto the path.
+			连接一条新的[page:SplineCurve]到路径上。
 		</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 21 - 22
docs/api/zh/extras/core/Shape.html

@@ -10,11 +10,11 @@
 	<body>
 		[page:Path] &rarr;
 
-		<h1>[name]</h1>
+		<h1>形状([name]</h1>
 
 		<p class="desc">
-		Defines an arbitrary 2d shape plane using paths with optional holes. It can be used with [page:ExtrudeGeometry],
-		[page:ShapeGeometry], to get points, or to get triangulated faces.
+		使用路径以及可选的孔洞来定义一个二维形状平面。
+		它可以和[page:ExtrudeGeometry]、[page:ShapeGeometry]一起使用,获取点,或者获取三角面。
 		</p>
 
 		<code>
@@ -35,7 +35,7 @@
 		var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial() );
 		</code>
 
-		<h2>Examples</h2>
+		<h2>示例</h2>
 
 		<p>
 		[example:webgl_geometry_shapes geometry / shapes ]<br/>
@@ -44,57 +44,56 @@
 		</p>
 
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]( [param:Array points] )</h3>
 		<p>
-		points -- (optional) array of [page:Vector2 Vector2s].<br /><br />
+		points -- (optional) 一个[page:Vector2 Vector2]数组。<br /><br />
 
-		Creates a Shape from the points. The first point defines the offset, then successive points
-		are added to the [page:CurvePath.curves curves] array as [page:LineCurve LineCurves].<br /><br />
+		从点来创建一个Shape。第一个点定义了偏移量,
+		接下来的点被作为[page:LineCurve LineCurves]加入到[page:CurvePath.curves curves]中。<br /><br />
 
-		If no points are specified, an empty shape is created and the [page:.currentPoint] is set to
-		the origin.
+		如果没有点被指定,一个空的形状将会被创建,且[page:.currentPoint]将会被设为原点。
 		</p>
 
 
-		<h2>Properties</h2>
-		<p>See the base [page:Path] class for common properties.</p>
+		<h2>属性</h2>
+		<p>请参阅其基类[page:Path]来了解共有属性。</p>
 
 		<h3>[property:String uuid]</h3>
 		<p>
-		[link:http://en.wikipedia.org/wiki/Universally_unique_identifier UUID] of this instance. This gets automatically assigned, so this shouldn't be edited.
+		该类所创建的实例的[link:http://en.wikipedia.org/wiki/Universally_unique_identifier UUID]。它是自动被指定的,因此它不应当被编辑、更改。
 		</p>
 
 		<h3>[property:array holes]</h3>
-		<p>An array of [page:Path paths] that define the holes in the shape.</p>
+		<p>一个[page:Path paths]数组,定义了形状上的孔洞。</p>
 
-		<h2>Methods</h2>
-		<p>See the base [page:Path] class for common methods.</p>
+		<h2>方法</h2>
+		<p>请参阅其基类[page:Path]来了解共有方法。</p>
 
 		<h3>[method:Array extractPoints]( [param:Integer divisions] )</h3>
 		<p>
-		divisions -- The fineness of the result.<br /><br />
+		divisions -- 结果的精细程度(细分数)。<br /><br />
 
-		Call [page:Curve.getPoints getPoints] on the shape and the [page:.holes] array, and return an object of the form:
+		在形状以及[page:.holes](孔洞)数组上调用[page:Curve.getPoints getPoints],并返回一个来自于:
 		<code>
 {
 	shape
 	holes
 }
 		</code>
-		where shape and holes are arrays of [page:Vector2 Vector2s].
+		的对象,其中的形状和孔洞是[page:Vector2 Vector2]数组。
 		</p>
 
 		<h3>[method:Array getPointsHoles]( [param:Integer divisions] )</h3>
 		<p>
-		divisions -- The fineness of the result.<br /><br />
+		divisions -- 结果的精细程度(细分数)。<br /><br />
 
-		Get an array of [page:Vector2 Vector2s] that represent the holes in the shape.
+		获取一个表示形状上的孔洞的[page:Vector2 Vector2s]数组。
 		</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 28 - 29
docs/api/zh/extras/core/ShapePath.html

@@ -10,81 +10,80 @@
 	<body>
 		[page:CurvePath] &rarr;
 
-		<h1>[name]</h1>
+		<h1>形状路径([name]</h1>
 
 		<p class="desc">
-		This class is used to convert a series of shapes to an array of [page:Path]s, for example an SVG shape to a
-		path (see the example below). It is used internally by [page:Font] to convert a font in JSON format to a
-		series of paths.
+		该类用于转换一系列的形状为一个[page:Path]数组,例如转换SVG中的Path为three.js中的Path(请参阅下方的example)。
+		在内部它由[page:Font]所使用,用于将JSON字体转换为一系列路径。
 		</p>
 
-		<h2>Example</h2>
+		<h2>示例</h2>
 
 		[example:webgl_geometry_extrude_shapes2 geometry / extrude / shapes2]
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name](  )</h3>
 		<p>
-		Creates a new ShapePath. Unlike a [page:Path], no points are passed in as the ShapePath is designed to
-		be generated after creation.
+		创建一个新的ShapePath。和[page:Path]不同,因为ShapePath被设计为在创建之后生成,所以没有点被传入到构造函数中。
 		</p>
 
 
-		<h2>Properties</h2>
+		<h2>属性</h2>
 
 		<h3>[property:array subPaths]</h3>
 		<p>
-		Array of [page:Path]s.
+		[page:Path]数组。
 		</p>
 
 		<h3>[property:array currentPath]</h3>
 		<p>
-		The current [page:Path] that is being generated.
+		当前将要被生成的路径。
 		</p>
 
-		<h2>Methods</h2>
+		<h2>方法</h2>
 
 		<h3>[method:null moveTo]( [param:Float x], [param:Float y] )</h3>
 		<p>
-		Starts a new [page:Path] and calls [page:Path.moveTo]( x, y ) on that [page:Path].
-		Also points [page:ShapePath.currentPath currentPath] to that [page:Path].
+		创建一个新的[page:Path],并在[page:Path]上调用[page:Path.moveTo]( x, y )。
 		</p>
 
 		<h3>[method:null lineTo]( [param:Float x], [param:Float y] )</h3>
-		<p>This creates a line from the [page:ShapePath.currentPath currentPath]'s
-			offset to X and Y and updates the offset to X and Y.</p>
+		<p>这一方法从[page:ShapePath.currentPath currentPath](当前路径)的偏移量创建一条到X和Y的线,并将偏移量更新为X和Y。
+		</p>
 
 		<h3>[method:null quadraticCurveTo]( [param:Float cpX], [param:Float cpY], [param:Float x], [param:Float y] )</h3>
-		<p>This creates a quadratic curve from the [page:ShapePath.currentPath currentPath]'s
-			offset to x and y with cpX and cpY as control point and updates the [page:ShapePath.currentPath currentPath]'s
-			offset to x and y.</p>
+		<p>这一方法从[page:ShapePath.currentPath currentPath](当前路径)创建一条到X和Y的二次曲线,cpX和cpY作为控制点,
+			并将[page:ShapePath.currentPath currentPath]的偏移量更新为x和y。
+		</p>
 
 		<h3>[method:null bezierCurveTo]( [param:Float cp1X], [param:Float cp1Y], [param:Float cp2X], [param:Float cp2Y], [param:Float x], [param:Float y] )</h3>
-		<p>This creates a bezier curve from the [page:ShapePath.currentPath currentPath]'s
-			 offset to x and y with cp1X, cp1Y and cp1X, cp1Y as control points and updates the
-			 [page:ShapePath.currentPath currentPath]'s offset to x and y.</p>
+		<p>
+			这一方法从[page:ShapePath.currentPath currentPath](当前路径)的偏移量创建一条到X和Y的贝塞尔曲线,
+			cp1X、cp1Y和cp1X、cp1Y为控制点,并将[page:ShapePath.currentPath currentPath]的偏移量更新为x和y。
+		</p>
 
 		<h3>[method:null splineThru] ( [param:Array points] ) </h3>
-		<p>points - An array of [page:Vector2]s</p>
-		<p>Connects a new [page:SplineCurve] onto the [page:ShapePath.currentPath currentPath].</p>
+		<p>points - 一个[page:Vector2]数组。</p>
+		<p>
+			连接一个新的[page:SplineCurve](样条曲线)到[page:ShapePath.currentPath currentPath](当前路径)。</p>
 
 
 		<h3>[method:Array toShapes]( [param:Boolean isCCW], [param:Boolean noHoles] )</h3>
 		<p>
-		isCCW -- Changes how solids and holes are generated<br/>
-		noHoles -- Whether or not to generate holes
+		isCCW -- 更改实体形状和孔洞的生成方式。<br/>
+		noHoles -- 是否创建孔洞。
 		</p>
 		<p>
-		Converts the [page:ShapePath.subPaths subPaths] array into an array of Shapes. By default solid shapes are defined clockwise (CW) and holes are defined counterclockwise (CCW). If isCCW is set to true,
-		then those are flipped. If the parameter noHoles is set to true then all paths are set as solid shapes and isCCW is ignored.
+		将[page:ShapePath.subPaths subPaths]数组转换为到Shapes数组。默认情况下,实体形状按照顺时针(CW)来定义,孔洞按照逆时针(CCW)来定义。
+		如果isCCW被设置为true,则孔洞和实体形状的定义将被反转。如果noHoles参数设置为true,则所有路径将被设置为实体形状,isCCW将被忽略。
 		<br/>
 
 		</p>
 
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/extras/core/Path.js src/extras/core/Path.js]
 	</body>

+ 7 - 7
docs/api/zh/extras/curves/ArcCurve.html

@@ -10,22 +10,22 @@
 	<body>
 		[page:EllipseCurve] &rarr;
 
-		<h1>[name]</h1>
+		<h1>弧线([name]</h1>
 
-		<p class="desc">Alias for [page:EllipseCurve]</p>
+		<p class="desc">[page:EllipseCurve]的别名</p>
 
-		<h2>Properties</h2>
-		<p>See the [page:EllipseCurve] class for common properties.</p>
+		<h2>属性</h2>
+		<p>请参阅[page:EllipseCurve]来了解共有属性。</p>
 
 		<h3>[property:Boolean isArcCurve]</h3>
 		<p>
-			Used to check whether this or derived classes are ArcCurves. Default is *true*.<br /><br />
+			用于检查该类或者其派生类是否为ArcCurves(弧线)。默认值为*true*。<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			你不应当对这一属性进行改变,它在内部使用,以用于优化。
 		</p>
 
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 19 - 18
docs/api/zh/extras/curves/CatmullRomCurve3.html

@@ -12,10 +12,11 @@
 
 		<h1>[name]</h1>
 
-		<p class="desc">Create a smooth 3d spline curve from a series of points using the
-			[link:https://en.wikipedia.org/wiki/Centripetal_Catmull-Rom_spline Catmull-Rom] algorithm.</p>
+		<p class="desc">
+			使用[link:https://en.wikipedia.org/wiki/Centripetal_Catmull-Rom_spline Catmull-Rom]算法,
+			从一系列的点创建一条平滑的三维样条曲线。</p>
 
-		<h2>Example</h2>
+		<h2>示例</h2>
 
 <code>
 //Create a closed wavey loop
@@ -39,42 +40,42 @@ var curveObject = new THREE.Line( geometry, material );
 		<h3>[example:webgl_geometry_extrude_splines geometry / extrude / splines]</h3>
 
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 		<h3>[name]( [param:Array points], [param:Boolean closed], [param:String curveType], [param:Float tension] )</h3>
 		<p>
-			points – An array of [page:Vector3] points<br/>
-			closed – Whether the curve is closed. Default is *false*.<br/>
-			curveType – Type of the curve. Default is *centripetal*.<br/>
-			tension – Tension of the curve. Default is *0.5*.
+			points – [page:Vector3]点数组<br/>
+			closed – 该曲线是否闭合,默认值为false。<br/>
+			curveType – 曲线的类型,默认值为*centripetal*。<br/>
+			tension – 曲线的张力,默认为*0.5*。
 		</p>
 
 
-		<h2>Properties</h2>
-		<p>See the base [page:Curve] class for common properties.</p>
+		<h2>属性</h2>
+		<p>请参阅其基类[page:Curve]来了解共有属性。</p>
 
 		<h3>[property:Boolean isCatmullRomCurve3]</h3>
 		<p>
-			Used to check whether this or derived classes are CatmullRomCurve3s. Default is *true*.<br /><br />
+			用于检查该类或者其派生类是否为CatmullRomCurve3。默认值为*true*。<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			你不应当对这一属性进行改变,它在内部使用,以用于优化。
 		</p>
 
 		<h3>[property:Array points]</h3>
-		<p>The array of [page:Vector3] points that define the curve. It needs at least two entries.</p>
+		<p>定义了这一曲线的[page:Vector3]点数组,数组中至少需要两个点。</p>
 
 		<h3>[property:Boolean closed]</h3>
-		<p>The curve will loop back onto itself when this is true.</p>
+		<p>当该值为true时,曲线将会闭合(环回自身)。</p>
 
 		<h3>[property:String curveType]</h3>
-		<p>Possible values are *centripetal*, *chordal* and *catmullrom*.</p>
+		<p>可能的值为*centripetal*、*chordal*和*catmullrom*。</p>
 
 		<h3>[property:float tension]</h3>
-		<p>When [page:.type] is *catmullrom*, defines catmullrom's tension.</p>
+		<p>当[page:.type]为*catmullrom*时,定义catmullrom的张力。</p>
 
 
-		<h2>Methods</h2>
-		<p>See the base [page:Curve] class for common methods.</p>
+		<h2>方法</h2>
+		<p>请参阅其基类[page:Curve]来了解共有方法。</p>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 22 - 21
docs/api/zh/extras/curves/CubicBezierCurve.html

@@ -10,15 +10,15 @@
 	<body>
 		[page:Curve] &rarr;
 
-		<h1>[name]</h1>
+		<h1>二维三次贝塞尔曲线([name]</h1>
 
 		<p class="desc">
-			Create a smooth 2d
-			<a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve#mediaviewer/File:Bezier_curve.svg" target="_blank">cubic bezier curve</a>,
-			defined by a start point, endpoint and two control points.
+			创建一条平滑的二维
+			<a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve#mediaviewer/File:Bezier_curve.svg" target="_blank">三次贝塞尔曲线</a>,
+			由起点、终点和两个控制点所定义。
 		</p>
 
-		<h2>Example</h2>
+		<h2>示例</h2>
 
 <code>
 var curve = new THREE.CubicBezierCurve(
@@ -37,44 +37,45 @@ var material = new THREE.LineBasicMaterial( { color : 0xff0000 } );
 var curveObject = new THREE.Line( geometry, material );
 </code>
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name] ( [param:Vector2 v0], [param:Vector2 v1], [param:Vector2 v2], [param:Vector2 v3] )</h3>
 		<p>
-			[page:Vector2 v0] – The starting point.<br/>
-			[page:Vector2 v1] – The first control point.<br/>
-			[page:Vector2 v2] – The second control point.<br/>
-			[page:Vector2 v3] – The ending point.
+			[page:Vector2 v0] – 起点<br/>
+			[page:Vector2 v1] – 第一个控制点<br/>
+			[page:Vector2 v2] – 第二个控制点<br/>
+			[page:Vector2 v3] – 终点
 		</p>
 
-		<h2>Properties</h2>
-		<p>See the base [page:Curve] class for common properties.</p>
+		<h2>属性</h2>
+		<p>请参阅其基类[page:Curve]来了解共有属性。</p>
 
 		<h3>[property:Boolean isCubicBezierCurve]</h3>
 		<p>
-			Used to check whether this or derived classes are CubicBezierCurves. Default is *true*.<br /><br />
+			
+			用于检查该类或者其派生类是否为CubicBezierCurves。默认值为*true*。<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			你不应当对这一属性进行改变,它在内部使用,以用于优化。
 		</p>
 
 		<h3>[property:Vector2 v0]</h3>
-		<p>The starting point.</p>
+		<p>起点</p>
 
 		<h3>[property:Vector2 v1]</h3>
-		<p>The first control point.</p>
+		<p>第一个控制点</p>
 
 		<h3>[property:Vector2 v2]</h3>
-		<p>The second control point.</p>
+		<p>第二个控制点</p>
 
 		<h3>[property:Vector2 v3]</h3>
-		<p>The ending point.</p>
+		<p>终点</p>
 
 
-		<h2>Methods</h2>
-		<p>See the base [page:Curve] class for common Methods.</p>
+		<h2>方法</h2>
+		<p>请参阅其基类[page:Curve]来了解共有方法。</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 25 - 25
docs/api/zh/extras/curves/CubicBezierCurve3.html

@@ -10,15 +10,15 @@
 	<body>
 		[page:Curve] &rarr;
 
-		<h1>[name]</h1>
+		<h1>三维三次贝塞尔曲线([name]</h1>
 
 		<p class="desc">
-			Create a smooth 3d
-			<a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve#mediaviewer/File:Bezier_curve.svg" target="_blank">cubic bezier curve</a>,
-			defined by a start point, endpoint and two control points.
+			创建一条平滑的三维
+			<a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve#mediaviewer/File:Bezier_curve.svg" target="_blank">三次贝塞尔曲线</a>,
+			由起点、终点和两个控制点所定义。
 		</p>
 
-		<h2>Example</h2>
+		<h2>示例</h2>
 
 <code>
 var curve = new THREE.CubicBezierCurve3(
@@ -38,44 +38,44 @@ var curveObject = new THREE.Line( geometry, material );
 
 </code>
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]( [param:Vector3 v0], [param:Vector3 v1], [param:Vector3 v2], [param:Vector3 v3] )</h3>
 		<p>
-			[page:Vector3 v0] – The starting point.<br/>
-			[page:Vector3 v1] – The first control point.<br/>
-			[page:Vector3 v2] – The second control point.<br/>
-			[page:Vector3 v3] – The ending point.
+			[page:Vector3 v0] – 起点<br/>
+			[page:Vector3 v1] – 第一个控制点<br/>
+			[page:Vector3 v2] – 第二个控制点<br/>
+			[page:Vector3 v3] – 终点
 		</p>
 
-		<h2>Properties</h2>
-		<p>See the base [page:Curve] class for common properties.</p>
+		<h2>属性</h2>
+		<p>请参阅其基类[page:Curve]来了解共有属性。</p>
 
 		<h3>[property:Boolean isCubicBezierCurve3]</h3>
 		<p>
-			Used to check whether this or derived classes are CubicBezierCurve3s. Default is *true*.<br /><br />
+			用于检查该类或者其派生类是否为CubicBezierCurves3。默认值为*true*。<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			你不应当对这一属性进行改变,它在内部使用,以用于优化。
 		</p>
 
-		<h3>[property:Vector2 v0]</h3>
-		<p>The starting point.</p>
+		<h3>[property:Vector3 v0]</h3>
+		<p>起点</p>
 
-		<h3>[property:Vector2 v1]</h3>
-		<p>The first control point.</p>
+		<h3>[property:Vector3 v1]</h3>
+		<p>第一个控制点</p>
 
-		<h3>[property:Vector2 v2]</h3>
-		<p>The second control point.</p>
+		<h3>[property:Vector3 v2]</h3>
+		<p>第二个控制点</p>
 
-		<h3>[property:Vector2 v3]</h3>
-		<p>The ending point.</p>
+		<h3>[property:Vector3 v3]</h3>
+		<p>终点</p>
 
 
-		<h2>Methods</h2>
-		<p>See the base [page:Curve] class for common Methods.</p>
+		<h2>方法</h2>
+		<p>请参阅其基类[page:Curve]来了解共有方法。</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 31 - 38
docs/api/zh/extras/curves/EllipseCurve.html

@@ -10,14 +10,14 @@
 	<body>
 		[page:Curve] &rarr;
 
-		<h1>[name]</h1>
+		<h1>椭圆曲线([name]</h1>
 
 		<p class="desc">
-			Creates a 2d curve in the shape of an ellipse. Setting the
-			[page:Number xRadius] equal to the [page:Number yRadius] will result in a circle.
+			创建一个形状为椭圆的曲线。
+			将[page:Number xRadius]与[page:Number yRadius]设为相等的值它将会成为一个圆。
 		</p>
 
-		<h2>Example</h2>
+		<h2>示例</h2>
 
 <code>
 var curve = new THREE.EllipseCurve(
@@ -37,68 +37,61 @@ var material = new THREE.LineBasicMaterial( { color : 0xff0000 } );
 var ellipse = new THREE.Line( geometry, material );
 </code>
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]( [param:Float aX], [param:Float aY], [param:Float xRadius], [param:Float yRadius], [param:Radians aStartAngle], [param:Radians aEndAngle], [param:Boolean aClockwise], [param:Radians aRotation] )</h3>
 		<p>
-			[page:Float aX] – The X center of the ellipse. Default is *0*.<br/>
-			[page:Float aY] – The Y center of the ellipse. Default is *0*.<br/>
-			[page:Float xRadius] – The radius of the ellipse in the x direction. Default is *1*.<br/>
-			[page:Float yRadius] – The radius of the ellipse in the y direction. Default is *1*.<br/>
-			[page:Radians aStartAngle] – The start angle of the curve in radians starting from the middle right side.  Default is *0*.<br/>
-			[page:Radians aEndAngle] – The end angle of the curve in radians starting from the middle right side. Default is *2 x Math.PI*.<br/>
-			[page:Boolean aClockwise] – Whether the ellipse is drawn clockwise. Default is *false*.<br/>
-			[page:Radians aRotation]  – The rotation angle of the ellipse in radians, counterclockwise from the positive X axis (optional). Default is *0*.<br/><br/>
-
-			<em>Note:</em> When going clockwise it's best to set the start angle to (Math.PI * 2) and then work towards lower numbers.
+			[page:Float aX] – 椭圆的中心的X坐标,默认值为*0*。<br/>
+			[page:Float aY] – 椭圆的中心的Y坐标,默认值为*0*。<br/>
+			[page:Float xRadius] – X轴向上椭圆的半径,默认值为*1*。<br/>
+			[page:Float yRadius] – Y轴向上椭圆的半径,默认值为*1*。<br/>
+			[page:Radians aStartAngle] – 以弧度来表示,从正右侧算起曲线开始的角度,默认值为*0*。<br/>
+			[page:Radians aEndAngle] – 以弧度来表示,从正右侧算起曲线终止的角度,默认值为*2 x Math.PI*。<br/>
+			[page:Boolean aClockwise] – 椭圆是否按照顺时针方向来绘制,默认值为*false*。<br/>
+			[page:Radians aRotation]  – 以弧度表示,椭圆从X轴正方向逆时针的旋转角度(可选),默认值为*0*。<br/><br/>
+
+			<em>请注意:</em> 当使用顺时针的时候,最好将起始角度角度设为(Math.PI * 2),并向着更小的数字运行。
 		</p>
 
-		<h2>Properties</h2>
-		<p>See the base [page:Curve] class for common properties.</p>
+		<h2>属性</h2>
+		<p>请参阅其基类[page:Curve]来了解共有属性。</p>
 
 		<h3>[property:Boolean isEllipseCurve]</h3>
 		<p>
-			Used to check whether this or derived classes are EllipseCurves. Default is *true*.<br /><br />
-
-			You should not change this, as it used internally for optimisation.
+			用于检查该类或者其派生类是否为EllipseCurves。默认值为*true*。
+			<br /><br />
+			你不应当更改这个属性,它在内部使用,以用于优化。
 		</p>
 
 		<h3>[property:Float aX]</h3>
-		<p>The X center of the ellipse.</p>
+		<p>椭圆的中心的X坐标。</p>
 
 		<h3>[property:Float aY]</h3>
-		<p>The Y center of the ellipse.</p>
+		<p>椭圆的中心的Y坐标。</p>
 
 		<h3>[property:Radians xRadius]</h3>
-		<p>The radius of the ellipse in the x direction.</p>
+		<p>X轴向上椭圆的半径。</p>
 
 		<h3>[property:Radians yRadius]</h3>
-		<p>The radius of the ellipse in the y direction.</p>
+		<p>Y轴向上椭圆的半径。</p>
 
 		<h3>[property:Float aStartAngle]</h3>
-		<p>The start angle of the curve in radians starting from the middle right side.</p>
+		<p>以弧度来表示,从正右侧算起曲线开始的角度。</p>
 
 		<h3>[property:Float aEndAngle]</h3>
-		<p>The end angle of the curve in radians starting from the middle right side.</p>
+		<p>以弧度来表示,从正右侧算起曲线终止的角度。</p>
 
 		<h3>[property:Boolean aClockwise]</h3>
-		<p>Whether the ellipse is drawn clockwise.</p>
+		<p>椭圆是否按照顺时针方向来绘制。</p>
 
 		<h3>[property:Float aRotation]</h3>
-		<p>The rotation angle of the ellipse in radians, counterclockwise from the positive X axis (optional). Default is *0*.</p>
-
-		<h3>[property:Boolean isEllipseCurve]</h3>
-		<p>
-			Used to check whether this or derived classes are ellipses. Default is *true*.<br /><br />
-
-			You should not change this, as it used internally for optimisation.
-		</p>
+		<p>以弧度表示,椭圆在X轴正方向逆时针的旋转角度(可选),默认值为*0*。</p>
 
-		<h2>Methods</h2>
-		<p>See the base [page:Curve] class for common methods.</p>
+		<h2>方法</h2>
+		<p>请参阅其基类[page:Curve]来了解共有方法。</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 15 - 14
docs/api/zh/extras/curves/LineCurve.html

@@ -10,41 +10,42 @@
 	<body>
 		[page:Curve] &rarr;
 
-		<h1>[name]</h1>
+		<h1>二维线段曲线([name]</h1>
 
-		<p class="desc">A curve representing a 2d line segment.</p>
+		<p class="desc">一个表示二维线段的曲线。</p>
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]( [param:Vector2 v1], [param:Vector2 v2] )</h3>
 		<p>
-			[page:Vector2 v1] – The start point.<br/>
-			[page:Vector2 v2] - The end point.
+			[page:Vector2 v1] – 起点<br/>
+			[page:Vector2 v2] - 终点
 		</p>
 
 
-		<h2>Properties</h2>
-		<p>See the base [page:Curve] class for common properties.</p>
+		<h2>属性</h2>
+		<p>请参阅其基类[page:Curve]来了解共有属性。</p>
 
 		<h3>[property:Boolean isLineCurve]</h3>
 		<p>
-			Used to check whether this or derived classes are LineCurves. Default is *true*.<br /><br />
+			用于检查该类或者其派生类是否为LineCurves。默认值为*true*。
+			<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			你不应当更改这个属性,它在内部使用,以用于优化。
 		</p>
 
 		<h3>[property:Vector2 v1]</h3>
-		<p>The start point.</p>
+		<p>起点</p>
 
 		<h3>[property:Vector2 v2]</h3>
-		<p>The end point</p>
+		<p>终点</p>
 
-		<h2>Methods</h2>
-		<p>See the base [page:Curve] class for common methods.</p>
+		<h2>方法</h2>
+		<p>请参阅其基类[page:Curve]来了解共有方法。</p>
 
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 16 - 15
docs/api/zh/extras/curves/LineCurve3.html

@@ -10,40 +10,41 @@
 	<body>
 		[page:Curve] &rarr;
 
-		<h1>[name]</h1>
+		<h1>三维线段曲线([name]</h1>
 
-		<p class="desc">A curve representing a 3d line segment.</p>
+		<p class="desc">一个表示三维线段的曲线。</p>
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]( [param:Vector3 v1], [param:Vector3 v2] )</h3>
 		<p>
-			[page:Vector3 v1] – The start point.<br/>
-			[page:Vector3 v2] - The end point.
+			[page:Vector3 v1] – 起点<br/>
+			[page:Vector3 v2] - 终点
 		</p>
 
 
-		<h2>Properties</h2>
-		<p>See the base [page:Curve] class for common properties.</p>
+		<h2>属性</h2>
+		<p>请参阅其基类[page:Curve]来了解共有属性。</p>
 
 		<h3>[property:Boolean isLineCurve3]</h3>
 		<p>
-			Used to check whether this or derived classes are LineCurve3s. Default is *true*.<br /><br />
-
-			You should not change this, as it used internally for optimisation.
+			用于检查该类或者其派生类是否为LineCurves。默认值为*true*。
+			<br /><br />
+	
+			你不应当更改这个属性,它在内部使用,以用于优化。
 		</p>
 
 		<h3>[property:Vector3 v1]</h3>
-		<p>The start point.</p>
+		<p>起点</p>
 
 		<h3>[property:Vector3 v2]</h3>
-		<p>The end point.</p>
+		<p>终点</p>
 
-		<h2>Methods</h2>
-		<p>See the base [page:Curve] class for common methods.</p>
+		<h2>方法</h2>
+		<p>请参阅其基类[page:Curve]来了解共有方法。</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 19 - 19
docs/api/zh/extras/curves/QuadraticBezierCurve.html

@@ -10,15 +10,15 @@
 	<body>
 		[page:Curve] &rarr;
 
-		<h1>[name]</h1>
+		<h1>二维二次贝塞尔曲线([name])</h1>
 
 		<p class="desc">
-			Create a smooth 2d
-			<a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve#mediaviewer/File:B%C3%A9zier_2_big.gif" target="_blank">quadratic bezier curve</a>,
-			defined by a startpoint, endpoint and a single control point.
+			创建一条平滑的二维
+			<a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve#mediaviewer/File:B%C3%A9zier_2_big.gif" target="_blank">二次贝塞尔曲线</a>,
+			由起点、终点和一个控制点所定义。
 		</p>
 
-		<h2>Example</h2>
+		<h2>示例</h2>
 
 <code>
 var curve = new THREE.QuadraticBezierCurve(
@@ -36,41 +36,41 @@ var material = new THREE.LineBasicMaterial( { color : 0xff0000 } );
 var curveObject = new THREE.Line( geometry, material );
 </code>
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]( [param:Vector2 v0], [param:Vector2 v1], [param:Vector2 v2] )</h3>
 		<p>
-			[page:Vector2 v0] – The startpoint.<br/>
-			[page:Vector2 v1] – The control point.<br/>
-			[page:Vector2 v2] – The endpoint.
+			[page:Vector2 v0] – 起点<br/>
+			[page:Vector2 v1] – 中间的控制点<br/>
+			[page:Vector2 v2] – 终点<br/>
 		</p>
 
 
-		<h2>Properties</h2>
-		<p>See the base [page:Curve] class for common properties.</p>
+		<h2>属性</h2>
+		<p>请参阅其基类[page:Curve]来了解共有属性。</p>
 
 		<h3>[property:Boolean isQuadraticBezierCurve]</h3>
 		<p>
-			Used to check whether this or derived classes are QuadraticBezierCurves. Default is *true*.<br /><br />
+			用于检查该类或者其派生类是否为QuadraticBezierCurve。默认值为*true*。<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			你不应当对这一属性进行改变,它在内部使用,以用于优化。
 		</p>
 
 
 		<h3>[property:Vector2 v0]</h3>
-		<p>The startpoint.</p>
+		<p>起点</p>
 
 		<h3>[property:Vector2 v1]</h3>
-		<p>The control point.</p>
+		<p>控制点</p>
 
 		<h3>[property:Vector2 v2]</h3>
-		<p>The endpoint.</p>
+		<p>终点</p>
 
-		<h2>Methods</h2>
-		<p>See the base [page:Curve] class for common methods.</p>
+		<h2>方法</h2>
+		<p>请参阅其基类[page:Curve]来了解共有方法。</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 19 - 19
docs/api/zh/extras/curves/QuadraticBezierCurve3.html

@@ -10,15 +10,15 @@
 	<body>
 		[page:Curve] &rarr;
 
-		<h1>[name]</h1>
+		<h1>三维二次贝塞尔曲线([name]</h1>
 
 		<p class="desc">
-			Create a smooth 3d
-			<a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve#mediaviewer/File:B%C3%A9zier_2_big.gif" target="_blank">quadratic bezier curve</a>,
-			defined by a startpoint, endpoint and a single control point.
+			创建一条平滑的三维
+			<a href="http://en.wikipedia.org/wiki/B%C3%A9zier_curve#mediaviewer/File:B%C3%A9zier_2_big.gif" target="_blank">二次贝塞尔曲线</a>,
+			由起点、终点和一个控制点所定义。
 		</p>
 
-		<h2>Example</h2>
+		<h2>示例</h2>
 
 <code>
 var curve = new THREE.QuadraticBezierCurve3(
@@ -36,41 +36,41 @@ var material = new THREE.LineBasicMaterial( { color : 0xff0000 } );
 var curveObject = new THREE.Line( geometry, material );
 </code>
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]( [param:Vector3 v0], [param:Vector3 v1], [param:Vector3 v2] )</h3>
 		<p>
-			[page:Vector3 v0] – The starting point<br/>
-			[page:Vector3 v1] – The middle control point<br/>
-			[page:Vector3 v2] – The ending point<br/>
+			[page:Vector3 v0] – 起点<br/>
+			[page:Vector3 v1] – 中间的控制点<br/>
+			[page:Vector3 v2] – 终点<br/>
 		</p>
 
 
 
-		<h2>Properties</h2>
-		<p>See the base [page:Curve] class for common properties.</p>
+		<h2>属性</h2>
+		<p>请参阅其基类[page:Curve]来了解共有属性。</p>
 
 		<h3>[property:Boolean isQuadraticBezierCurve3]</h3>
 		<p>
-			Used to check whether this or derived classes are QuadraticBezierCurve3s. Default is *true*.<br /><br />
+			用于检查该类或者其派生类是否为QuadraticBezierCurve3。默认值为*true*。<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			你不应当对这一属性进行改变,它在内部使用,以用于优化。
 		</p>
 
 		<h3>[property:Vector3 v0]</h3>
-		<p>The startpoint.</p>
+		<p>起点</p>
 
 		<h3>[property:Vector3 v1]</h3>
-		<p>The control point.</p>
+		<p>控制点</p>
 
 		<h3>[property:Vector3 v2]</h3>
-		<p>The endpoint.</p>
+		<p>终点</p>
 
-		<h2>Methods</h2>
-		<p>See the base [page:Curve] class for common methods.</p>
+		<h2>方法</h2>
+		<p>请参阅其基类[page:Curve]来了解共有方法。</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 13 - 14
docs/api/zh/extras/curves/SplineCurve.html

@@ -10,14 +10,13 @@
 	<body>
 		[page:Curve] &rarr;
 
-		<h1>[name]</h1>
+		<h1>样条曲线([name]</h1>
 
 		<p class="desc">
-		Create a smooth 2d spline curve from a series of points. Internally this uses
-		[page:Interpolations.CatmullRom] to create the curve.
+			从一系列的点中,创建一个平滑的二维样条曲线。内部使用[page:Interpolations.CatmullRom]来创建曲线。
 		</p>
 
-		<h2>Example</h2>
+		<h2>示例</h2>
 
 <code>
 // Create a sine-like wave
@@ -38,34 +37,34 @@ var material = new THREE.LineBasicMaterial( { color : 0xff0000 } );
 var splineObject = new THREE.Line( geometry, material );
 </code>
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]( [param:Array points] )</h3>
-		<p>points – An array of [page:Vector2] points that define the curve.</p>
+		<p>points – 定义曲线的[page:Vector2]点的数组。</p>
 
 
-		<h2>Properties</h2>
-		<p>See the base [page:Curve] class for common properties.</p>
+		<h2>属性</h2>
+		<p>请参阅其基类[page:Curve]来了解共有属性。</p>
 
 		<h3>[property:Boolean isSplineCurve]</h3>
 		<p>
-			Used to check whether this or derived classes are SplineCurves. Default is *true*.<br /><br />
+			用于检查该类或者其派生类是否为样条曲线。默认值为*true*。<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			你不应当对这一属性进行改变,它在内部使用,以用于优化。
 		</p>
 
 		<h3>[property:Array points]</h3>
-		<p>The array of [page:Vector2] points that define the curve.</p>
+		<p>定义这一曲线的[page:Vector2]点的数组。</p>
 
 
 
-		<h2>Methods</h2>
-		<p>See the base [page:Curve] class for common methods.</p>
+		<h2>方法</h2>
+		<p>请参阅其基类[page:Curve]来了解共有方法。</p>
 
 
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 2 - 2
docs/api/zh/extras/objects/ImmediateRenderObject.html

@@ -10,9 +10,9 @@
 	<body>
 		[page:Object3D] &rarr;
 
-		<h1>时渲染对象([name])</h1>
+		<h1>时渲染对象([name])</h1>
 
-		<p class="desc">时渲染对象的基类。</p>
+		<p class="desc">时渲染对象的基类。</p>
 
 
 		<h2>构造函数(Constructor)</h2>

+ 1 - 1
docs/api/zh/geometries/CircleBufferGeometry.html

@@ -10,7 +10,7 @@
 	<body>
 		[page:BufferGeometry] &rarr;
 
-		<h1>圆形缓冲几何体[name]</h1>
+		<h1>圆形缓冲几何体[name]</h1>
 
 		<p class="desc">这是[page:CircleGeometry]中的[page:BufferGeometry]接口。</p>
 

+ 1 - 1
docs/api/zh/geometries/LatheBufferGeometry.html

@@ -10,7 +10,7 @@
 	<body>
 		[page:BufferGeometry] &rarr;
 
-		<h1>[name]</h1>
+		<h1>车削缓冲几何体([name]</h1>
 
 		<p class="desc">这是[page:LatheGeometry]中的[page:BufferGeometry]接口。</p>
 

+ 7 - 7
docs/api/zh/geometries/ParametricBufferGeometry.html

@@ -10,9 +10,9 @@
 	<body>
 		[page:BufferGeometry] &rarr;
 
-		<h1>[name]</h1>
+		<h1>参数化缓冲几何体([name]</h1>
 
-		<p class="desc">Generate geometry representing a parametric surface.</p>
+		<p class="desc">生成由参数表示其表面的几何体。</p>
 
 		<iframe id="scene" src="scenes/geometry-browser.html#ParametricBufferGeometry"></iframe>
 
@@ -32,7 +32,7 @@
 
 		</script>
 
-		<h2>Example</h2>
+		<h2>示例</h2>
 
 		<code>
 		var geometry = new THREE.ParametricBufferGeometry( THREE.ParametricGeometries.klein, 25, 25 );
@@ -42,7 +42,7 @@
 		</code>
 
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]([param:Function func], [param:Integer slices], [param:Integer stacks])</h3>
@@ -52,15 +52,15 @@
 		stacks — The count of stacks to use for the parametric function
 		</p>
 
-		<h2>Properties</h2>
+		<h2>属性</h2>
 
 		<h3>[property:Object parameters]</h3>
 		<p>
-		An object with a property for each of the constructor parameters. Any modification after instantiation does not change the geometry.
+		一个包含着构造函数中每个参数的对象。在对象实例化之后,对该属性的任何修改都不会改变这个几何体。
 		</p>
 
 
-		<h2>Source</h2>
+		<h2>方法</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/geometries/ParametricGeometry.js src/geometries/ParametricGeometry.js]
 	</body>

+ 7 - 7
docs/api/zh/geometries/ParametricGeometry.html

@@ -10,9 +10,9 @@
 	<body>
 		[page:Geometry] &rarr;
 
-		<h1>[name]</h1>
+		<h1>参数化几何体([name]</h1>
 
-		<p class="desc">Generate geometry representing a parametric surface.</p>
+		<p class="desc">生成由参数表示其表面的几何体。</p>
 
 		<iframe id="scene" src="scenes/geometry-browser.html#ParametricGeometry"></iframe>
 
@@ -32,7 +32,7 @@
 
 		</script>
 
-		<h2>Example</h2>
+		<h2>示例</h2>
 
 		<code>
 		var geometry = new THREE.ParametricGeometry( THREE.ParametricGeometries.klein, 25, 25 );
@@ -42,7 +42,7 @@
 		</code>
 
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]([param:Function func], [param:Integer slices], [param:Integer stacks])</h3>
@@ -53,15 +53,15 @@
 		</p>
 
 
-		<h2>Properties</h2>
+		<h2>属性</h2>
 
 		<h3>[property:Object parameters]</h3>
 		<p>
-		An object with a property for each of the constructor parameters. Any modification after instantiation does not change the geometry.
+		一个包含着构造函数中每个参数的对象。在对象实例化之后,对该属性的任何修改都不会改变这个几何体。
 		</p>
 
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 1 - 1
docs/api/zh/geometries/PlaneBufferGeometry.html

@@ -10,7 +10,7 @@
 	<body>
 		[page:BufferGeometry] &rarr;
 
-		<h1>[name]</h1>
+		<h1>平面缓冲几何体([name]</h1>
 
 		<p class="desc">这是[page:PlaneGeometry]中的[page:BufferGeometry]接口。</p>
 

+ 1 - 1
docs/api/zh/geometries/SphereGeometry.html

@@ -10,7 +10,7 @@
 	<body>
 		[page:Geometry] &rarr;
 
-		<h1>球几何体[name]</h1>
+		<h1>球几何体[name]</h1>
 
 		<p class="desc">一个用于生成球体的类。</p>
 

+ 1 - 1
docs/api/zh/geometries/TorusGeometry.html

@@ -10,7 +10,7 @@
 	<body>
 		[page:Geometry] &rarr;
 
-		<h1>圆环几何体[name]</h1>
+		<h1>圆环几何体[name]</h1>
 
 		<p class="desc">一个用于生成圆环几何体的类。</p>
 

+ 1 - 1
docs/api/zh/geometries/TorusKnotBufferGeometry.html

@@ -10,7 +10,7 @@
 	<body>
 		[page:BufferGeometry] &rarr;
 
-		<h1>[name]</h1>
+		<h1>圆环缓冲几何体([name]</h1>
 
 		<p class="desc">This is the [page:BufferGeometry] port of [page:TorusKnotGeometry].</p>
 

+ 0 - 1
docs/api/zh/loaders/ObjectLoader.html

@@ -19,7 +19,6 @@
 		<h2>例子</h2>
 
 		<p>
-			[example:webgl_animation_skinning_blending WebGL / animation / skinning / blending]<br />
 			[example:webgl_loader_json_claraio WebGL / loader / json / claraio]<br />
 			[example:webgl_materials_lightmap WebGL / materials / lightmap]
 		</p>

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

@@ -83,17 +83,6 @@
     这可以与网格的[page:Integer renderOrder]属性结合使用,以创建遮挡其他对象的不可见对象。默认值为*true*。
 </p>
 
-<h3>[property:Material customDepthMaterial]</h3>
-<p>渲染到深度贴图时此材质要使用的自定义深度材质。
-    当使用[page:DirectionalLight]或[page:SpotLight]进行阴影投射时,如果您正在(a)修改顶点着色器中的顶点位置,
-    (b)使用位移贴图,(c)alphaTest中使用alpha贴图,或(d)alphaTest中使用透明纹理,
-    您必须指定customDepthMaterial以得到合适的阴影。默认值*undefined*。
-</p>
-
-<h3>[property:Material customDistanceMaterial]</h3>
-<p>与customDepthMaterial相同,但与[page:PointLight]一起使用。默认值为*undefined*。
-</p>
-
 <h3>[property:Object defines]</h3>
 <p> 注入shader的自定义对象。 以键值对形式的对象传递,{ MY_CUSTOM_DEFINE: '' , PI2: Math.PI * 2 }。
     这些键值对在顶点和片元着色器中定义。默认值为*undefined*。

+ 1 - 1
docs/api/zh/math/Matrix4.html

@@ -8,7 +8,7 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		<h1>四维矩阵([name]</h1>
+		<h1>四维矩阵([name]</h1>
 
 		<p class="desc">
 			表示为一个 4x4 [link:https://en.wikipedia.org/wiki/Matrix_(mathematics) matrix].<br /><br />

+ 1 - 1
docs/api/zh/math/Quaternion.html

@@ -290,4 +290,4 @@ q.slerp( qb, t )
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>
-</html>
+</html>

+ 67 - 75
docs/api/zh/math/Ray.html

@@ -8,206 +8,198 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		<h1>[name]</h1>
+		<h1>射线([name]</h1>
 
 		<p class="desc">
-			A ray that emits from an origin in a certain direction. This is used by the
-			[page:Raycaster] to assist with [link:https://en.wikipedia.org/wiki/Ray_casting raycasting].
-			Raycasting is used for mouse picking (working out what objects in the 3D space the mouse is over) amongst
-			other things.
+			射线由一个原点向一个确定的方向发射。它被[page:Raycaster](光线投射)所使用,
+			以用于辅助[link:https://en.wikipedia.org/wiki/Ray_casting raycasting]。
+			光线投射用于在各个物体之间进行拾取(当鼠标经过三维空间中的物体/对象时进行拾取)。
 		</p>
 
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]( [param:Vector3 origin], [param:Vector3 direction] )</h3>
 		<p>
-		[page:Vector3 origin] - (optional) the origin of the [page:Ray]. Default is a [page:Vector3] at (0, 0, 0).<br />
-		[page:Vector3 direction] - [page:Vector3] The direction of the [page:Ray]. This must be normalized
-		 (with [page:Vector3.normalize]) for the methods to operate properly.  Default is a [page:Vector3] at (0, 0, 0).<br /><br />
+		[page:Vector3 origin] - (可选)[page:Ray](射线)的原点,默认值是一个位于(0, 0, 0)的[page:Vector3]。<br />
+		[page:Vector3 direction] - [page:Vector3] [page:Ray](射线)的方向。该向量必须经过标准化(使用[page:Vector3.normalize]),这样才能使方法正常运行。
+		默认值是一个位于(0, 0, 0)的[page:Vector3]。<br /><br />
 
-		Creates a new [name].
+		创建一个新的[name]。
 		</p>
 
-		<h2>Properties</h2>
+		<h2>属性</h2>
 
 		<h3>[property:Vector3 origin]</h3>
-		<p>The origin of the [page:Ray]. Default is a [page:Vector3] at (0, 0, 0).</p>
+		<p>[page:Ray](射线)的原点,默认值是一个位于(0, 0, 0)的[page:Vector3]。</p>
 
 		<h3>[property:Vector3 direction]</h3>
 		<p>
-		The direction of the [page:Ray]. This must be normalized (with [page:Vector3.normalize])
-		for the methods to operate properly. Default is a [page:Vector3] at (0, 0, 0).
+		[page:Ray](射线)的方向。该向量必须经过标准化(使用[page:Vector3.normalize]),这样才能使方法正常运行。
+		默认值是一个位于(0, 0, 0)的[page:Vector3]。
 		</p>
 
 
 
 
-		<h2>Methods</h2>
+		<h2>方法</h2>
 
 		<h3>[method:Ray applyMatrix4]( [param:Matrix4 matrix4] )</h3>
 		<p>
-		[page:Matrix4 matrix4] - the [page:Matrix4] to apply to this [page:Ray].<br /><br />
+		[page:Matrix4 matrix4] - 将被用于这个[page:Ray]的[page:Matrix4]。<br /><br />
 
-		Transform this [page:Ray] by the [page:Matrix4].
+		使用传入的[page:Matrix4]来变换这个[page:Ray]。
 		</p>
 
 		<h3>[method:Vector3 at]( [param:Float t], [param:Vector3 target] ) </h3>
 		<p>
-		[page:Float t] - the distance along the [page:Ray] to retrieve a position for.<br />
-		[page:Vector3 target] — the result will be copied into this Vector3.<br /><br />
+		[page:Float t] - 使用这一传入的距离,在[page:Ray]上确定一个位置。<br />
+		[page:Vector3 target] — 结果将复制到这一Vector3中。<br /><br />
 
-		Get a [page:Vector3] that is a given distance along this [page:Ray].
+		获得这一[page:Ray]上给定距离处的[page:Vector3]。
 		</p>
 
 		<h3>[method:Ray clone]()</h3>
 		<p>
-			Creates a new Ray with identical [page:.origin origin] and [page:.direction direction]  to this one.
+			创建一个新的和这个Ray具有相同[page:.origin origin]和[page:.direction direction]的Ray。
 		</p>
 
 		<h3>[method:Vector3 closestPointToPoint]( [param:Vector3 point], [param:Vector3 target] )</h3>
 		<p>
-		[page:Vector3 point] - the point to get the closest approach to. <br />
-		[page:Vector3 target] — the result will be copied into this Vector3.<br /><br />
+		[page:Vector3 point] - 获得距离射线上的点最接近的点。<br />
+		[page:Vector3 target] — 结果将复制到这一Vector3中。<br /><br />
 
-		Get the point along this [page:Ray] that is closest to the [page:Vector3] provided.
+		沿着[page:Ray],获得与所传入[page:Vector3]最接近的点。
 		</p>
 
 		<h3>[method:Ray copy]( [param:Ray ray] )</h3>
 		<p>
-			Copies the [page:.origin origin] and [page:.direction direction] properties
-			of [page:Ray ray] into this ray.
+			复制所传入Ray的[page:.origin origin]和[page:.direction direction]属性到这个Ray上。
 		</p>
 
 		<h3>[method:Float distanceSqToPoint]( [param:Vector3 point] )</h3>
 		<p>
 		[page:Vector3 point] - the [page:Vector3] to compute a distance to.<br /><br />
 
-		Get the squared distance of the closest approach between the [page:Ray] and the [page:Vector3].
+		获得[page:Ray]与传入的[page:Vector3]之间最近的平方距离。
 		</p>
 
 		<h3>[method:Float distanceSqToSegment]( [param:Vector3 v0], [param:Vector3 v1], [param:Vector3 optionalPointOnRay], [param:Vector3 optionalPointOnSegment] )</h3>
 		<p>
-		[page:Vector3 v0] - the start of the line segment.<br />
-		[page:Vector3 v1] - the end of the line segment.<br />
-		optionalPointOnRay - (optional) if this is provided, it receives the point on this
-			[page:Ray] that is closest to the segment.<br />
-		optionalPointOnSegment - (optional) if this is provided, it receives the point
-			on the line segment that is closest to this [page:Ray].<br /><br />
+		[page:Vector3 v0] - 线段的起点。<br />
+		[page:Vector3 v1] - 线段的终点。<br />
+		optionalPointOnRay - (可选)若这个值被给定,它将接收在[page:Ray](射线)上距离线段最近的点。
+			<br />
+		optionalPointOnSegment - (可选)若这个值被给定,它将接收在线段上距离[page:Ray](射线)最近的点。<br /><br />
 
-		Get the squared distance between this [page:Ray] and a line segment.
+		获取[page:Ray](射线)与线段之间的平方距离。
 		</p>
 
 		<h3>[method:Float distanceToPlane]( [param:Plane plane] )</h3>
 		<p>
-		[page:Plane plane] - the [page:Plane] to get the distance to.<br /><br />
+		[page:Plane plane] - 将要获取射线原点到该平面的距离的平面。<br /><br />
 
-		Get the distance from [page:.origin origin] to the [page:Plane], or *null* if the [page:Ray] doesn't intersect the [page:Plane].
+		获取射线原点([page:.origin origin])到平面([page:Plane])之间的距离。若射线([page:Ray])不与平面([page:Plane])相交,则将返回*null*。
 		</p>
 
 		<h3>[method:Float distanceToPoint]( [param:Vector3 point] )</h3>
 		<p>
-		[page:Vector3 point] - [page:Vector3] The [page:Vector3] to compute a distance to.<br /><br />
+		[page:Vector3 point] - [page:Vector3] 将被用于计算到其距离的[page:Vector3]。<br /><br />
 
-		Get the distance of the closest approach between the [page:Ray] and the [page:Vector3 point].
+		获得[page:Ray](射线)到所传入[page:Vector3 point]之间最接近的距离。
 		</p>
 
 
 		<h3>[method:Boolean equals]( [param:Ray ray] )</h3>
 		<p>
-		[page:Ray ray] - the [page:Ray] to compare to.<br /><br />
+		[page:Ray ray] - 用于比较的[page:Ray]。<br /><br />
 
-		Returns true if this and the other [page:Ray ray] have equal [page:.offset offset]
-		 and [page:.direction direction].
+		如果所传入的[page:Ray ray]具有和当前Ray相同的[page:.offset offset]和[page:.direction direction]则返回true。
 		</p>
 
 		<h3>[method:Vector3 intersectBox]( [param:Box3 box], [param:Vector3 target] )</h3>
 		<p>
-		[page:Box3 box] - the [page:Box3] to intersect with.<br />
-		[page:Vector3 target] — the result will be copied into this Vector3.<br /><br />
+		[page:Box3 box] - 将会与之相交的[page:Box3]。<br />
+		[page:Vector3 target] — 结果将会被复制到这一Vector3中。<br /><br />
 
-		Intersect this [page:Ray] with a [page:Box3], returning the intersection point or
-		*null* if there is no intersection.
+		将[page:Ray](射线)与一个[page:Box3]相交,并返回交点,倘若没有交点将返回*null*。
 		</p>
 
 		<h3>[method:Vector3 intersectPlane]( [param:Plane plane], [param:Vector3 target] )</h3>
 		<p>
-		[page:Plane plane] - the [page:Plane] to intersect with.<br />
-		[page:Vector3 target] — the result will be copied into this Vector3.<br /><br />
+		[page:Plane plane] - 将会与之相交的[page:Plane]。<br />
+		[page:Vector3 target] — 结果将会被复制到这一Vector3中。<br /><br />
 
-		Intersect this [page:Ray] with a [page:Plane], returning the intersection point or
-		*null* if there is no intersection.
+		将[page:Ray](射线)与一个[page:Plane]相交,并返回交点,倘若没有交点将返回*null*。
 		</p>
 
 		<h3>[method:Vector3 intersectSphere]( [param:Sphere sphere], [param:Vector3 target] )</h3>
 		<p>
-		[page:Sphere sphere] - the [page:Sphere] to intersect with.<br />
-		[page:Vector3 target] — the result will be copied into this Vector3.<br /><br />
+		[page:Sphere sphere] - 将会与之相交的[page:Sphere]。<br />
+		[page:Vector3 target] — 结果将会被复制到这一Vector3中。<br /><br />
 
-		Intersect this [page:Ray] with a [page:Sphere], returning the intersection point or
-		*null* if there is no intersection.
+		将[page:Ray](射线)与一个[page:Sphere](球)相交,并返回交点,倘若没有交点将返回*null*。
 		</p>
 
 		<h3>[method:Vector3 intersectTriangle]( [param:Vector3 a], [param:Vector3 b], [param:Vector3 c], [param:Boolean backfaceCulling], [param:Vector3 target] )</h3>
 		<p>
-		[page:Vector3 a], [page:Vector3 b], [page:Vector3 c] - The [page:Vector3] points making up the triangle.<br />
-		[page:Boolean backfaceCulling] - whether to use backface culling.<br />
-		[page:Vector3 target] — the result will be copied into this Vector3.<br /><br />
+		[page:Vector3 a], [page:Vector3 b], [page:Vector3 c] - 组成三角形的三个[page:Vector3]。<br />
+		[page:Boolean backfaceCulling] - 是否使用背面剔除。<br />
+		[page:Vector3 target] — 结果将会被复制到这一Vector3中。<br /><br />
 
-		Intersect this [page:Ray] with a triangle, returning the intersection point or *null*
-		if there is no intersection.
+		将[page:Ray](射线)与一个三角形相交,并返回交点,倘若没有交点将返回*null*。
 		</p>
 
 		<h3>[method:Boolean intersectsBox]( [param:Box3 box] )</h3>
 		<p>
-		[page:Box3 box] - the [page:Box3] to intersect with.<br /><br />
+		[page:Box3 box] - 将被检查是否与之相交的[page:Box3]。<br /><br />
 
-		Return true if this [page:Ray] intersects with the [page:Box3].
+		若这一射线与[page:Box3]相交,则将返回true。
 		</p>
 
 		<h3>[method:Boolean intersectsPlane]( [param:Plane plane] )</h3>
 		<p>
-		[page:Plane plane] - the [page:Plane] to intersect with.<br /><br />
+		[page:Plane plane] - 将被检查是否与之相交的[page:Plane]。<br /><br />
 
-		Return true if this [page:Ray] intersects with the [page:Plane].
+		若这一射线与[page:Plane]相交,则将返回true。
 		</p>
 
 		<h3>[method:Boolean intersectsSphere]( [param:Sphere sphere] )</h3>
 		<p>
-		[page:Sphere sphere] - the [page:Sphere] to intersect with.<br /><br />
+		[page:Sphere sphere] - 将被检查是否与之相交的[page:Sphere]。<br /><br />
 
-		Return true if this [page:Ray] intersects with the [page:Sphere].
+		若这一射线与[page:Sphere]相交,则将返回true。
 		</p>
 
 		<h3>[method:Ray lookAt]( [param:Vector3 v] )</h3>
 		<p>
-		[page:Vector3 v] - The [page:Vector3] to look at.<br /><br />
+		[page:Vector3 v] - 将要“直视”的[page:Vector3]<br /><br />
 
-		Adjusts the direction of the ray to point at the vector in world coordinates.
+		调整光线的方向到世界坐标中该向量所指代的点。
 		</p>
 
 		<h3>[method:Ray recast]( [param:Float t] )</h3>
 		<p>
-		[page:Float t] - The distance along the [page:Ray] to interpolate.<br /><br />
+		[page:Float t] - 沿着[page:Ray]进行插值的距离。<br /><br />
 
-		Shift the origin of this [page:Ray] along its direction by the distance given.
+		将[page:Ray](射线)的原点沿着其方向移动给定的距离。
 		</p>
 
 		<h3>[method:Ray set]( [param:Vector3 origin], [param:Vector3 direction] )</h3>
 		<p>
-		[page:Vector3 origin] - the [page:.origin origin] of the [page:Ray].<br />
-		[page:Vector3 origin] - the [page:.direction direction] of the [page:Ray].
-		This must be normalized (with [page:Vector3.normalize]) for the methods to operate
-		properly.<br /><br />
+		[page:Vector3 origin] - [page:Ray](射线)的[page:.origin origin](原点)。<br />
+		[page:Vector3 origin] - [page:Ray](射线)的[page:.direction direction](方向)。
+		
+		该向量必须经过标准化(使用[page:Vector3.normalize]),这样才能使方法正常运行。
+		<br /><br />
 
-		Copy the parameters to the [page:.origin origin] and [page:.direction direction] properties
-		of this ray.
+		将传入的参数赋值给射线的[page:.origin origin]和[page:.direction direction]。
 		</p>
 
 
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 39 - 43
docs/api/zh/math/Sphere.html

@@ -8,131 +8,127 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		<h1>[name]</h1>
+		<h1>球([name]</h1>
 
-		<p class="desc">A sphere defined by a center and radius.</p>
+		<p class="desc">一个球由球心和半径所定义。</p>
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 		<h3>[name]( [param:Vector3 center], [param:Float radius] )</h3>
 		<p>
-		[page:Vector3 center] - center of the sphere. Default is a [page:Vector3] at (0, 0, 0). <br />
-		[page:Float radius] - radius of the sphere. Default is 0.<br /><br />
+		[page:Vector3 center] - 球心的位置,默认值是一个位于(0, 0, 0)的[page:Vector3]。<br />
+		[page:Float radius] - 球的半径,默认值是0。<br /><br />
 
-		Creates a new [name].
+		创建一个新的[name]。
 
 		</p>
 
 
-		<h2>Properties</h2>
+		<h2>属性</h2>
 
 
 		<h3>[property:Vector3 center]</h3>
-		<p>A [page:Vector3] defining the center of the sphere. Default is (0, 0, 0).</p>
+		<p>A [page:Vector3]定义了球心的位置,默认值位于(0, 0, 0)。</p>
 
 		<h3>[property:Float radius]</h3>
-		<p>The radius of the sphere. Default is 0.</p>
+		<p>球的半径,默认值为0。</p>
 
-		<h2>Methods</h2>
+		<h2>方法</h2>
 
 		<h3>[method:Sphere applyMatrix4]( [param:Matrix4 matrix] )</h3>
 		<p>
-			[page:Matrix4 matrix] - the [Page:Matrix4] to apply <br /><br />
+			[page:Matrix4 matrix] - 将被应用的[Page:Matrix4]矩阵。<br /><br />
 
-			Transforms this sphere with the provided [page:Matrix4].
+			使用所传入的[page:Matrix4]矩阵来对球进行变换。
 		</p>
 
 		<h3>[method:Vector3 clampPoint]( [param:Vector3 point], [param:Vector3 target] )</h3>
 		<p>
-		[page:Vector3 point] - [page:Vector3] The point to clamp.<br />
-		[page:Vector3 target] — the result will be copied into this Vector3.<br /><br />
+		[page:Vector3 point] - [page:Vector3] 将要夹取的点。<br />
+		[page:Vector3 target] — 结果将被复制到这个Vector3中。<br /><br />
 
-		Clamps a point within the sphere. If the point is is outside the sphere, it will clamp it to the
-		closets point on the edge of the sphere. Points already inside the sphere will not be affected.
+		从球中夹取一个点。若这一点位于球外,则将会夹取到该点球边缘最近的点。已位于球中的点将不会受到影响。
 		</p>
 
 		<h3>[method:Sphere clone]()</h3>
-		<p>Returns a new sphere with the same [page:.center center] and [page:.radius radius] as this one.</p>
+		<p>返回一个新的球,新的球与这个球具有相同的[page:.center center]和[page:.radius radius]。</p>
 
 		<h3>[method:Boolean containsPoint]( [param:Vector3 point] )</h3>
 		<p>
 		[page:Vector3 point] - the [page:Vector3] to be checked<br /><br />
 
-		Checks to see if the sphere contains the provided [page:Vector3 point] inclusive of the
-		surface of the sphere.
+		检查球体中是否包含所传入的[page:Vector3 point]点,包括球的表面。
 		</p>
 
 		<h3>[method:Sphere copy]( [param:Sphere sphere] )</h3>
 		<p>
-		Copies the values of the passed sphere's [page:.center center] and [page:.radius radius]
-		properties to this sphere.
+		复制所传入的球的[page:.center center]和[page:.radius radius]到这个球上。
 		</p>
 
 		<h3>[method:Float distanceToPoint]( [param:Vector3 point] )</h3>
 		<p>
-		Returns the closest distance from the boundary of the sphere to the [page:Vector3 point]. If the sphere contains the point,
-		the distance will be negative.
+		返回球的边界到所传入的[page:Vector3 point]点的最近距离。
+		若这个点,则距离将为负值。
 		</p>
 
 		<h3>[method:Boolean empty]()</h3>
-		<p>Checks to see if the sphere is empty (the radius set to 0).</p>
+		<p>检查球是否为空(其半径设为了0).</p>
 
 		<h3>[method:Boolean equals]( [param:Sphere sphere] )</h3>
 		<p>
-		Checks to see if the two spheres' centers and radii are equal.
+		检查这两个球的球心与半径是否相等。
 		</p>
 
 		<h3>[method:Box3 getBoundingBox]( [param:Box3 target] )</h3>
 		<p>
-		[page:Box3 target] — the result will be copied into this Box3.<br /><br />
+		[page:Box3 target] — 结果将被复制到这个Box3中。<br /><br />
 
-		Returns a[link:https://en.wikipedia.org/wiki/Minimum_bounding_box Minimum Bounding Box] for the sphere.
+		返回这个球的[link:https://en.wikipedia.org/wiki/Minimum_bounding_box Minimum Bounding Box](最小包围盒)。
 		</p>
 
 		<h3>[method:Boolean intersectsBox]( [param:Box3 box] )</h3>
 		<p>
-		[page:Box3 box] - [page:Box3] to check for intersection against.<br /><br />
+		[page:Box3 box] - 将被用于测试是否与这个球有交集的[page:Box3]。<br /><br />
 
-		Determines whether or not this sphere intersects a given [page:Box3 box].
+		检测这个球与所传入的[page:Box3 box]是否有交集。
 		</p>
 
 		<h3>[method:Boolean intersectsPlane]( [param:Plane plane] )</h3>
 		<p>
-		[page:Plane plane] - Plane to check for intersection against.<br /><br />
+		[page:Plane plane] - 将被用于测试是否与这个球有交集的Plane。<br /><br />
 
-		Determines whether or not this sphere intersects a given [page:Plane plane].
+		检测这个球与所传入的[page:Plane plane]是否有交集。
 		</p>
 
 		<h3>[method:Boolean intersectsSphere]( [param:Sphere sphere] )</h3>
 		<p>
-		[page:Sphere sphere] - Sphere to check for intersection against.<br /><br />
+		[page:Sphere sphere] - 将被用于测试是否与这个球有交集的Sphere。<br /><br />
 
-		Checks to see if two spheres intersect.
+		检测两球之间是否有交集。
 		</p>
 
 		<h3>[method:Sphere set]( [param:Vector3 center], [param:Float radius] )</h3>
 		<p>
-			[page:Vector3 center] - center of the sphere.<br />
-			[page:Float radius] - radius of the sphere.<br /><br />
+			[page:Vector3 center] - 球心位置。<br />
+			[page:Float radius] - 球的半径。<br /><br />
 
-		Sets the [page:.center center] and [page:.radius radius] properties of this sphere.
+		设置球的[page:.center center]和[page:.radius radius]属性。
 		</p>
 
 		<h3>[method:Sphere setFromPoints]( [param:Array points], [param:Vector3 optionalCenter] )</h3>
 		<p>
-		[page:Array points] - an [page:Array] of [page:Vector3] positions.<br />
-		[page:Vector3 optionalCenter] - Optional [page:Vector3] position for the sphere's center.<br /><br />
+		[page:Array points] - 一个包含有[page:Vector3]位置的[page:Array]。<br />
+		[page:Vector3 optionalCenter] - 可选, [page:Vector3] 球心位置。<br /><br />
 
-		Computes the minimum bounding sphere for an array of [page:Array points]. If  [page:Vector3 optionalCenter]is given,
-		it is used as the sphere's center. Otherwise, the center of the axis-aligned bounding box encompassing
-		[page:Array points] is calculated.
+		计算一个[page:Array points]数组(中的点)的最小边界球。如果给定了[page:Vector3 optionalCenter],则它将被用作该球的球心;
+		否则,环绕[page:Array points]的包围盒的轴心将通过计算来得到。
 		</p>
 
 		<h3>[method:Sphere translate]( [param:Vector3 offset] )</h3>
 		<p>
-		Translate the sphere's center by the provided offset [page:Vector3].
+		使用所给定[page:Vector3] offset(偏移量)平移球心。
 		</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 38 - 41
docs/api/zh/math/Triangle.html

@@ -8,135 +8,132 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		<h1>[name]</h1>
+		<h1>三角形([name]</h1>
 
 		<p class="desc">
-			A geometric triangle as defined by three [page:Vector3 Vector3s] representing its
-			three corners.
+			一个三角形由三个表示其三个角的[page:Vector3 Vector3]所定义。
 		</p>
 
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]( [param:Vector3 a], [param:Vector3 b], [param:Vector3 c] )</h3>
 		<p>
-		[page:Vector3 a] - the first corner of the triangle. Default is a [page:Vector3] at (0, 0, 0).<br />
-		[page:Vector3 b] - the second corner of the triangle. Default is a [page:Vector3] at (0, 0, 0).<br />
-		[page:Vector3 c] - the final corner of the triangle. Default is a [page:Vector3] at (0, 0, 0).<br /><br />
+		[page:Vector3 a] - 三角形的第一个角,默认值是一个在(0, 0, 0)处的[page:Vector3]。<br />
+		[page:Vector3 b] - 三角形的第二个角,默认值是一个在(0, 0, 0)处的[page:Vector3]。<br />
+		[page:Vector3 c] - 三角形的第三个角(最后一个角),默认值是一个在(0, 0, 0)处的[page:Vector3]。<br /><br />
 
-		Creates a new [name].
+		创建一个新的[name]。
 		</p>
 
 
-		<h2>Properties</h2>
+		<h2>属性</h2>
 
 		<h3>[property:Vector3 a]</h3>
 		<p>
-			The first corner of the triangle. Default is a [page:Vector3] at (0, 0, 0).
+			三角形的第一个角,默认值是一个在(0, 0, 0)处的[page:Vector3]。
 		</p>
 
 		<h3>[property:Vector3 b]</h3>
 		<p>
-			The second corner of the triangle. Default is a [page:Vector3] at (0, 0, 0).
+			三角形的第二个角,默认值是一个在(0, 0, 0)处的[page:Vector3]。
 		</p>
 
 		<h3>[property:Vector3 c]</h3>
 		<p>
-		the final corner of the triangle. Default is a [page:Vector3] at (0, 0, 0)
+			三角形的第三个角(最后一个角),默认值是一个在(0, 0, 0)处的[page:Vector3]。
 		</p>
 
-		<h2>Methods</h2>
+		<h2>方法</h2>
 
 		<h3>[method:Triangle clone]()</h3>
 		<p>
-			Returns a new triangle with the same [page:.a a], [page:.b b] and  [page:.c c] properties as this one.
+			返回一个和该三角形具有相同[page:.a a]、[page:.b b]和[page:.c c]属性的新三角形。
 		</p>
 
 		<h3>[method:Vector3 closestPointToPoint]( [param:Vector3 point], [param:Vector3 target] )</h3>
 		<p>
 		[page:Vector3 point] - [page:Vector3] <br />
-		[page:Vector3 target] — the result will be copied into this Vector3.<br /><br />
+		[page:Vector3 target] — 结果将被拷贝到这一Vector3中。<br /><br />
 
-		Returns the closest point on the triangle to [page:Vector3 point].
+		返回三角形上最靠近所给定的[page:Vector3 point]的点。
 		</p>
 
 		<h3>[method:Boolean containsPoint]( [param:Vector3 point] )</h3>
 		<p>
-		[page:Vector3 point] - [page:Vector3] to check.<br /><br />
+		[page:Vector3 point] - 将被检测的[page:Vector3]。<br /><br />
 
-		Returns true if the passed point, when projected onto the plane of the triangle, lies within the triangle.
+		如果传入的点投影到三角形的平面内,则返回true。
 		</p>
 
 		<h3>[method:Triangle copy]( [param:Triangle triangle] )</h3>
 		<p>
-			Copies the values of the passed triangles's [page:.a a], [page:.b b] and [page:.c c]
-			properties to this triangle.
+			将传入的三角形的[page:.a a]、[page:.b b]和[page:.c c]属性复制给这一三角形。
 		</p>
 
 		<h3>[method:Boolean equals]( [param:Triangle triangle] )</h3>
 		<p>
-		Returns true if the two triangles have identical [page:.a a], [page:.b b] and [page:.c c] properties.
+			若这两个三角形具有相同的[page:.a a]、[page:.b b]和[page:.c c]属性,则返回true。
 		</p>
 
 		<h3>[method:Float getArea]()</h3>
-		<p>Return the area of the triangle.</p>
+		<p>返回三角形的面积。</p>
 
 		<h3>[method:Vector3 getBarycoord]( [param:Vector3 point], [param:Vector3 target] )</h3>
 		<p>
 		[page:Vector3 point] - [page:Vector3] <br />
-		[page:Vector3 target] — the result will be copied into this Vector3.<br /><br />
+		[page:Vector3 target] — 结果将会被拷贝到这一Vector3中。<br /><br />
 
-		Return a [link:https://en.wikipedia.org/wiki/Barycentric_coordinate_system barycentric coordinate]
-		 from the given vector. <br/><br/>
+		从给定的向量中返回一个[link:https://en.wikipedia.org/wiki/Barycentric_coordinate_system barycentric coordinate](重心坐标)。<br/><br/>
 
-		[link:http://commons.wikimedia.org/wiki/File:Barycentric_coordinates_1.png Picture of barycentric coordinates]
+		请参阅关于这一概念的相关图片:[link:http://commons.wikimedia.org/wiki/File:Barycentric_coordinates_1.png Picture of barycentric coordinates]
 		</p>
 
 		<h3>[method:Vector3 getMidpoint]( [param:Vector3 target] )</h3>
 		<p>
-		[page:Vector3 target] — the result will be copied into this Vector3.<br /><br />
+		[page:Vector3 target] — 结果将会被拷贝到这一Vector3中。<br /><br />
 
-		Calculate the midpoint of the triangle.
+		计算三角形的中点。
 		</p>
 
 		<h3>[method:Vector3 getNormal]( [param:Vector3 target] )</h3>
 		<p>
-		[page:Vector3 target] — the result will be copied into this Vector3.<br /><br />
+		[page:Vector3 target] — 结果将会被拷贝到这一Vector3中。<br /><br />
 
-		Calculate the [link:https://en.wikipedia.org/wiki/Normal_(geometry) normal vector] of the triangle.
+		计算三角形的法向量([link:https://en.wikipedia.org/wiki/Normal_(geometry) normal vector])。
 		</p>
 
 		<h3>[method:Plane getPlane]( [param:Plane target] )</h3>
 		<p>
-		[page:Vector3 target] — the result will be copied into this Plane.<br /><br />
+		[page:Vector3 target] — 结果将会被拷贝到这一Plane中。<br /><br />
 
-		Calculate a [page:Plane plane] based on the triangle. .
+		基于三角形计算出一个平面([page:Plane plane])。
 		</p>
 
 		<h3>[method:Boolean intersectsBox]( [param:Box3 box] )</h3>
 		<p>
-		[page:Box3 box] - Box to check for intersection against.<br /><br />
+		[page:Box3 box] - 将被用于检测是否与三角形有交集的box。<br /><br />
 
-		Determines whether or not this triangle intersects [page:Box3 box].
+		判定三角形与传入的[page:Box3 box]是否相交。
 		</p>
 
 		<h3>[method:Triangle set]( [param:Vector3 a], [param:Vector3 b], [param:Vector3 c] ) [param:Triangle this]</h3>
 		<p>
-		Sets the triangle's [page:.a a], [page:.b b] and [page:.c c] properties to the passed [page:vector3 vector3s].
+			将三角形的[page:.a a]、[page:.b b]和[page:.c c]属性设置为所传入的[page:vector3 vector3]。
 		</p>
 
 		<h3>[method:Triangle setFromPointsAndIndices]( [param:Array points], [param:Integer i0], [param:Integer i1], [param:Integer i2] ) [param:Triangle this]</h3>
 		<p>
-		points - [page:Array] of [page:Vector3]s <br />
-		i0 - [page:Integer] index <br />
-		i1 - [page:Integer] index <br />
-		i2 - [page:Integer] index<br /><br />
+		points - [page:Vector3]数组([page:Array]) <br />
+		i0 - 整数([page:Integer])索引 <br />
+		i1 - 整数([page:Integer])索引 <br />
+		i2 - 整数([page:Integer])索引<br /><br />
 
-		Sets the triangle's vectors to the vectors in the array.
+		设置三角形的向量为数组中的向量。
 		</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>

+ 1 - 1
docs/api/zh/math/Vector2.html

@@ -343,4 +343,4 @@
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
 	</body>
-</html>
+</html>

+ 41 - 23
docs/api/zh/objects/SkinnedMesh.html

@@ -38,41 +38,60 @@
 		<h2>示例</h2>
 
 		<code>
-		var geometry = new THREE.CylinderGeometry( 5, 5, 5, 5, 15, 5, 30 );
+		var geometry = new THREE.CylinderBufferGeometry( 5, 5, 5, 5, 15, 5, 30 );
 
-		//Create the skin indices and skin weights
-		for ( var i = 0; i < geometry.vertices.length; i ++ ) {
+		// create the skin indices and skin weights
 
-			// Imaginary functions to calculate the indices and weights
-			// This part will need to be changed depending your skeleton and model
-			var skinIndex = calculateSkinIndex( geometry.vertices, i );
-			var skinWeight = calculateSkinWeight( geometry.vertices, i );
+		var position = geometry.attributes.position;
 
-			// Ease between each bone
-			geometry.skinIndices.push( new THREE.Vector4( skinIndex, skinIndex + 1, 0, 0 ) );
-			geometry.skinWeights.push( new THREE.Vector4( 1 - skinWeight, skinWeight, 0, 0 ) );
+		var vertex = new THREE.Vector3();
+
+		var skinIndices = [];
+		var skinWeights = [];
+
+		for ( var i = 0; i < position.count; i ++ ) {
+
+			vertex.fromBufferAttribute( position, i );
+
+			// compute skinIndex and skinWeight based on some configuration data
+
+			var y = ( vertex.y + sizing.halfHeight );
+
+			var skinIndex = Math.floor( y / sizing.segmentHeight );
+			var skinWeight = ( y % sizing.segmentHeight ) / sizing.segmentHeight;
+
+			skinIndices.push( skinIndex, skinIndex + 1, 0, 0 );
+			skinWeights.push( 1 - skinWeight, skinWeight, 0, 0 );
 
 		}
 
+		geometry.addAttribute( 'skinIndex', new THREE.Uint16BufferAttribute( skinIndices, 4 ) );
+		geometry.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( skinWeights, 4 ) );
+
+		// create skinned mesh and skeleton
+
 		var mesh = new THREE.SkinnedMesh( geometry, material );
+		var skeleton = new THREE.Skeleton( bones );
 
-		// See example from THREE.Skeleton for the armSkeleton
-		var rootBone = armSkeleton.bones[ 0 ];
+		// see example from THREE.Skeleton
+
+		var rootBone = skeleton.bones[ 0 ];
 		mesh.add( rootBone );
 
-		// Bind the skeleton to the mesh
-		mesh.bind( armSkeleton );
+		// bind the skeleton to the mesh
+
+		mesh.bind( skeleton );
+
+		// move the bones and manipulate the model
 
-		// Move the bones and manipulate the model
-		armSkeleton.bones[ 0 ].rotation.x = -0.1;
-		armSkeleton.bones[ 1 ].rotation.x = 0.2;
+		skeleton.bones[ 0 ].rotation.x = -0.1;
+		skeleton.bones[ 1 ].rotation.x = 0.2;
 		</code>
 
 		<h2>构造器</h2>
-		<h3>[name]( [param:Geometry geometry], [param:Material material] )</h3>
+		<h3>[name]( [param:BufferGeometry geometry], [param:Material material] )</h3>
 		<p>
-    [page:Geometry geometry] —— 一个[page:Geometry]或者[page:BufferGeometry](推荐)的实例。
-	[page:Geometry.skinIndices skinIndices] 和 [page:Geometry.skinWeights skinWeights] 在几何体上应当被设置为true。<br />
+    [page:BufferGeometry geometry] —— TODO<br />
     [page:Material material] —— (可选)一个[page:Material]的实例,默认值是一个新的[page:MeshBasicMaterial]。
 		</p>
 
@@ -108,7 +127,7 @@
 
 		<h3>[property:Skeleton skeleton]</h3>
 		<p>
-			[page:Skeleton]是由从构造函数中传入的[page:Geometry]中的[page:Geometry.bones bones]来创建的。
+			TODO
 		</p>
 
 
@@ -121,7 +140,6 @@
 		[page:Skeleton skeleton] —— 由一棵[page:Bone Bones]树创建的[page:Skeleton]。<br/>
 		[page:Matrix4 bindMatrix] —— 代表着骨架基本变换的[page:Matrix4](4x4矩阵)。<br /><br />
 		将骨架绑定到一个蒙皮网格上。bindMatrix会被保存到.bindMatrix属性中,其逆矩阵.bindMatrixInverse也会被计算出来。
-		它在构造函数中会被自动调用,其骨架是由传入到构造函数的[page:Geometry]中的[page:Geometry.bones bones]来创建的。
 		</p>
 
 		<h3>[method:SkinnedMesh clone]()</h3>
@@ -131,7 +149,7 @@
 
 		<h3>[method:null normalizeSkinWeights]()</h3>
 		<p>
-		规范化[page:Geometry.skinWeights]矢量。不会对[page:BufferGeometry]产生影响。
+		TODO
 		</p>
 
 		<h3>[method:null pose]()</h3>

+ 2 - 2
docs/manual/en/introduction/Browser-support.html

@@ -13,7 +13,7 @@
 	<h2>Overview</h2>
 	<div>
 		<p>
-			Three.js can use WebGL to render your scenes on all modern browsers. For older browsers, especially Internet Explorer 10 and below, you may have to fallback to one of the other [link:https://github.com/mrdoob/three.js/tree/master/examples/js/renderers renderers] (CSS2DRenderer, CSS3DRenderer, SVGRenderer, CanvasRenderer). Additionally, you may have to include some polyfills, especially if you are using files from the [link:https://github.com/mrdoob/three.js/tree/master/examples /examples] folder.
+			Three.js can use WebGL to render your scenes on all modern browsers. For older browsers, especially Internet Explorer 10 and below, you may have to fallback to one of the other [link:https://github.com/mrdoob/three.js/tree/master/examples/js/renderers renderers] (CSS2DRenderer, CSS3DRenderer, SVGRenderer). Additionally, you may have to include some polyfills, especially if you are using files from the [link:https://github.com/mrdoob/three.js/tree/master/examples /examples] folder.
 		</p>
 		<p>
 			Note: if you don't need to support these old browsers, then it is not recommended to use the other renderers as they are slower and support less features than the WebGLRenderer.
@@ -120,4 +120,4 @@
 		</ul>
 	</div>
 </body>
-</html>
+</html>

+ 3 - 2
docs/manual/en/introduction/Loading-3D-models.html

@@ -55,13 +55,14 @@
 	</p>
 
 	<ul>
-		<li><a href="https://github.com/KhronosGroup/glTF-Blender-Exporter" target="_blank" rel="noopener">glTF-Blender-Exporter</a> by the Khronos Group</li>
+		<li><a href="https://github.com/KhronosGroup/glTF-Blender-IO" target="_blank" rel="noopener">glTF-Blender-IO</a> by the Khronos Group</li>
 		<li><a href="https://github.com/KhronosGroup/COLLADA2GLTF" target="_blank" rel="noopener">COLLADA2GLTF</a> by the Khronos Group</li>
 		<li><a href="https://github.com/facebookincubator/FBX2glTF" target="_blank" rel="noopener">FBX2GLTF</a> by Facebook</li>
 		<li><a href="https://github.com/AnalyticalGraphicsInc/obj2gltf" target="_blank" rel="noopener">OBJ2GLTF</a> by Analytical Graphics Inc</li>
 		<li><a href="https://www.allegorithmic.com/products/substance-painter" target="_blank" rel="noopener">Substance Painter</a> by Allegorithmic</li>
 		<li><a href="https://www.foundry.com/products/modo" target="_blank" rel="noopener">Modo</a> by Foundry</li>
 		<li><a href="https://www.marmoset.co/toolbag/" target="_blank" rel="noopener">Toolbag</a> by Marmoset</li>
+		<li><a href="https://www.sidefx.com/products/houdini/" target="_blank" rel="noopener">Houdini</a> by SideFX</li>
 		<li>&hellip;and <a href="https://github.com/khronosgroup/gltf#gltf-tools" target="_blank" rel="noopener">many more</a></li>
 	</ul>
 
@@ -96,7 +97,7 @@
 	<p>
 		Currently three.js examples are not available as ES modules (import &hellip; from '&hellip;').
 		Several workarounds are discussed in
-		<a href="https://github.com/KhronosGroup/glTF/issues/9562" target="_blank" rel="noopener">#9562</a>.
+		<a href="https://github.com/mrdoob/three.js/issues/9562" target="_blank" rel="noopener">#9562</a>.
 	</p>
 
 	<p>

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

@@ -103,7 +103,7 @@
 				maintained as part of the three.js repository, and always use the latest version of three.js.
 			</li>
 			<li>
-				[link:https://rawgit.com/mrdoob/three.js/dev/examples/ Official three.js dev branch examples]  -
+				[link:https://raw.githack.com/mrdoob/three.js/dev/examples/ Official three.js dev branch examples]  -
 				Same as the above, except these use the dev branch of three.js,	and are used to check that
 				everything is working as three.js being is developed.
 			</li>
@@ -126,7 +126,7 @@
 			[link:http://idflood.github.io/ThreeNodes.js/ ThreeNodes.js].
 		</li>
 	 </ul>
-		
+
 	<h2>WebGL References</h2>
 	 <ul>
 		 <li>
@@ -142,7 +142,7 @@
 
 	 <ul>
 		<li>
-			<a href="https://www.youtube.com/watch?v=Dir4KO9RdhM">AlterQualia at WebGL Camp 3</a>
+			<a href="https://www.youtube.com/watch?v=Dir4KO9RdhM" target="_blank">AlterQualia at WebGL Camp 3</a>
 		</li>
 		<li>
 			[link:http://yomotsu.github.io/threejs-examples/ Yomotsus Examples] - a collection of examples using three.js r45.
@@ -157,7 +157,7 @@
 			[link:http://bkcore.com/blog/general/adobe-user-group-nl-talk-video-hexgl.html Fast HTML5 game development using three.js] by [link:https://github.com/BKcore BKcore] (video).
 		</li>
 		<li>
-			<a href="http://www.youtube.com/watch?v=VdQnOaolrPA">Trigger Rally</a>  by [link:https://github.com/jareiko jareiko] (video).
+			<a href="https://www.youtube.com/watch?v=VdQnOaolrPA" target="_blank">Trigger Rally</a>  by [link:https://github.com/jareiko jareiko] (video).
 		</li>
 		<li>
 			[link:http://blackjk3.github.io/threefab/ ThreeFab] - scene editor, maintained up until around three.js r50.

+ 60 - 69
docs/manual/zh/buildTools/Testing-with-NPM.html

@@ -8,69 +8,67 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		<h1>[name]</h1>
+		<h1>使用NPM进行测试([name]</h1>
 
 		<p class="desc">
-			This article shows how to get three.js into a [link:https://nodejs.org/en/ node.js] environment so that you
-			can execute automated tests. Tests can be run on the command line, or by automated
-			CI tools like [link:https://travis-ci.org/ Travis].
+			这篇文章展示了如何将three.js置入[link:https://nodejs.org/en/ node.js]环境中,
+			这样你就可以执行自动化测试了。测试可以通过命令行或者类似[link:https://travis-ci.org/ Travis]的CI工具来运行。
 		</p>
 
-		<h2>The short version</h2>
+		<h2>一句话概括</h2>
 
 		<p>
-			If you're comfortable with node and npm,
+			如果你习惯使用node和npm,
 			<code>
 				$ npm install three --save-dev
 			</code>
-			and add
+			并将
 		<code>
 			var THREE = require('three');
 		</code>
-			to your test.
+			添加到你的测试中。
 		</p>
 
-		<h2>Create a testable project from scratch</h2>
+		<h2>从头创建一个可测试的项目</h2>
 		<p>
-			If you're not familiar with these tools, here's a quick guide (for linux, the installation process
-			will be slightly different using windows, but the NPM commands are identical).
+			如果你不太熟悉这些工具,下面是一个快速入门。(基于linux,在windows上的安装过程会稍稍有点不一样,不过NPM指令是相同的。)
 		</p>
 
-		<h3>Basic setup</h3>
+		<h3>基本设置</h3>
 		<div>
 			<ol>
 				<li>
-					Install [link:https://www.npmjs.org/ npm] and nodejs. The shortest path typically looks something like
+					安装[link:https://www.npmjs.org/ npm]和nodejs。最简单的方式一般像这样
 					<code>
 $ sudo apt-get install -y npm nodejs-legacy
-# fix any problems with SSL in the default registry URL
+# 修复默认registry URL中任何SSL的问题
 $ npm config set registry http://registry.npmjs.org/
 					</code>
 				</li>
 
 				<li>
-					Make a new project directory
+					新建一个项目路径
 					<code>
 						 $ mkdir test-example; cd test-example
 					</code>
 				</li>
 
 				<li>
-					Ask npm to create a new project file for you:
+					让npm为你创建一份新的项目文件:
 					<code>
 					 $ npm init
 					</code>
-					 and accept all defaults by hitting Enter on all the prompts.
-					 This will create package.json.
+					 在所有出现的提示中敲击回车键来接受默认值。
+					 这样,一份package.json就建立好了。
 				</li><br />
 
 				<li>
-					Try and start the test feature with
+					尝试启动测试功能
 					<code>
 $ npm test
 					</code>
-					This will fail, which is expected.
-					If you look in the package.json, the definition of the test script is
+					当然,这一定会失败。
+					如果你检查一下package.json,test script的定义是这样的
 					<code>
 						"test": "echo \"Error: no test specified\" && exit 1"
 					</code>
@@ -79,78 +77,75 @@ $ npm test
 			</ol>
 		</div>
 
-		<h2>Add mocha</h2>
+		<h2>添加mocha</h2>
 		<div>
-			We're going to use [link:https://mochajs.org/ mocha].
+			我们将使用[link:https://mochajs.org/ mocha]。
 
 			<ol>
 				<li>
-					Install mocha with
+					安装mocha
 					<code>
 $ npm install mocha --save-dev
 					</code>
-					Notice that node_modules/ is created and your dependencies appear in there.
-				  Also notice that your package.json has been updated: the property devDependencies
-					is added and updated by the use of --save-dev.
+					你会注意到 node_modules/ 被创建了,并且你的依赖都出现在了这里面。
+					还有你的package.json被更新了,--save-dev指令向其中加入并更新了devDependencies属性。
 				</li><br />
 
 				<li>
-					Edit package.json to use mocha for testing. When test is invoked, we just want to run
-					mocha and specify a verbose reporter. By default this will run anything in test/
-					(not having directory test/ can run into npm ERR!, create it by mkdir test)
+					编辑package.json来使用mocha进行测试。当调用测试的时候,我们只想运行mocha并且生成一份详细的报告。
+					默认情况下这会运行 test/ 中的任何东西。
+					(如果项目中没有 test/ 目录的话,会导致npm报错。你可以通过mkdir test来创建这个目录)
 					<code>
 						"test": "mocha --reporter list"
 					</code>
 				</li>
 
 				<li>
-					Rerun the test with
+					重新运行测试
 					<code>
 						$ npm test
 					</code>
 
-					This should now succeed, reporting 0 passing (1ms)
-				 	or similar.
+					现在应该就能成功执行了,生成类似 0 passing (1ms) 的报告。
 				</li>
 
 			</ol>
 		</div>
 
-		<h2>Add three.js</h2>
+		<h2>添加three.js</h2>
 		<div>
 			<ol>
 				<li>
-					Let's pull in our three.js dependency with
+					现在添加我们的three.js依赖
 					<code>
 $ npm install three --save-dev
 					</code>
 					<ul>
 						<li>
-							If you need a different three version, use
+							如果你需要three.js的其他版本,使用
 							<code>
 								$ npm show three versions
 							</code>
-						  to see
-							what's available. To tell npm the right one, use
+						  	来确认哪些是可用的。要让npm使用正确的版本,执行
 							<code>
  $ npm install [email protected] --save
 							</code>
-							(0.84.0 in this example). --save makes this a dependency of this project, rather than
-							dev dependency. See the docs [link:https://www.npmjs.org/doc/json.html here] for more info.
+							(例子中用的是0.84.0)。 --save 指令将此加入项目的dependency而不是dev dependency。
+							更多信息请参阅<a href="https://www.npmjs.org/doc/json.html">这份文档</a>。
 						</li>
 					</ul>
 				</li>
 
 				<li>
-					Mocha will look for tests in test/, so let's
+					Mocha会在 test/ 目录中寻找测试文件,所以我们先创建这个目录:
 					<code>
 					$ mkdir test
 					</code>
 				</li>
 
 				<li>
-					Finally we actually need a JS test to run. Let's add a simple test that will verify that
-					the three.js object is available and working. Create test/verify-three.js containing:
+					最后我们需要一份JS测试文件来运行。我们就添加一段简单的测试程序,这段程序会检验three.js对象是否能正常工作。
+					在 test/ 目录下创建verify-three.js包含以下代码:
 <code>
 var THREE = require('three');
 var assert = require("assert");
@@ -169,8 +164,7 @@ describe('The THREE object', function() {
 				</li>
 
 				<li>
-				Finally let's test again with $ npm test. This should run the tests above and succeed,
-				showing something like:
+				最后再次通过$ npm test来测试。这次应该能正确执行上面的代码,并且返回类似:
 				<code>
 The THREE object should have a defined BasicShadowMap constant: 0ms
 The THREE object should be able to construct a Vector3 with default of x=0: 0ms
@@ -180,33 +174,33 @@ The THREE object should be able to construct a Vector3 with default of x=0: 0ms
 			</ol>
 		</div>
 
-		<h2>Add your own code</h2>
+		<h2>加入你自己的代码</h2>
 		<div>
-			You need to do three things:
+			你需要做下面三件事:
 
 			<ol>
 				<li>
-					Write a test for the expected behaviour of your code, and place it under test/.
-					[link:https://github.com/air/encounter/blob/master/test/Physics-test.js Here] is an example from a real project.
+					为你的代码写一段测试程序来检验期望结果,并把它放在 test/ 目录下。
+					<a href="https://github.com/air/encounter/blob/master/test/Physics-test.js">这里</a>有一个实际项目的例子。
 				</li>
 
 				<li>
-					Export your functional code in such a way that nodejs can see it, for use in conjunction with require.
-					See it [link:https://github.com/air/encounter/blob/master/js/Physics.js here].
+					将你的代码以nodejs承认的方式导出,即可以通过require的方式引用。
+					参考<a href="https://github.com/air/encounter/blob/master/js/Physics.js">这份代码</a>。
 				</li>
 
 				<li>
-					Require your code into the test file, in the same way we did a require('three') in the example above.
+					在测试程序中通过require引入你自己的代码,就像上面例子中我们通过require('three')来引入一样。
 				</li>
 			</ol>
 
 			<p>
-				Items 2 and 3 will vary depending on how you manage your code. In the example of Physics.js
-		  	given above, the export part is right at the end. We assign an object to module.exports:
+				第2、3条会根据你组织代码的方式而改变。在上面给出的Physics.js的例子中,导出的部分在代码的最末尾。
+				我们将module.exports赋值为一个对象:
 			</p>
 			<code>
 //=============================================================================
-// make available in nodejs
+// 为了在nodejs中可用
 //=============================================================================
 if (typeof exports !== 'undefined')
 {
@@ -215,38 +209,35 @@ if (typeof exports !== 'undefined')
 			</code>
 		</div>
 
-		<h2>Dealing with dependencies</h2>
+		<h2>处理依赖</h2>
 		<div>
 			<p>
-				If you're already using something clever like require.js or browserify, skip this part.
+				如果你已经在使用require.js或者browserify之类的便捷工具,就跳过这个部分。
 			</p>
 			<p>
-				Typically a three.js project is going to run in the browser. Module loading is hence done by
-				the browser executing a bunch of script tags. Your individual files don't have to worry
-				about dependencies. In a nodejs context however, there is no index.html binding everything
-				together, so you have to be explicit.
+				一般来说,一个three.js项目将在浏览器中运行,浏览器会通过执行一系列script标签来加载模块。
+				你自己的文件不用考虑依赖的问题。然而在nodejs环境中,没有一个关联所有文件的index.html,所以你需要显式地加载。
 			</p>
 			<p>
-				If you're exporting a module that depends on other files, you're going to have to tell node to load them.
-				Here is one approach:
+				如果你要导出的模块还依赖其他文件,你需要告诉node去加载它们。下面是一种方式:
 			</p>
 			<ol>
 				<li>
-					At the start of your module, check to see if you're in a nodejs environment.
+					在你的模块顶部,检查是否处于nodejs环境中。
 				</li>
 				<li>
-					If so, explicitly declare your dependencies.
+					如果是,那就显式地声明你的依赖。
 				</li>
 				<li>
-					If not, you're probably in a browser so you don't need to do anything else.
+					如果不是,你多半处于浏览器环境中。这时候你不需要做任何多余操作。
 				</li>
 			</ol>
-			Example code from Physics.js:
+			用Physics.js中的代码举例:
 			<code>
 //=============================================================================
-// setup for server-side testing
+// 服务器端测试配置
 //=============================================================================
-if (typeof require === 'function') // test for nodejs environment
+if (typeof require === 'function') // 检测nodejs环境
 {
   var THREE = require('three');
   var MY3 = require('./MY3.js');

+ 49 - 53
docs/manual/zh/introduction/Animation-system.html

@@ -8,82 +8,79 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		<h1>[name]</h1>
+		<h1>动画系统([name]</h1>
 
-		<h2>Overview(概述)</h2>
+		<h2>概述</h2>
 
 		<p class="desc">
 			在three.js动画系统中,您可以为模型的各种属性设置动画:
-			[page:SkinnedMesh 蒙皮和装配模型]的骨头,[page:Geometry.morphTargets 变形目标],不同的材料属性(颜色,
-			不透明度,布尔运算),可见性和变换。 动画属性可以淡入,淡出,交叉淡化和扭曲。 不同时间的重量和时间尺度
-			可以更改同一对象以及不同对象上的动画独立。 可以在相同和不同对象上进行各种动画同步。
+			[page:SkinnedMesh](蒙皮和装配模型)的骨骼,[page:Geometry.morphTargets](变形目标),
+			不同的材料属性(颜色,不透明度,布尔运算),可见性和变换。动画属性可以淡入、淡出、交叉淡化和扭曲。
+			在相同或不同物体上同时发生的动画的权重和时间比例的变化可以独立地进行。
+			相同或不同物体的动画也可以同步发生。
 			<br /><br />
-			在一个同构系统中实现所有这一切,即three.js动画系统
-			[link:https://github.com/mrdoob/three.js/issues/6881在2015年彻底改变]
-			(注意过时的信息!),它现在有一个与Unity /虚幻引擎4类似的架构.此页面简要概述了主要组件系统以及它们如何协同工作。
+			为了在一个同构系统中实现所有这一切,
+			three.js的动画系统<a href="https://github.com/mrdoob/three.js/issues/6881">在2015年彻底改变</a>(注意过时的信息!),
+			它现在有一个与Unity/虚幻4引擎类似的架构。此页面简要阐述了这个系统中的主要组件以及它们如何协同工作。
 		</p>
 
-		<h3>Animation Clips(动画片段)</h3>
+		<h3>动画片段(Animation Clips)</h3>
 
 		<p class="desc">
-			如果您已成功导入动画3D对象(如果有,则无关紧要)
-			骨骼或变形目标或两者) - 例如使用[link:https://github.com/KhronosGroup/glTF-Blender-Exporter glTF Blender导出器]从Blender导出它
-			使用[page:GLTFLoader]将其加载到three.js场景中 - 其中一个响应字段应该是一个名为“animations”的数组,其中包含此模型的[page:AnimationClip AnimationClips](请参阅下面的可能加载器列表)。
+			如果您已成功导入3D动画对象(无论它是否有骨骼或变形目标或两者皆有都不要紧)——
+			例如使用<a href="https://github.com/KhronosGroup/glTF-Blender-Exporter">glTF Blender导出器</a>
+			从Blender导出它并使用[page:GLTFLoader]将其加载到three.js场景中
+			—— 其中一个响应字段应该是一个名为“animations”的数组,
+			其中包含此模型的[page:AnimationClip AnimationClips](请参阅下面可用的加载器列表)。
 			<br /><br />
-			每个* AnimationClip *通常保存对象的某个活动的数据。 如果
-			mesh是一个字符,例如,可以有一个用于walkcycle的动画片段,第二个
-			跳跃,三分之一的回避等等。
+			每个*AnimationClip*通常保存对象某个活动的数据。
+			举个例子,假如mesh是一个角色,可能有一个AnimationClip实现步行循环,
+			第二个AnimationClip实现跳跃,第三个AnimationClip实现闪避等等。
 		</p>
 
-		<h3>Keyframe Tracks(关键帧轨道)</h3>
+		<h3>关键帧轨道(Keyframe Tracks)</h3>
 
 		<p class="desc">
-			在这样的* AnimationClip *里面,每个动画属性的数据都存储在一个
-			单独[page:KeyframeTrack]。 假设一个角色对象有一个[page:Skeleton skeleton],
-			一个关键帧轨道可以存储下臂骨骼位置变化的数据
-			随着时间的推移,不同的轨道数据为同一骨骼的旋转变化,三分之一
-			轨道位置,旋转或缩放另一个骨骼,等等。 应该很清楚,
-			AnimationClip可以由许多这样的轨道组成。
-			.<br /><br />
-			假设模型具有[page:Geometry.morphTargets 变形目标](例如一个变形
-			目标显示一个友好的面孔,另一个显示愤怒的脸),每个轨道持有
-			关于某个变形的[page:Mesh.morphTargetInfluences 影响]的信息
-			目标在剪辑执行期间发生变化。
+			在这样的*AnimationClip*里面,每个动画属性的数据都存储在一个单独的[page:KeyframeTrack]中。
+			假设一个角色对象有[page:Skeleton](骨架),
+			一个关键帧轨道可以存储下臂骨骼位置随时间变化的数据,
+			另一个轨道追踪同一块骨骼的旋转变化,第三个追踪另外一块骨骼的位置、转角和尺寸,等等。
+			应该很清楚,AnimationClip可以由许多这样的轨道组成。
+			<br /><br />
+			假设模型具有[page:Geometry.morphTargets](变形目标)——
+			例如一个变形目标显示一个笑脸,另一个显示愤怒的脸 ——
+			每个轨道都持有某个变形目标在AnimationClip运行期间产生的[page:Mesh.morphTargetInfluences](变形目标影响)如何变化的信息。
 		</p>
 
-		<h3>Animation Mixer(动画混音器)</h3>
+		<h3>动画混合器(Animation Mixer)</h3>
 
 		<p class="desc">
-			存储的数据仅构成动画的基础 - 实际播放由控制
-			[page:AnimationMixer]。 你可以想象这不仅仅是动画的播放器,而是
-			作为硬件的模拟,如真正的调音台控制台,可以控制几个动画
-			同时,混合和合并它们。
+			存储的数据仅构成动画的基础 —— 实际播放由[page:AnimationMixer]控制。
+			你可以想象这不仅仅是动画的播放器,而是作为硬件的模拟,如真正的调音台,可以同时控制和混合若干动画。
 		</p>
 
-		<h3>Animation Actions</h3>
+		<h3>动画行为(Animation Actions</h3>
 
 		<p class="desc">
-			* AnimationMixer *本身只有很少(通用)属性和方法,因为它
-			可以通过[page:AnimationAction AnimationActions]来控制。 通过配置
-			* AnimationAction *您可以确定何时播放某个* AnimationClip *,暂停
-			或者停在其中一个混音器上,是否以及频率必须重复,无论是否
-			应使用淡入淡出或时间缩放以及一些其他内容(例如交叉渐变)来执行
-			或同步。
+			*AnimationMixer*本身只有很少的(大体上)属性和方法,
+			因为它可以通过[page:AnimationAction AnimationActions]来控制。
+			通过配置*AnimationAction*,您可以决定何时播放、暂停或停止其中一个混合器中的某个*AnimationClip*,
+			这个*AnimationClip*是否需要重复播放以及重复的频率,
+			是否需要使用淡入淡出或时间缩放,以及一些其他内容(例如交叉渐变和同步)。
 		</p>
 
-		<h3>Animation Object Groups(动画对象组)</h3>
+		<h3>动画对象组(Animation Object Groups)</h3>
 
 		<p class="desc">
-				如果您希望一组对象接收共享动画状态,则可以使用[page:AnimationObjectGroup].
-
+			如果您希望一组对象接收共享的动画状态,则可以使用[page:AnimationObjectGroup]。
 		</p>
 
-		<h3>Supported Formats and Loaders(支持的格式和加载器)</h3>
+		<h3>支持的格式和加载器(Supported Formats and Loaders)</h3>
 
 		<p class="desc">
-			请注意,并非所有模型格式都包含动画(尤其是OBJ,没有),而且只有一些
-			three.js加载器支持[page:AnimationClip AnimationClip]序列。 以下几个<i>确实</ i>
-			支持此动画类型:
+			请注意,并非所有模型格式都包含动画(尤其是OBJ,没有),
+			而且只有某些three.js加载器支持[page:AnimationClip AnimationClip]序列。
+			以下几个<i>确实</i>支持此动画类型:
 		</p>
 
 			<ul>
@@ -97,30 +94,29 @@
 			</ul>
 
 		<p class="desc">
-			请注意,3ds max和Maya当前无法导出多个动画(这意味着动画不是
-			在同一时间线上)直接到一个文件。
+			请注意,3ds max和Maya当前无法直接导出多个动画(这意味着动画不是在同一时间线上)到一个文件中。
 		</p>
 
-		<h2>Example</h2>
+		<h2>范例</h2>
 
 		<code>
 		var mesh;
 
-		// Create an AnimationMixer, and get the list of AnimationClip instances
+		// 新建一个AnimationMixer, 并取得AnimationClip实例列表
 		var mixer = new THREE.AnimationMixer( mesh );
 		var clips = mesh.animations;
 
-		// Update the mixer on each frame
+		// 在每一帧中更新mixer
 		function update () {
 			mixer.update( deltaSeconds );
 		}
 
-		// Play a specific animation
+		// 播放一个特定的动画
 		var clip = THREE.AnimationClip.findByName( clips, 'dance' );
 		var action = mixer.clipAction( clip );
 		action.play();
 
-		// Play all animations
+		// 播放所有动画
 		clips.forEach( function ( clip ) {
 			mixer.clipAction( clip ).play();
 		} );

+ 3 - 3
docs/manual/zh/introduction/Browser-support.html

@@ -13,14 +13,14 @@
 	<h2>总览</h2>
 	<div>
 		<p>
-            在所有现代浏览器中,Three.js可以使用WebGL来渲染场景。对于较旧的浏览器,特别是Internet Explorer 10或者更低版本浏览器,你将需要回落到其它[link:https://github.com/mrdoob/three.js/tree/master/examples/js/renderers renderers](CSS2DRenderer、CSS3DRenderer、SVGRenderer、CanvasRenderer)。此外,你或许不得不包含一些额外的“填充物”来解决兼容性问题,特别是当你使用[link:https://github.com/mrdoob/three.js/tree/master/examples /examples]目录中的文件时。
+            在所有现代浏览器中,Three.js可以使用WebGL来渲染场景。对于较旧的浏览器,特别是Internet Explorer 10或者更低版本浏览器,你将需要回落到其它[link:https://github.com/mrdoob/three.js/tree/master/examples/js/renderers renderers](CSS2DRenderer、CSS3DRenderer、SVGRenderer)。此外,你或许不得不包含一些额外的“填充物”来解决兼容性问题,特别是当你使用[link:https://github.com/mrdoob/three.js/tree/master/examples /examples]目录中的文件时。
 		</p>
 		<p>
             注意:如果你并不需要支持较旧的浏览器,那就不推荐使用其他渲染器来进行渲染,因为与WebGLRenderer相比,其它渲染器渲染较慢,并且不支持WebGL的诸多特性。
 		</p>
 	</div>
 
-	<h2>支持WebGL的渲染器</h2>
+	<h2>支持WebGL的浏览器</h2>
 	<div>
 		<p>
 			Google Chrome 9+、Firefox 4+、Opera 15+、Safari 5.1+、Internet Explorer 11 和 Microsoft Edge。你可以点击[link:https://caniuse.com/#feat=webgl Can I use WebGL]来查阅各个浏览器对WebGL的支持性。
@@ -32,7 +32,7 @@
         </h2>
 	<div>
 		<p>
-            这里是一些在Three.js中使用到的特性,其中的一部分需要额外的“填充物”来解决兼容性问题。
+            这里是一些在Three.js中使用到的特性,其中的一部分需要额外的“填充物”(Polyfills)来解决兼容性问题。
 		</p>
 		<table>
 			<thead>

+ 1 - 1
docs/manual/zh/introduction/Drawing-lines.html

@@ -11,7 +11,7 @@
 		<h1>画线([name])</h1>
 		<div>
 			<p>
-				假设你将要画一个圆或者画一条线,而不是一个线框,或者说不是一个[page:Mesh](网格)。
+				假设你将要画一个圆或者画一条线,而不是一个线框模型,或者说不是一个[page:Mesh](网格)。
 				第一步我们要做的,是设置好[page:WebGLRenderer renderer](渲染器)、[page:Scene scene](场景)和[page:Camera camera](相机)-(如果对这里所提到的东西,还不了解,请阅读本手册第一章“创建一个场景 - Creating a scene”)。
 			</p>
 

+ 5 - 6
docs/manual/zh/introduction/FAQ.html

@@ -10,14 +10,14 @@
 	<body>
 		<h1>常见问题([name])</h1>
 
-		<h2>哪一种三维物体格式能够得到最好地支持?</h2>
+		<h2>哪一种三维物体格式能够得到最好地支持?</h2>
 		<div>
 			<p>
-			推荐使用glTF(gl传输格式)来对三维物体进行导入和导出,由于glTF这种格式是专注于在程序运行时呈现三维物体的,所以它的传输效率非常高,且加载速度非常快。
+			推荐使用glTF(gl传输格式)来对三维物体进行导入和导出,由于glTF这种格式专注于在程序运行时呈现三维物体,因此它的传输效率非常高,且加载速度非常快。
 			</p>
 			
 			
-			<p>three.js同样也为其它广受欢迎的格式像FBX、Collada以及OBJ等等提供了载入工具。虽然如此,你应当还是首先尝试着在你的项目里建立一个基于glTF的工作流程。
+			<p>three.js同样也为其它广受欢迎的格式(例如FBX、Collada以及OBJ等)提供了载入工具。即便如此,你应当还是首先尝试着在你的项目中建立一个基于glTF的工作流程。
 				了解更多详细信息,请查看[link:#manual/introduction/Loading-3D-models loading 3D models]。
 			</p>
 		</div>
@@ -46,10 +46,9 @@ visible_height = 2 * Math.tan( ( Math.PI / 180 ) * camera.fov / 2 ) * distance_f
 
 		<h2>为什么我的物体的一部分是不可见的?</h2>
 		<p>
-			这可能是由于面消隐而导致的。面是具有朝向的,这个朝向决定了哪边是正面或者哪边是背面。
-			在正常情况下,渲染时会将背面进行消隐。要查看这是不是你所遇到的问题,请将material的slide更改为THREE.DoubleSide。
+			这可能是由于面剔除而导致的。面是具有朝向的,这个朝向决定了哪边是正面或者哪边是背面。
+			在正常情况下,渲染时会将背面进行剔除。要查看这是不是你所遇到的问题,请将material的side更改为THREE.DoubleSide。
 			<code>material.side = THREE.DoubleSide</code>
 		</p>
 	</body>
 </html>
-

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

@@ -117,62 +117,6 @@ ruby -r webrick -e "s = WEBrick::HTTPServer.new(:Port => 8000, :DocumentRoot =>
 				</ol>
 			</div>
 
-		<h2>更改本地文件的安全策略</h2>
-		<div>
-			<h3>Safari</h3>
-			<div>
-				<p>
-                    在“偏好”面板中启用开发菜单,位于“高级”-&gt“在菜单栏中显示开发菜单”
-				</p>
-
-				<p>
-                    之后从Safari中的“开发”菜单中,选择“停用本地文件限制”,同样需要注意的是,Safari对于缓存有一些奇怪的行为,
-                    因此建议,在同一菜单中打开“停用缓存”的选项;如果你正在编辑,请使用Safari进行调试。
-				</p>
-			</div>
-
-
-			<h3>Chrome</h3>
-			<div>
-				<p>请关闭Chrome浏览器正在运行的*所有*实例,注意这里非常重要的关键字是“*所有*”。</p>
-
-				<p>
-                    在Windows中,你可以在任务管理器中查看所有正在运行的Chorme浏览器的实例。
-                    此外,如果你在系统任务栏中看到了Chrome图标,请鼠标右键打开它的上下文菜单,点击关闭。这样就应当已经关闭所有正在运行的Chrome浏览器实例了。
-
-				</p>
-
-				<p>
-                    然后使用命令行执行Chrome浏览器,并在命令行中添加允许访问本地文件的参数:</p>
-
-				<code>chrome --allow-file-access-from-files</code>
-
-				<p>
-                    在Windows中,最简单的做法或许就是创建一个特别的快捷方式图标,快捷方式的目标指向上面的命令行
-                    (右键点击快捷方式图标-&gt;属性-&gt;目标)。
-				</p>
-
-				<p>在Mac OS X中,你可以用这种方法来添加允许访问本地文件的参数并运行Chrome:</p>
-
-				<code>open /Applications/Google\ Chrome.app --args --allow-file-access-from-files</code>
-			</div>
-			<h3>Firefox</h3>
-			<div>
-				<ol>
-				<li>
-					在地址栏中,键入<code>about:config</code>
-				</li>
-				<li>
-					找到这个参数<code>security.fileuri.strict_origin_policy</code>
-				</li>
-				<li>
-					将其设置为<em>false</em>
-				</li>
-				</ol>
-			</div>
-
-		</div>
-
 			<p>
                 其它简单的替代方案你可以在Stack Overflow上找到:[link:http://stackoverflow.com/q/12905426/24874 click here]。
 			</p>

+ 33 - 34
docs/manual/zh/introduction/How-to-update-things.html

@@ -8,7 +8,7 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		<h1>[name]</h1>
+		<h1>如何更新场景([name]</h1>
 		<div>
 			<p>默认情况下,所有对象都会自动更新它们的矩阵(如果它们已添加到场景中)</p>
 			<code>
@@ -21,7 +21,7 @@ var object1 = new THREE.Object3D();
 var object2 = new THREE.Object3D();
 
 object1.add( object2 );
-scene.add( object1 ); //object1 and object2 will automatically update their matrices
+scene.add( object1 ); //object1 和 object2 会自动更新它们的矩阵
 			</code>
 		</div>
 
@@ -32,27 +32,27 @@ object.matrixAutoUpdate  = false;
 object.updateMatrix();
 		</code>
 
-		<h2>Geometries(几何形状)</h2>
+		<h2>几何形状(Geometries)</h2>
 		<div>
 			<h3>[page:BufferGeometry]</h3>
 			<div>
 				<p>
-					BufferGeometries 将信息(例如顶点位置,面索引,法线,颜色,uv和任何自定义属性) 存储在 [page:BufferAttribute buffers] - 也就是,
+					BufferGeometries 将信息(例如顶点位置,面索引,法线,颜色,uv和任何自定义属性)存储在[page:BufferAttribute buffers] —— 也就是,
 					[link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays typed arrays].
 					这使得它们通常比标准Geometries更快,缺点是更难用。
 				</p>
 				<p>
-					关于更新BufferGeometries, 最重要的是理解你不能调整 buffers 大小(这种操作开销很大,	相当于创建了个新的geometry).
-					但你可以更新 buffers的内容.
+					关于更新BufferGeometries,最重要的是理解你不能调整 buffers 大小(这种操作开销很大,相当于创建了个新的geometry)。
+					但你可以更新 buffers的内容
 				</p>
 				<p>
 					这意味着如果你知道BufferGeometry的一个属性会增长,比如顶点的数量,
 					你必须预先分配足够大的buffer来容纳可能创建的任何新顶点。
-					当然,这也意味着BufferGeometry将有一个最大大小 - 无法创建一个可以高效地无限扩展的BufferGeometry。
+					当然,这也意味着BufferGeometry将有一个最大大小 —— 无法创建一个可以高效地无限扩展的BufferGeometry。
 				</p>
 				<p>
 					我们以在渲染时扩展的line来示例。我们将分配可容纳500个顶点的空间但起初仅绘制2个,使用
-					在500个顶点的缓冲区中,但首先只使用 [page:BufferGeometry.drawRange].
+					在500个顶点的缓冲区中,但首先只使用 [page:BufferGeometry.drawRange]
 				</p>
 				<code>
 var MAX_POINTS = 500;
@@ -106,14 +106,14 @@ line.geometry.setDrawRange( 0, newValue );
 					如果要在第一次渲染后更改position数值,则需要像这样设置needsUpdate标志:
 				</p>
 				<code>
-line.geometry.attributes.position.needsUpdate = true; // required after the first render
+line.geometry.attributes.position.needsUpdate = true; // 需要加在第一次渲染之后
 				</code>
 
 				<p>
-					[link:http://jsfiddle.net/w67tzfhx/ 这个fiddle] 展示了一个你可以参考的运动的line.
+					<a href="http://jsfiddle.net/w67tzfhx/">这个fiddle</a>展示了一个你可以参考的运动的line。
 				</p>
 
-				<h3>Examples:</h3>
+				<h3>例子:</h3>
 					[example:webgl_custom_attributes WebGL / custom / attributes]<br />
 					[example:webgl_buffergeometry_custom_attributes_particles WebGL / buffergeometry / custom / attributes / particles]
 
@@ -123,10 +123,9 @@ line.geometry.attributes.position.needsUpdate = true; // required after the firs
 			<h3>[page:Geometry]</h3>
 			<div>
 				<p>
-					以下标志控制各种geometry属性的更新. 仅对于需要更新的属性设置标志
-					,因为更新成本很高. 一旦buffers
-					改变, 这些标志位会自动重置为false. 你需要保持这些设置为true,如果你想要持续更新buffers. 请注意这仅适用于[page:Geometry]
-					而不是 [page:BufferGeometry].
+					以下标志控制各种geometry属性的更新。仅对于需要更新的属性设置标志,因为更新成本很高。
+					一旦buffers改变,这些标志位会自动重置为false。如果你想要持续更新buffers,你需要保持这些设置为true。
+					请注意这仅适用于[page:Geometry]而不是[page:BufferGeometry]。
 				</p>
 				<code>
 var geometry = new THREE.Geometry();
@@ -140,8 +139,8 @@ geometry.tangentsNeedUpdate = true;
 				</code>
 
 				<p>
-					在早于 [link:https://github.com/mrdoob/three.js/releases/tag/r66 r66]版本中, meshes
-					需要额外设定 <em>dynamic</em> 标志true (为了维持内部的 typed arrays):
+					在早于[link:https://github.com/mrdoob/three.js/releases/tag/r66 r66]版本中,meshes
+					需要额外设定 <em>dynamic</em> 标志为true (为了维持内部的 typed arrays):
 				</p>
 
 				<code>
@@ -149,7 +148,7 @@ geometry.tangentsNeedUpdate = true;
 		geometry.dynamic = true;
 				</code>
 
-				<h3>Examples:</h3>
+				<h3>例子:</h3>
 					[example:webgl_geometry_dynamic WebGL / geometry / dynamic]<br />
 			</div>
 
@@ -158,19 +157,19 @@ geometry.tangentsNeedUpdate = true;
 
 
 
-		<h2>Materials(材质)</h2>
+		<h2>材质(Materials)</h2>
 		<div>
-			<p>所有uniforms值都可以自由改变 (e.g. colors, textures, opacity, etc), 这些数值在每帧都发给shader .</p>
+			<p>所有uniforms值都可以自由改变(比如 colors, textures, opacity 等等),这些数值在每帧都发给shader。</p>
 
-			<p>GL状态相关参数也可以随时改变 (depthTest, blending, polygonOffset, etc).</p>
+			<p>GL状态相关参数也可以随时改变(depthTest, blending, polygonOffset 等)。</p>
 
-			<p>平滑/平滑阴影被作到法线. 你需要重置法线 buffer (见上).</p>
+			<p>平整/光滑阴影被作到法线。你需要重置法线 buffer(见上)。</p>
 
-			<p>在运行时无法轻松更改以下属性 (一旦material被渲染了一次):</p>
+			<p>在运行时无法轻松更改以下属性(一旦material被渲染了一次):</p>
 			<ul>
 				<li>uniforms的数量和类型</li>
 				<li>lights的数量和类型</li>
-				<li>存在与否
+				<li>是否存在
 					<ul>
 						<li>texture</li>
 						<li>fog</li>
@@ -183,42 +182,42 @@ geometry.tangentsNeedUpdate = true;
 				</li>
 			</ul>
 
-			<p>这些变化需要建立新的shader程序. 你需要设置</p>
+			<p>这些变化需要建立新的shader程序你需要设置</p>
 			<code>material.needsUpdate = true</code>
 
-			<p>请记住,这可能会非常缓慢并导致帧率的波动。 (特别是在Windows上,因为shader编译在directx中比opengl慢).</p>
+			<p>请记住,这可能会非常缓慢并导致帧率的波动。(特别是在Windows上,因为shader编译在directx中比opengl慢)。</p>
 
-			<p>为了获得更流畅的体验,您可以通过“虚拟”值(如零强度光,白色纹理或零密度雾)在一定程度上模拟这些功能的变化.</p>
+			<p>为了获得更流畅的体验,您可以通过“虚拟”值(如零强度光,白色纹理或零密度雾)在一定程度上模拟这些功能的变化</p>
 
-			<p>您可以自由更改用于几何块的材质,但是无法更改对象如何划分为块(根据面材料). </p>
+			<p>您可以自由更改用于几何块的材质,但是无法更改对象如何划分为块(根据面材料)</p>
 
 			<h3>如果你需要在运行时使用不同的材料配置:</h3>
-			<p>如果材料/块的数量很少,您可以事先预先划分物体(例如,人的头发/脸部/身体/上衣/裤子,汽车的前部/侧面/顶部/玻璃/轮胎/内部). </p>
+			<p>如果材料/块的数量很少,您可以事先预先划分物体(例如,人的头发/脸部/身体/上衣/裤子,汽车的前部/侧面/顶部/玻璃/轮胎/内部)</p>
 
 			<p>如果数量很大(例如,每个面可能有所不同),请考虑不同的解决方案,例如使用属性/纹理来驱动不同的每个面部外观。</p>
 
-			<h3>Examples:</h3>
+			<h3>例子:</h3>
 			[example:webgl_materials_cars WebGL / materials / cars]<br />
 			[example:webgl_postprocessing_dof WebGL / webgl_postprocessing / dof]
 		</div>
 
 
-		<h2>Textures(纹理)</h2>
+		<h2>纹理(Textures)</h2>
 		<div>
 			<p>如果更改了图像,画布,视频和数据纹理,则需要设置以下标志:</p>
 			<code>
 				texture.needsUpdate = true;
 			</code>
-			<p>Render targets update automatically.</p>
+			<p>渲染对象就会自动更新。</p>
 
-			<h3>Examples:</h3>
+			<h3>例子:</h3>
 			[example:webgl_materials_video WebGL / materials / video]<br />
 			[example:webgl_rtt WebGL / rtt]
 
 		</div>
 
 
-		<h2>Cameras(相机)</h2>
+		<h2>相机(Cameras)</h2>
 		<div>
 			<p>相机的位置和目标会自动更新。 如果你需要改变</p>
 			<ul>

+ 53 - 13
docs/manual/zh/introduction/Loading-3D-models.html

@@ -14,15 +14,14 @@
 	<br />
 
 	<p>
-	3D模型目前的有成千上万种格式可供选择,但每一种格式都具有不同的目的、用途以及复杂性。
+	目前,3D模型的格式有成千上万种可供选择,但每一种格式都具有不同的目的、用途以及复杂性。
 		虽然<a href="https://github.com/mrdoob/three.js/tree/dev/examples/js/loaders" target="_blank" rel="noopener">
-	three.js已经提供了多种导入工具</a>
-	但是选择正确的文件格式以及工作流程将可以节省很多时间,以及避免很多挫折。某些格式难以使用,或者实时体验效率低下,或者目前尚未得到完全支持。
+	three.js已经提供了多种导入工具</a>
+	但是选择正确的文件格式以及工作流程将可以节省很多时间,以及避免遭受很多挫折。某些格式难以使用,或者实时体验效率低下,或者目前尚未得到完全支持。
 	</p>
 
 	<p>
 		对大多数用户,本指南向你推荐了一个工作流程,并向你提供了一些当没有达到预期效果时的建议。
-
 	</p>
 
 	<h2>在开始之前</h2>
@@ -67,9 +66,50 @@
 		当glTF不可用的时候,诸如FBX、OBJ或者COLLADA等等其它广受欢迎的格式在Three.js中也是可以使用、并且定期维护的。
 	</p>
 
-	<h2>Loading</h2>
+	<h2>加载</h2>
+
+	<p>
+		three.js中默认仅包含了几个加载器(例如:[page:ObjectLoader])——其它加载器需要你分别地添加到页面中。
+		取决于你对构建工具的偏好,选择以下任意一种方式:
+	</p>
+
+	<code>
+		// global script
+		&lt;script src="GLTFLoader.js"&gt;&lt;/script&gt;
+
+		// commonjs
+		var THREE = window.THREE = require('three');
+		require('three/examples/js/loaders/GLTFLoader');
+	</code>
+
+	<p>
+		目前three.js示例不能作为ES modules (import &hellip; from '&hellip;')来使用。
+		这里讨论了一些解决方法:
+		<a href="https://github.com/mrdoob/three.js/issues/9562" target="_blank" rel="noopener">#9562</a>.
+	</p>
+
+	<p>
+		一旦你引入了一个加载器,你就已经准备好为场景添加模型了。不同加载器之间可能具有不同的语法 ——
+		当使用其它格式的时候请参阅该格式加载器的示例以及文档。对于glTF,基本用法类似:
+	</p>
+
+	<code>
+		var loader = new THREE.GLTFLoader();
+
+		loader.load( 'path/to/model.glb', function ( gltf ) {
+
+			scene.add( gltf.scene );
 
-	<p>TODO.</p>
+		}, undefined, function ( error ) {
+
+			console.error( error );
+
+		} );
+	</code>
+
+	<p>
+		请参阅[page:GLTFLoader GLTFLoader documentation]来深入了解详细信息。
+	</p>
 
 	<h2>故障排除</h2>
 
@@ -84,28 +124,28 @@
 		在Javascript的Console中查找错误,并确定当你调用<em>.load()</em>的时候,使用了<em>onError</em>回调函数来输出结果。
 		</li>
 		<li>
-		请在的应用程序中查看3D模型。对于glTF格式的模型来说,可以直接在下面的应用程序中进行查看:
+		请在其它的应用程序中查看3D模型。对于glTF格式的模型来说,可以直接在下面的应用程序中进行查看:
 			<a href="https://gltf-viewer.donmccurdy.com/" target="_blank" rel="noopener">three.js</a>和
 		<a href="http://sandbox.babylonjs.com/" target="_blank" rel="noopener">babylon.js</a>。
-	 如果该模型能够在一个或者更多应用程序里正确地呈现,请<a href="https://github.com/mrdoob/three.js/issues/new" target="_blank" rel="noopener">点击这里向three.js提交Bug报告</a>。
+	 如果该模型能够在一个或者多个应用程序中正确地呈现,请<a href="https://github.com/mrdoob/three.js/issues/new" target="_blank" rel="noopener">点击这里向three.js提交Bug报告</a>。
 	 如果模型不能在任意一个应用程序里显示,我们强烈鼓励你向我们提交Bug报告,并告知我们你的模型是使用哪一款应用程序创建的。
 
 		</li>
 		<li>
-		尝试将模型放大或缩小到原来的1000倍。许多模型的缩放比例各不相同,倘若摄像机位于相机内,则大型模型将可能不会显示。
+		尝试将模型放大或缩小到原来的1000倍。许多模型的缩放比例各不相同,如果摄像机位于模型内,则大型模型将可能不会显示。
 		</li>
 		<li>
-		在网络面板中查找失败的纹理贴图请求,像<em>C:\\Path\To\Model\texture.jpg</em>。使用相对于你的模型的文件路径,例如
-		<em>images/texture.jpg</em>——这或许需要在文本编辑器中来对模型文件进行修改。
+		在网络面板中查找失败的纹理贴图请求,比如说<em>C:\\Path\To\Model\texture.jpg</em>。载入贴图时,请使用相对于模型文件路径,例如
+		<em>images/texture.jpg</em> —— 这或许需要在文本编辑器中来对模型文件进行修改。
 		</li>
 	</ol>
 
 	<h2>请求帮助</h2>
 
 	<p>
-	倘若你已经尝试经历了以上故障排除的过程,但是你的模型仍然无法工作,寻求正确的方法来获得帮助将使您更快地获得解决方案。
+	如果你已经尝试经历了以上故障排除的过程,但是你的模型仍然无法工作,寻求正确的方法来获得帮助将使您更快地获得解决方案。
 您可以将您的问题发布到<a href="https://discourse.threejs.org/" target="_blank" rel="noopener">three.js forum</a>,
-	同时,尽可能将你的模型(或者一个简单的、具有相同问题的模型)包含在你能够使用的任何格式中,为其他人提供足够的信息,以便快速重现这个问题——最好是一个能够现场演示的Demo。
+	同时,尽可能将你的模型(或者一个简单的、具有相同问题的模型)包含在你能够使用的任何格式中,为其他人提供足够的信息,以便快速重现这个问题 —— 最好是一个能够现场演示的Demo。
 	</p>
 
 </body>

+ 14 - 14
docs/manual/zh/introduction/Matrix-transformations.html

@@ -8,24 +8,24 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		<h1>[name]</h1>
+		<h1>矩阵变换([name]</h1>
 
 		<p>
-				Three.js使用*matrix*编码3D变换 - 平移(位置),旋转和缩放。 [page:Object3D]的每个实例都有一个[page:Object3D.matrix matrix],用于存储该对象的位置,旋转和比例。 本页介绍如何更新对象的转换。
+				Three.js使用*matrix*编码3D变换 —— 平移(位置),旋转和缩放。
+				[page:Object3D]的每个实例都有一个[page:Object3D.matrix matrix],用于存储该对象的位置,旋转和比例。本页介绍如何更新对象的变换。
 		</p>
 
-		<h2>Convenience properties and *matrixAutoUpdate*(便利属性和 *matrixAutoUpdate*)</h2>
+		<h2>便利的属性和*matrixAutoUpdate*(Convenience properties and *matrixAutoUpdate*)</h2>
 
 		有两种方法可以更新对象的转换:
 		<ol>
 			<li>
-				修改对象的* position *,* quaternion *和* scale *属性,让three.js重新计算
-				来自这些属性的对象矩阵:
+				修改对象的*position*,*quaternion*和*scale*属性,让three.js重新计算来自这些属性的对象矩阵:
 				<code>
 				object.position.copy(start_position);
 				object.quaternion.copy(quaternion);
 				</code>
-				默认情况下,* matrixAutoUpdate *属性设置为true,并且将自动重新计算矩阵。
+				默认情况下,*matrixAutoUpdate*属性设置为true,并且将自动重新计算矩阵。
 如果对象是静态的,或者您希望在重新计算时手动控制,则可以通过将属性设置为false来获得更好的性能:
 				<code>
 				object.matrixAutoUpdate = false;
@@ -42,25 +42,25 @@
 				object.matrix.setPosition(start_position);
 				object.matrixAutoUpdate = false;
 				</code>
-				请注意,在这种情况下,* matrixAutoUpdate * <em>必须</em>设置为* false *,并且您应该确保<em>不</em>调用* updateMatrix *。 调用* updateMatrix *将破坏对矩阵所做的手动更改,从* position *,* scale *重新计算矩阵,依此类推。
+				请注意,在这种情况下,*matrixAutoUpdate* <em> 必须 </em>设置为*false*,并且您应该确保<em> 不 </em>调用*updateMatrix*。
+				调用*updateMatrix*将破坏对矩阵所做的手动更改,从*position*,*scale*重新计算矩阵,依此类推。
 			</li>
 		</ol>
 
-		<h2>Object and world matrices(对象和世界矩阵)</h2>
+		<h2>对象和世界矩阵(Object and world matrices)</h2>
 		<p>
-		对象的[page:Object3D.matrix matrix]将对象的转换<em> 相对于 </em>对象的[page:Object3D.parent parent]; 要在<em> 世界 </em>坐标中获取对象的转换,您必须访问该对象的[page:Object3D.matrixWorld]。
-		An object's [page:Object3D.matrix matrix] stores the object's transformation 
+		一个对象的[page:Object3D.matrix matrix]存储了该对象<em> 相对于 </em>其[page:Object3D.parent](父节点)的变换。要在<em> 世界 </em>坐标系中获取对象的转换,您必须访问该对象的[page:Object3D.matrixWorld]。
 		</p>
 		<p>
-		当父对象或子对象的转换发生更改时,可以通过调用[page:Object3D.updateMatrixWorld updateMatrixWorld]()来请求更新子对象的[page:Object3D.matrixWorld matrixWorld]。
+		当父对象或子对象的变换发生更改时,可以通过调用[page:Object3D.updateMatrixWorld updateMatrixWorld()]来请求更新子对象的[page:Object3D.matrixWorld matrixWorld]。
 		</p>
 
-		<h2>Rotation and Quaternion(旋转和四元数)</h2>
+		<h2>旋转和四元数(Rotation and Quaternion)</h2>
 		<p>
-		Three.js提供了两种表示3D旋转的方式:[page:Euler Euler angles]和[page:Quaternion Quaternions],以及两者之间的转换方法。 欧拉角受到称为“万向节锁定”的问题,其中某些配置可能失去一定程度的自由度(防止物体绕一个轴旋转)。 因此,对象旋转<em>始终</em>存储在对象的[page:Object3D.quaternion quaternion]中。
+		Three.js提供了两种表示3D旋转的方式:[page:Euler Euler angles](欧拉角)和[page:Quaternion Quaternions](四元数),以及两者之间的转换方法。 欧拉角有称为“万向节锁定”的问题,其中某些配置可能失去一定程度的自由度(防止物体绕一个轴旋转)。 因此,对象旋转<em> 始终 </em>存储在对象的[page:Object3D.quaternion quaternion]中。
 		</p>
 		<p>
-		该库的早期版本包含* useQuaternion *属性,当设置为false时,将导致对象的[page:Object3D.matrix矩阵]从欧拉角计算。 这种做法已被弃用 - 相反,您应该使用[page:Object3D.setRotationFromEuler setRotationFromEuler]方法,该方法将更新四元数。	
+		该库的早期版本包含*useQuaternion*属性,当设置为false时,将导致对象的[page:Object3D.matrix matrix]从欧拉角计算。这种做法已被弃用 - 作为代替,您应该使用[page:Object3D.setRotationFromEuler setRotationFromEuler]方法,该方法将更新四元数。
 		</p>
 
 	</body>

+ 5 - 5
docs/manual/zh/introduction/Useful-links.html

@@ -24,7 +24,7 @@
 		<p>
 			Three.js官方使用[link:http://stackoverflow.com/tags/three.js/info Stack Overflow]来处理帮助请求。
 			如果你需要一些帮助,这才是你所要去的地方。请<strong>一定不要</strong>在GitHub上提issue来寻求帮助。
-		
+
 		</p>
 
 		<h2>教程以及课程</h2>
@@ -100,7 +100,7 @@
 				maintained as part of the three.js repository, and always use the latest version of three.js.
 			</li>
 			<li>
-				[link:https://rawgit.com/mrdoob/three.js/dev/examples/ Official three.js dev branch examples]  -
+				[link:https://raw.githack.com/mrdoob/three.js/dev/examples/ Official three.js dev branch examples]  -
 				Same as the above, except these use the dev branch of three.js,	and are used to check that
 				everything is working as three.js being is developed.
 			</li>
@@ -123,7 +123,7 @@
 			[link:http://idflood.github.io/ThreeNodes.js/ ThreeNodes.js].
 		</li>
 	 </ul>
-		
+
 	<h2>WebGL参考</h2>
 	 <ul>
 		 <li>
@@ -138,7 +138,7 @@
 
 	 <ul>
 		<li>
-			<a href="https://www.youtube.com/watch?v=Dir4KO9RdhM">AlterQualia at WebGL Camp 3</a>
+			<a href="https://www.youtube.com/watch?v=Dir4KO9RdhM" target="_blank">AlterQualia at WebGL Camp 3</a>
 		</li>
 		<li>
 			[link:http://yomotsu.github.io/threejs-examples/ Yomotsus Examples] - a collection of examples using three.js r45.
@@ -153,7 +153,7 @@
 			[link:http://bkcore.com/blog/general/adobe-user-group-nl-talk-video-hexgl.html Fast HTML5 game development using three.js] by [link:https://github.com/BKcore BKcore] (video).
 		</li>
 		<li>
-			<a href="http://www.youtube.com/watch?v=VdQnOaolrPA">Trigger Rally</a>  by [link:https://github.com/jareiko jareiko] (video).
+			<a href="https://www.youtube.com/watch?v=VdQnOaolrPA" target="_blank">Trigger Rally</a>  by [link:https://github.com/jareiko jareiko] (video).
 		</li>
 		<li>
 			[link:http://blackjk3.github.io/threefab/ ThreeFab] - scene editor, maintained up until around three.js r50.

+ 1 - 1
docs/manual/zh/introduction/WebGL-compatibility-check.html

@@ -10,7 +10,7 @@
 	<body>
 		<h1>WebGL兼容性检查([name])</h1><br />
 		<p>
-            虽然这个问题现在已经变得越来越小,但不得不说,有的设备或者浏览器直到现在仍然不支持WebGL。<br>以下的方法可以帮助你检测当前用户所使用的环境是否支持WebGL,倘若不支持,将向用户显示一条信息。
+            虽然这个问题现在已经变得越来不明显,但不可否定的是,某些设备以及浏览器直到现在仍然不支持WebGL。<br>以下的方法可以帮助你检测当前用户所使用的环境是否支持WebGL,如果不支持,将会向用户提示一条信息。
 		</p>
 
 		<p>

+ 34 - 25
docs/scenes/bones-browser.html

@@ -43,12 +43,10 @@
 			var gui, scene, camera, renderer, orbit, lights, mesh, bones, skeletonHelper;
 
 			var state = {
-
-				animateBones : false
-
+				animateBones: false
 			};
 
-			function initScene () {
+			function initScene() {
 
 				gui = new dat.GUI();
 				scene = new THREE.Scene();
@@ -92,35 +90,46 @@
 
 			}
 
-			function createGeometry ( sizing ) {
+			function createGeometry( sizing ) {
 
-				var geometry = new THREE.CylinderGeometry(
-					5,                       // radiusTop
-					5,                       // radiusBottom
-					sizing.height,           // height
-					8,                       // radiusSegments
+				var geometry = new THREE.CylinderBufferGeometry(
+					5, // radiusTop
+					5, // radiusBottom
+					sizing.height, // height
+					8, // radiusSegments
 					sizing.segmentCount * 3, // heightSegments
-					true                     // openEnded
+					true // openEnded
 				);
 
-				for ( var i = 0; i < geometry.vertices.length; i ++ ) {
+				var position = geometry.attributes.position;
+
+				var vertex = new THREE.Vector3();
+
+				var skinIndices = [];
+				var skinWeights = [];
+
+				for ( var i = 0; i < position.count; i ++ ) {
+
+					vertex.fromBufferAttribute( position, i );
 
-					var vertex = geometry.vertices[ i ];
 					var y = ( vertex.y + sizing.halfHeight );
 
 					var skinIndex = Math.floor( y / sizing.segmentHeight );
 					var skinWeight = ( y % sizing.segmentHeight ) / sizing.segmentHeight;
 
-					geometry.skinIndices.push( new THREE.Vector4( skinIndex, skinIndex + 1, 0, 0 ) );
-					geometry.skinWeights.push( new THREE.Vector4( 1 - skinWeight, skinWeight, 0, 0 ) );
+					skinIndices.push( skinIndex, skinIndex + 1, 0, 0 );
+					skinWeights.push( 1 - skinWeight, skinWeight, 0, 0 );
 
 				}
 
+				geometry.addAttribute( 'skinIndex', new THREE.Uint16BufferAttribute( skinIndices, 4 ) );
+				geometry.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( skinWeights, 4 ) );
+
 				return geometry;
 
 			}
 
-			function createBones ( sizing ) {
+			function createBones( sizing ) {
 
 				bones = [];
 
@@ -142,10 +151,10 @@
 
 			}
 
-			function createMesh ( geometry, bones ) {
+			function createMesh( geometry, bones ) {
 
 				var material = new THREE.MeshPhongMaterial( {
-					skinning : true,
+					skinning: true,
 					color: 0x156289,
 					emissive: 0x072534,
 					side: THREE.DoubleSide,
@@ -167,7 +176,7 @@
 
 			}
 
-			function setupDatGui () {
+			function setupDatGui() {
 
 				var folder = gui.addFolder( "General Options" );
 
@@ -213,7 +222,7 @@
 
 			}
 
-			function initBones () {
+			function initBones() {
 
 				var segmentHeight = 8;
 				var segmentCount = 4;
@@ -221,10 +230,10 @@
 				var halfHeight = height * 0.5;
 
 				var sizing = {
-					segmentHeight : segmentHeight,
-					segmentCount : segmentCount,
-					height : height,
-					halfHeight : halfHeight
+					segmentHeight: segmentHeight,
+					segmentCount: segmentCount,
+					height: height,
+					halfHeight: halfHeight
 				};
 
 				var geometry = createGeometry( sizing );
@@ -236,7 +245,7 @@
 
 			}
 
-			function render () {
+			function render() {
 
 				requestAnimationFrame( render );
 

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

@@ -480,8 +480,8 @@ Sidebar.Object = function ( editor ) {
 
 			if ( object.receiveShadow !== undefined && object.receiveShadow !== objectReceiveShadow.getValue() ) {
 
-				editor.execute( new SetValueCommand( object, 'receiveShadow', objectReceiveShadow.getValue() ) );
 				object.material.needsUpdate = true;
+				editor.execute( new SetValueCommand( object, 'receiveShadow', objectReceiveShadow.getValue() ) );
 
 			}
 

+ 4 - 2
examples/files.js

@@ -58,6 +58,7 @@ var files = {
 		"webgl_kinect",
 		"webgl_layers",
 		"webgl_lensflares",
+		"webgl_lightningstrike",
 		"webgl_lights_hemisphere",
 		"webgl_lights_physical",
 		"webgl_lights_pointlights",
@@ -92,6 +93,7 @@ var files = {
 		"webgl_loader_imagebitmap",
 		"webgl_loader_json_claraio",
 		"webgl_loader_kmz",
+		"webgl_loader_ldraw",
 		"webgl_loader_md2",
 		"webgl_loader_md2_control",
 		"webgl_loader_mmd",
@@ -198,8 +200,6 @@ var files = {
 		"webgl_multiple_scenes_comparison",
 		"webgl_multiple_views",
 		"webgl_nearestneighbour",
-		"webgl_octree",
-		"webgl_octree_raycasting",
 		"webgl_panorama_cube",
 		"webgl_panorama_dualfisheye",
 		"webgl_panorama_equirectangular",
@@ -298,6 +298,7 @@ var files = {
 		"webgl_custom_attributes_points",
 		"webgl_custom_attributes_points2",
 		"webgl_custom_attributes_points3",
+		"webgl_fire",
 		"webgl_gpgpu_birds",
 		"webgl_gpgpu_water",
 		"webgl_gpgpu_protoplanet",
@@ -349,6 +350,7 @@ var files = {
 		"misc_controls_pointerlock",
 		"misc_controls_trackball",
 		"misc_controls_transform",
+		"misc_exporter_collada",
 		"misc_exporter_gltf",
 		"misc_exporter_obj",
 		"misc_exporter_stl",

+ 29 - 0
examples/files/ldraw_org_logo/LDraw.org_logo_LICENSE.txt

@@ -0,0 +1,29 @@
+Content © 2002 LDraw.org. All content created specifically for LDraw.org, including but not limited to images, HTML code, and original unique content falls under the OpenContent Licence (OPL). Individual programs made available for download from this site are subject to their individual respective licenses and are used by permission.
+
+OpenContent License (OPL)
+Version 1.0, July 14, 1998.
+
+This document outlines the principles underlying the OpenContent (OC) movement and may be redistributed provided it remains unaltered. For legal purposes, this document is the license under which OpenContent is made available for use.
+
+The original version of this document may be found at http://www.opencontent.org/opl.shtml
+
+LICENSE
+
+Terms and Conditions for Copying, Distributing, and Modifying
+
+Items other than copying, distributing, and modifying the Content with which this license was distributed (such as using, etc.) are outside the scope of this license.
+
+        You may copy and distribute exact replicas of the OpenContent (OC) as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the OC a copy of this License along with the OC. You may at your option charge a fee for the media and/or handling involved in creating a unique copy of the OC for use offline, you may at your option offer instructional support for the OC in exchange for a fee, or you may at your option offer warranty in exchange for a fee. You may not charge a fee for the OC itself. You may not charge a fee for the sole service of providing access to and/or use of the OC via a network (e.g. the Internet), whether it be via the world wide web, FTP, or any other method.
+        You may modify your copy or copies of the OpenContent or any portion of it, thus forming works based on the Content, and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+
+        a) You must cause the modified content to carry prominent notices stating that you changed it, the exact nature and content of the changes, and the date of any change.
+
+        b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the OC or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License, unless otherwise permitted under applicable Fair Use law.
+
+        These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the OC, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the OC, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Exceptions are made to this requirement to release modified works free of charge under this license only in compliance with Fair Use law where applicable.
+        You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to copy, distribute or modify the OC. These actions are prohibited by law if you do not accept this License. Therefore, by distributing or translating the OC, or by deriving works herefrom, you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or translating the OC.
+
+NO WARRANTY
+
+    BECAUSE THE OPENCONTENT (OC) IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE OC, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE OC "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK OF USE OF THE OC IS WITH YOU. SHOULD THE OC PROVE FAULTY, INACCURATE, OR OTHERWISE UNACCEPTABLE YOU ASSUME THE COST OF ALL NECESSARY REPAIR OR CORRECTION.
+    IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MIRROR AND/OR REDISTRIBUTE THE OC AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE OC, EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 

二进制
examples/files/ldraw_org_logo/Stamp145.png


+ 0 - 2138
examples/js/Octree.js

@@ -1,2138 +0,0 @@
-/*!
- *
- * threeoctree.js (r60) / https://github.com/collinhover/threeoctree
- * (sparse) dynamic 3D spatial representation structure for fast searches.
- *
- * @author Collin Hover / http://collinhover.com/
- * based on Dynamic Octree by Piko3D @ http://www.piko3d.com/ and Octree by Marek Pawlowski @ pawlowski.it
- *
- */
-( function ( THREE ) {
-
-	"use strict";
-
-	/*===================================================
-
-	utility
-
-	=====================================================*/
-
-	function isNumber( n ) {
-
-		return ! isNaN( n ) && isFinite( n );
-
-	}
-
-	function isArray( target ) {
-
-		return Object.prototype.toString.call( target ) === '[object Array]';
-
-	}
-
-	function toArray( target ) {
-
-		return target ? ( isArray( target ) !== true ? [ target ] : target ) : [];
-
-	}
-
-	function indexOfValue( array, value ) {
-
-		for ( var i = 0, il = array.length; i < il; i ++ ) {
-
-			if ( array[ i ] === value ) {
-
-				return i;
-
-			}
-
-		}
-
-		return - 1;
-
-	}
-
-	function indexOfPropertyWithValue( array, property, value ) {
-
-		for ( var i = 0, il = array.length; i < il; i ++ ) {
-
-			if ( array[ i ][ property ] === value ) {
-
-				return i;
-
-			}
-
-		}
-
-		return - 1;
-
-	}
-
-	/*===================================================
-
-	octree
-
-	=====================================================*/
-
-	THREE.Octree = function ( parameters ) {
-
-		// handle parameters
-
-		parameters = parameters || {};
-
-		parameters.tree = this;
-
-		// static properties ( modification is not recommended )
-
-		this.nodeCount = 0;
-
-		this.INDEX_INSIDE_CROSS = - 1;
-		this.INDEX_OUTSIDE_OFFSET = 2;
-
-		this.INDEX_OUTSIDE_POS_X = isNumber( parameters.INDEX_OUTSIDE_POS_X ) ? parameters.INDEX_OUTSIDE_POS_X : 0;
-		this.INDEX_OUTSIDE_NEG_X = isNumber( parameters.INDEX_OUTSIDE_NEG_X ) ? parameters.INDEX_OUTSIDE_NEG_X : 1;
-		this.INDEX_OUTSIDE_POS_Y = isNumber( parameters.INDEX_OUTSIDE_POS_Y ) ? parameters.INDEX_OUTSIDE_POS_Y : 2;
-		this.INDEX_OUTSIDE_NEG_Y = isNumber( parameters.INDEX_OUTSIDE_NEG_Y ) ? parameters.INDEX_OUTSIDE_NEG_Y : 3;
-		this.INDEX_OUTSIDE_POS_Z = isNumber( parameters.INDEX_OUTSIDE_POS_Z ) ? parameters.INDEX_OUTSIDE_POS_Z : 4;
-		this.INDEX_OUTSIDE_NEG_Z = isNumber( parameters.INDEX_OUTSIDE_NEG_Z ) ? parameters.INDEX_OUTSIDE_NEG_Z : 5;
-
-		this.INDEX_OUTSIDE_MAP = [];
-		this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_POS_X ] = { index: this.INDEX_OUTSIDE_POS_X, count: 0, x: 1, y: 0, z: 0 };
-		this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_NEG_X ] = { index: this.INDEX_OUTSIDE_NEG_X, count: 0, x: - 1, y: 0, z: 0 };
-		this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_POS_Y ] = { index: this.INDEX_OUTSIDE_POS_Y, count: 0, x: 0, y: 1, z: 0 };
-		this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_NEG_Y ] = { index: this.INDEX_OUTSIDE_NEG_Y, count: 0, x: 0, y: - 1, z: 0 };
-		this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_POS_Z ] = { index: this.INDEX_OUTSIDE_POS_Z, count: 0, x: 0, y: 0, z: 1 };
-		this.INDEX_OUTSIDE_MAP[ this.INDEX_OUTSIDE_NEG_Z ] = { index: this.INDEX_OUTSIDE_NEG_Z, count: 0, x: 0, y: 0, z: - 1 };
-
-		this.FLAG_POS_X = 1 << ( this.INDEX_OUTSIDE_POS_X + 1 );
-		this.FLAG_NEG_X = 1 << ( this.INDEX_OUTSIDE_NEG_X + 1 );
-		this.FLAG_POS_Y = 1 << ( this.INDEX_OUTSIDE_POS_Y + 1 );
-		this.FLAG_NEG_Y = 1 << ( this.INDEX_OUTSIDE_NEG_Y + 1 );
-		this.FLAG_POS_Z = 1 << ( this.INDEX_OUTSIDE_POS_Z + 1 );
-		this.FLAG_NEG_Z = 1 << ( this.INDEX_OUTSIDE_NEG_Z + 1 );
-
-		this.utilVec31Search = new THREE.Vector3();
-		this.utilVec32Search = new THREE.Vector3();
-
-		// pass scene to see octree structure
-
-		this.scene = parameters.scene;
-
-		if ( this.scene ) {
-
-			var helper = new THREE.BoxHelper( new THREE.Mesh( new THREE.BoxBufferGeometry( 1, 1, 1 ) ), 0xff0066 );
-			this.visualGeometry = helper.geometry;
-			this.visualMaterial = helper.material;
-
-		}
-
-		// properties
-
-		this.objects = [];
-		this.objectsMap = {};
-		this.objectsData = [];
-		this.objectsDeferred = [];
-
-		this.depthMax = isNumber( parameters.depthMax ) ? parameters.depthMax : Infinity;
-		this.objectsThreshold = isNumber( parameters.objectsThreshold ) ? parameters.objectsThreshold : 8;
-		this.overlapPct = isNumber( parameters.overlapPct ) ? parameters.overlapPct : 0.15;
-		this.undeferred = parameters.undeferred || false;
-
-		this.root = parameters.root instanceof THREE.OctreeNode ? parameters.root : new THREE.OctreeNode( parameters );
-
-	};
-
-	THREE.Octree.prototype = {
-
-		update: function () {
-
-			// add any deferred objects that were waiting for render cycle
-
-			if ( this.objectsDeferred.length > 0 ) {
-
-				for ( var i = 0, il = this.objectsDeferred.length; i < il; i ++ ) {
-
-					var deferred = this.objectsDeferred[ i ];
-
-					this.addDeferred( deferred.object, deferred.options );
-
-				}
-
-				this.objectsDeferred.length = 0;
-
-			}
-
-		},
-
-		add: function ( object, options ) {
-
-			// add immediately
-
-			if ( this.undeferred ) {
-
-				this.updateObject( object );
-
-				this.addDeferred( object, options );
-
-			} else {
-
-				// defer add until update called
-
-				this.objectsDeferred.push( { object: object, options: options } );
-
-			}
-
-		},
-
-		addDeferred: function ( object, options ) {
-
-			var i, l,
-				geometry,
-				faces,
-				useFaces,
-				vertices,
-				useVertices,
-				objectData;
-
-			// ensure object is not object data
-
-			if ( object instanceof THREE.OctreeObjectData ) {
-
-				object = object.object;
-
-			}
-
-			// check uuid to avoid duplicates
-
-			if ( ! object.uuid ) {
-
-				object.uuid = THREE.Math.generateUUID();
-
-			}
-
-			if ( ! this.objectsMap[ object.uuid ] ) {
-
-				// store
-
-				this.objects.push( object );
-				this.objectsMap[ object.uuid ] = object;
-
-				// check options
-
-				if ( options ) {
-
-					useFaces = options.useFaces;
-					useVertices = options.useVertices;
-
-				}
-
-				if ( useVertices === true ) {
-
-					geometry = object.geometry;
-					vertices = geometry.vertices;
-
-					for ( i = 0, l = vertices.length; i < l; i ++ ) {
-
-						this.addObjectData( object, vertices[ i ] );
-
-					}
-
-				} else if ( useFaces === true ) {
-
-					geometry = object.geometry;
-					faces = geometry.faces;
-
-					for ( i = 0, l = faces.length; i < l; i ++ ) {
-
-						this.addObjectData( object, faces[ i ] );
-
-					}
-
-				} else {
-
-					this.addObjectData( object );
-
-				}
-
-			}
-
-		},
-
-		addObjectData: function ( object, part ) {
-
-			var objectData = new THREE.OctreeObjectData( object, part );
-
-			// add to tree objects data list
-
-			this.objectsData.push( objectData );
-
-			// add to nodes
-
-			this.root.addObject( objectData );
-
-		},
-
-		remove: function ( object ) {
-
-			var i, l,
-				objectData = object,
-				index,
-				objectsDataRemoved;
-
-			// ensure object is not object data for index search
-
-			if ( object instanceof THREE.OctreeObjectData ) {
-
-				object = object.object;
-
-			}
-
-			// check uuid
-
-			if ( this.objectsMap[ object.uuid ] ) {
-
-				this.objectsMap[ object.uuid ] = undefined;
-
-				// check and remove from objects, nodes, and data lists
-
-				index = indexOfValue( this.objects, object );
-
-				if ( index !== - 1 ) {
-
-					this.objects.splice( index, 1 );
-
-					// remove from nodes
-
-					objectsDataRemoved = this.root.removeObject( objectData );
-
-					// remove from objects data list
-
-					for ( i = 0, l = objectsDataRemoved.length; i < l; i ++ ) {
-
-						objectData = objectsDataRemoved[ i ];
-
-						index = indexOfValue( this.objectsData, objectData );
-
-						if ( index !== - 1 ) {
-
-							this.objectsData.splice( index, 1 );
-
-						}
-
-					}
-
-				}
-
-			} else if ( this.objectsDeferred.length > 0 ) {
-
-				// check and remove from deferred
-
-				index = indexOfPropertyWithValue( this.objectsDeferred, 'object', object );
-
-				if ( index !== - 1 ) {
-
-					this.objectsDeferred.splice( index, 1 );
-
-				}
-
-			}
-
-		},
-
-		extend: function ( octree ) {
-
-			var i, l,
-				objectsData,
-				objectData;
-
-			if ( octree instanceof THREE.Octree ) {
-
-				// for each object data
-
-				objectsData = octree.objectsData;
-
-				for ( i = 0, l = objectsData.length; i < l; i ++ ) {
-
-					objectData = objectsData[ i ];
-
-					this.add( objectData, { useFaces: objectData.faces, useVertices: objectData.vertices } );
-
-				}
-
-			}
-
-		},
-
-		rebuild: function () {
-
-			var i, l,
-				node,
-				object,
-				objectData,
-				indexOctant,
-				indexOctantLast,
-				objectsUpdate = [];
-
-			// check all object data for changes in position
-			// assumes all object matrices are up to date
-
-			for ( i = 0, l = this.objectsData.length; i < l; i ++ ) {
-
-				objectData = this.objectsData[ i ];
-
-				node = objectData.node;
-
-				// update object
-
-				objectData.update();
-
-				// if position has changed since last organization of object in tree
-
-				if ( node instanceof THREE.OctreeNode && ! objectData.positionLast.equals( objectData.position ) ) {
-
-					// get octant index of object within current node
-
-					indexOctantLast = objectData.indexOctant;
-
-					indexOctant = node.getOctantIndex( objectData );
-
-					// if object octant index has changed
-
-					if ( indexOctant !== indexOctantLast ) {
-
-						// add to update list
-
-						objectsUpdate.push( objectData );
-
-					}
-
-				}
-
-			}
-
-			// update changed objects
-
-			for ( i = 0, l = objectsUpdate.length; i < l; i ++ ) {
-
-				objectData = objectsUpdate[ i ];
-
-				// remove object from current node
-
-				objectData.node.removeObject( objectData );
-
-				// add object to tree root
-
-				this.root.addObject( objectData );
-
-			}
-
-		},
-
-		updateObject: function ( object ) {
-
-			var i, l,
-				parentCascade = [ object ],
-				parent,
-				parentUpdate;
-
-			// search all parents between object and root for world matrix update
-
-			parent = object.parent;
-
-			while ( parent ) {
-
-				parentCascade.push( parent );
-				parent = parent.parent;
-
-			}
-
-			for ( i = 0, l = parentCascade.length; i < l; i ++ ) {
-
-				parent = parentCascade[ i ];
-
-				if ( parent.matrixWorldNeedsUpdate === true ) {
-
-					parentUpdate = parent;
-
-				}
-
-			}
-
-			// update world matrix starting at uppermost parent that needs update
-
-			if ( typeof parentUpdate !== 'undefined' ) {
-
-				parentUpdate.updateMatrixWorld();
-
-			}
-
-		},
-
-		search: function ( position, radius, organizeByObject, direction ) {
-
-			var i, l,
-				node,
-				objects,
-				objectData,
-				object,
-				results,
-				resultData,
-				resultsObjectsIndices,
-				resultObjectIndex,
-				directionPct;
-
-			// add root objects
-
-			objects = [].concat( this.root.objects );
-
-			// ensure radius (i.e. distance of ray) is a number
-
-			if ( ! ( radius > 0 ) ) {
-
-				radius = Number.MAX_VALUE;
-
-			}
-
-			// if direction passed, normalize and find pct
-
-			if ( direction instanceof THREE.Vector3 ) {
-
-				direction = this.utilVec31Search.copy( direction ).normalize();
-				directionPct = this.utilVec32Search.set( 1, 1, 1 ).divide( direction );
-
-			}
-
-			// search each node of root
-
-			for ( i = 0, l = this.root.nodesIndices.length; i < l; i ++ ) {
-
-				node = this.root.nodesByIndex[ this.root.nodesIndices[ i ] ];
-
-				objects = node.search( position, radius, objects, direction, directionPct );
-
-			}
-
-			// if should organize results by object
-
-			if ( organizeByObject === true ) {
-
-				results = [];
-				resultsObjectsIndices = [];
-
-				// for each object data found
-
-				for ( i = 0, l = objects.length; i < l; i ++ ) {
-
-					objectData = objects[ i ];
-					object = objectData.object;
-
-					resultObjectIndex = indexOfValue( resultsObjectsIndices, object );
-
-					// if needed, create new result data
-
-					if ( resultObjectIndex === - 1 ) {
-
-						resultData = {
-							object: object,
-							faces: [],
-							vertices: []
-						};
-
-						results.push( resultData );
-
-						resultsObjectsIndices.push( object );
-
-					} else {
-
-						resultData = results[ resultObjectIndex ];
-
-					}
-
-					// object data has faces or vertices, add to list
-
-					if ( objectData.faces ) {
-
-						resultData.faces.push( objectData.faces );
-
-					} else if ( objectData.vertices ) {
-
-						resultData.vertices.push( objectData.vertices );
-
-					}
-
-				}
-
-			} else {
-
-				results = objects;
-
-			}
-
-			return results;
-
-		},
-
-		setRoot: function ( root ) {
-
-			if ( root instanceof THREE.OctreeNode ) {
-
-				// store new root
-
-				this.root = root;
-
-				// update properties
-
-				this.root.updateProperties();
-
-			}
-
-		},
-
-		getDepthEnd: function () {
-
-			return this.root.getDepthEnd();
-
-		},
-
-		getNodeCountEnd: function () {
-
-			return this.root.getNodeCountEnd();
-
-		},
-
-		getObjectCountEnd: function () {
-
-			return this.root.getObjectCountEnd();
-
-		},
-
-		toConsole: function () {
-
-			this.root.toConsole();
-
-		}
-
-	};
-
-	/*===================================================
-
-	object data
-
-	=====================================================*/
-
-	THREE.OctreeObjectData = function ( object, part ) {
-
-		// properties
-
-		this.object = object;
-
-		// handle part by type
-
-		if ( part instanceof THREE.Face3 ) {
-
-			this.faces = part;
-			this.face3 = true;
-			this.utilVec31FaceBounds = new THREE.Vector3();
-
-		} else if ( part instanceof THREE.Vector3 ) {
-
-			this.vertices = part;
-
-		}
-
-		this.radius = 0;
-		this.position = new THREE.Vector3();
-
-		// initial update
-
-		if ( this.object instanceof THREE.Object3D ) {
-
-			this.update();
-
-		}
-
-		this.positionLast = this.position.clone();
-
-	};
-
-	THREE.OctreeObjectData.prototype = {
-
-		update: function () {
-
-			if ( this.face3 ) {
-
-				this.radius = this.getFace3BoundingRadius( this.object, this.faces );
-				this.position.copy( this.faces.centroid ).applyMatrix4( this.object.matrixWorld );
-
-			} else if ( this.vertices ) {
-
-				this.radius = this.object.material.size || 1;
-				this.position.copy( this.vertices ).applyMatrix4( this.object.matrixWorld );
-
-			} else {
-
-				if ( this.object.geometry ) {
-
-					if ( this.object.geometry.boundingSphere === null ) {
-
-						this.object.geometry.computeBoundingSphere();
-
-					}
-
-					this.radius = this.object.geometry.boundingSphere.radius;
-					this.position.copy( this.object.geometry.boundingSphere.center ).applyMatrix4( this.object.matrixWorld );
-
-				} else {
-
-					this.radius = this.object.boundRadius;
-					this.position.setFromMatrixPosition( this.object.matrixWorld );
-
-				}
-
-			}
-
-			this.radius = this.radius * Math.max( this.object.scale.x, this.object.scale.y, this.object.scale.z );
-
-		},
-
-		getFace3BoundingRadius: function ( object, face ) {
-
-			if ( face.centroid === undefined ) face.centroid = new THREE.Vector3();
-
-			var geometry = object.geometry || object,
-				vertices = geometry.vertices,
-				centroid = face.centroid,
-				va = vertices[ face.a ], vb = vertices[ face.b ], vc = vertices[ face.c ],
-				centroidToVert = this.utilVec31FaceBounds,
-				radius;
-
-			centroid.addVectors( va, vb ).add( vc ).divideScalar( 3 );
-			radius = Math.max( centroidToVert.subVectors( centroid, va ).length(), centroidToVert.subVectors( centroid, vb ).length(), centroidToVert.subVectors( centroid, vc ).length() );
-
-			return radius;
-
-		}
-
-	};
-
-	/*===================================================
-
-	node
-
-	=====================================================*/
-
-	THREE.OctreeNode = function ( parameters ) {
-
-		// utility
-
-		this.utilVec31Branch = new THREE.Vector3();
-		this.utilVec31Expand = new THREE.Vector3();
-		this.utilVec31Ray = new THREE.Vector3();
-
-		// handle parameters
-
-		parameters = parameters || {};
-
-		// store or create tree
-
-		if ( parameters.tree instanceof THREE.Octree ) {
-
-			this.tree = parameters.tree;
-
-		} else if ( parameters.parent instanceof THREE.OctreeNode !== true ) {
-
-			parameters.root = this;
-
-			this.tree = new THREE.Octree( parameters );
-
-		}
-
-		// basic properties
-
-		this.id = this.tree.nodeCount ++;
-		this.position = parameters.position instanceof THREE.Vector3 ? parameters.position : new THREE.Vector3();
-		this.radius = parameters.radius > 0 ? parameters.radius : 1;
-		this.indexOctant = parameters.indexOctant;
-		this.depth = 0;
-
-		// reset and assign parent
-
-		this.reset();
-		this.setParent( parameters.parent );
-
-		// additional properties
-
-		this.overlap = this.radius * this.tree.overlapPct;
-		this.radiusOverlap = this.radius + this.overlap;
-		this.left = this.position.x - this.radiusOverlap;
-		this.right = this.position.x + this.radiusOverlap;
-		this.bottom = this.position.y - this.radiusOverlap;
-		this.top = this.position.y + this.radiusOverlap;
-		this.back = this.position.z - this.radiusOverlap;
-		this.front = this.position.z + this.radiusOverlap;
-
-		// visual
-
-		if ( this.tree.scene ) {
-
-			this.visual = new THREE.LineSegments( this.tree.visualGeometry, this.tree.visualMaterial );
-			this.visual.scale.set( this.radiusOverlap * 2, this.radiusOverlap * 2, this.radiusOverlap * 2 );
-			this.visual.position.copy( this.position );
-			this.tree.scene.add( this.visual );
-
-		}
-
-	};
-
-	THREE.OctreeNode.prototype = {
-
-		setParent: function ( parent ) {
-
-			// store new parent
-
-			if ( parent !== this && this.parent !== parent ) {
-
-				this.parent = parent;
-
-				// update properties
-
-				this.updateProperties();
-
-			}
-
-		},
-
-		updateProperties: function () {
-
-			var i, l;
-
-			// properties
-
-			if ( this.parent instanceof THREE.OctreeNode ) {
-
-				this.tree = this.parent.tree;
-				this.depth = this.parent.depth + 1;
-
-			} else {
-
-				this.depth = 0;
-
-			}
-
-			// cascade
-
-			for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
-				this.nodesByIndex[ this.nodesIndices[ i ] ].updateProperties();
-
-			}
-
-		},
-
-		reset: function ( cascade, removeVisual ) {
-
-			var i, l,
-				node,
-				nodesIndices = this.nodesIndices || [],
-				nodesByIndex = this.nodesByIndex;
-
-			this.objects = [];
-			this.nodesIndices = [];
-			this.nodesByIndex = {};
-
-			// unset parent in nodes
-
-			for ( i = 0, l = nodesIndices.length; i < l; i ++ ) {
-
-				node = nodesByIndex[ nodesIndices[ i ] ];
-
-				node.setParent( undefined );
-
-				if ( cascade === true ) {
-
-					node.reset( cascade, removeVisual );
-
-				}
-
-			}
-
-			// visual
-
-			if ( removeVisual === true && this.visual && this.visual.parent ) {
-
-				this.visual.parent.remove( this.visual );
-
-			}
-
-		},
-
-		addNode: function ( node, indexOctant ) {
-
-			node.indexOctant = indexOctant;
-
-			if ( indexOfValue( this.nodesIndices, indexOctant ) === - 1 ) {
-
-				this.nodesIndices.push( indexOctant );
-
-			}
-
-			this.nodesByIndex[ indexOctant ] = node;
-
-			if ( node.parent !== this ) {
-
-				node.setParent( this );
-
-			}
-
-		},
-
-		removeNode: function ( indexOctant ) {
-
-			var index,
-				node;
-
-			index = indexOfValue( this.nodesIndices, indexOctant );
-
-			this.nodesIndices.splice( index, 1 );
-
-			node = node || this.nodesByIndex[ indexOctant ];
-
-			delete this.nodesByIndex[ indexOctant ];
-
-			if ( node.parent === this ) {
-
-				node.setParent( undefined );
-
-			}
-
-		},
-
-		addObject: function ( object ) {
-
-			var index,
-				indexOctant,
-				node;
-
-			// get object octant index
-
-			indexOctant = this.getOctantIndex( object );
-
-			// if object fully contained by an octant, add to subtree
-			if ( indexOctant > - 1 && this.nodesIndices.length > 0 ) {
-
-				node = this.branch( indexOctant );
-
-				node.addObject( object );
-
-			} else if ( indexOctant < - 1 && this.parent instanceof THREE.OctreeNode ) {
-
-				// if object lies outside bounds, add to parent node
-
-				this.parent.addObject( object );
-
-			} else {
-
-				// add to this objects list
-
-				index = indexOfValue( this.objects, object );
-
-				if ( index === - 1 ) {
-
-					this.objects.push( object );
-
-				}
-
-				// node reference
-
-				object.node = this;
-
-				// check if need to expand, split, or both
-
-				this.checkGrow();
-
-			}
-
-		},
-
-		addObjectWithoutCheck: function ( objects ) {
-
-			var i, l,
-				object;
-
-			for ( i = 0, l = objects.length; i < l; i ++ ) {
-
-				object = objects[ i ];
-
-				this.objects.push( object );
-
-				object.node = this;
-
-			}
-
-		},
-
-		removeObject: function ( object ) {
-
-			var i, l,
-				nodesRemovedFrom,
-				removeData;
-
-			// cascade through tree to find and remove object
-
-			removeData = this.removeObjectRecursive( object, { searchComplete: false, nodesRemovedFrom: [], objectsDataRemoved: [] } );
-
-			// if object removed, try to shrink the nodes it was removed from
-
-			nodesRemovedFrom = removeData.nodesRemovedFrom;
-
-			if ( nodesRemovedFrom.length > 0 ) {
-
-				for ( i = 0, l = nodesRemovedFrom.length; i < l; i ++ ) {
-
-					nodesRemovedFrom[ i ].shrink();
-
-				}
-
-			}
-
-			return removeData.objectsDataRemoved;
-
-		},
-
-		removeObjectRecursive: function ( object, removeData ) {
-
-			var i, l,
-				index = - 1,
-				objectData,
-				node,
-				objectRemoved;
-
-			// find index of object in objects list
-
-			// search and remove object data (fast)
-			if ( object instanceof THREE.OctreeObjectData ) {
-
-				// remove from this objects list
-
-				index = indexOfValue( this.objects, object );
-
-				if ( index !== - 1 ) {
-
-					this.objects.splice( index, 1 );
-					object.node = undefined;
-
-					removeData.objectsDataRemoved.push( object );
-
-					removeData.searchComplete = objectRemoved = true;
-
-				}
-
-			} else {
-
-				// search each object data for object and remove (slow)
-
-				for ( i = this.objects.length - 1; i >= 0; i -- ) {
-
-					objectData = this.objects[ i ];
-
-					if ( objectData.object === object ) {
-
-						this.objects.splice( i, 1 );
-						objectData.node = undefined;
-
-						removeData.objectsDataRemoved.push( objectData );
-
-						objectRemoved = true;
-
-						if ( ! objectData.faces && ! objectData.vertices ) {
-
-							removeData.searchComplete = true;
-							break;
-
-						}
-
-					}
-
-				}
-
-			}
-
-			// if object data removed and this is not on nodes removed from
-
-			if ( objectRemoved === true ) {
-
-				removeData.nodesRemovedFrom.push( this );
-
-			}
-
-			// if search not complete, search nodes
-
-			if ( removeData.searchComplete !== true ) {
-
-				for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
-					node = this.nodesByIndex[ this.nodesIndices[ i ] ];
-
-					// try removing object from node
-
-					removeData = node.removeObjectRecursive( object, removeData );
-
-					if ( removeData.searchComplete === true ) {
-
-						break;
-
-					}
-
-				}
-
-			}
-
-			return removeData;
-
-		},
-
-		checkGrow: function () {
-
-			// if object count above max
-
-			if ( this.objects.length > this.tree.objectsThreshold && this.tree.objectsThreshold > 0 ) {
-
-				this.grow();
-
-			}
-
-		},
-
-		grow: function () {
-
-			var indexOctant,
-				object,
-				objectsExpand = [],
-				objectsExpandOctants = [],
-				objectsSplit = [],
-				objectsSplitOctants = [],
-				objectsRemaining = [],
-				i, l;
-
-			// for each object
-
-			for ( i = 0, l = this.objects.length; i < l; i ++ ) {
-
-				object = this.objects[ i ];
-
-				// get object octant index
-
-				indexOctant = this.getOctantIndex( object );
-
-				// if lies within octant
-				if ( indexOctant > - 1 ) {
-
-					objectsSplit.push( object );
-					objectsSplitOctants.push( indexOctant );
-
-				} else if ( indexOctant < - 1 ) {
-
-					// lies outside radius
-
-					objectsExpand.push( object );
-					objectsExpandOctants.push( indexOctant );
-
-				} else {
-
-					// lies across bounds between octants
-
-					objectsRemaining.push( object );
-
-				}
-
-			}
-
-			// if has objects to split
-
-			if ( objectsSplit.length > 0 ) {
-
-				objectsRemaining = objectsRemaining.concat( this.split( objectsSplit, objectsSplitOctants ) );
-
-			}
-
-			// if has objects to expand
-
-			if ( objectsExpand.length > 0 ) {
-
-				objectsRemaining = objectsRemaining.concat( this.expand( objectsExpand, objectsExpandOctants ) );
-
-			}
-
-			// store remaining
-
-			this.objects = objectsRemaining;
-
-			// merge check
-
-			this.checkMerge();
-
-		},
-
-		split: function ( objects, octants ) {
-
-			var i, l,
-				indexOctant,
-				object,
-				node,
-				objectsRemaining;
-
-			// if not at max depth
-
-			if ( this.depth < this.tree.depthMax ) {
-
-				objects = objects || this.objects;
-
-				octants = octants || [];
-
-				objectsRemaining = [];
-
-				// for each object
-
-				for ( i = 0, l = objects.length; i < l; i ++ ) {
-
-					object = objects[ i ];
-
-					// get object octant index
-
-					indexOctant = octants[ i ];
-
-					// if object contained by octant, branch this tree
-
-					if ( indexOctant > - 1 ) {
-
-						node = this.branch( indexOctant );
-
-						node.addObject( object );
-
-					} else {
-
-						objectsRemaining.push( object );
-
-					}
-
-				}
-
-				// if all objects, set remaining as new objects
-
-				if ( objects === this.objects ) {
-
-					this.objects = objectsRemaining;
-
-				}
-
-			} else {
-
-				objectsRemaining = this.objects;
-
-			}
-
-			return objectsRemaining;
-
-		},
-
-		branch: function ( indexOctant ) {
-
-			var node,
-				overlap,
-				radius,
-				radiusOffset,
-				offset,
-				position;
-
-			// node exists
-
-			if ( this.nodesByIndex[ indexOctant ] instanceof THREE.OctreeNode ) {
-
-				node = this.nodesByIndex[ indexOctant ];
-
-			} else {
-
-				// properties
-
-				radius = ( this.radiusOverlap ) * 0.5;
-				overlap = radius * this.tree.overlapPct;
-				radiusOffset = radius - overlap;
-				offset = this.utilVec31Branch.set( indexOctant & 1 ? radiusOffset : - radiusOffset, indexOctant & 2 ? radiusOffset : - radiusOffset, indexOctant & 4 ? radiusOffset : - radiusOffset );
-				position = new THREE.Vector3().addVectors( this.position, offset );
-
-				// node
-
-				node = new THREE.OctreeNode( {
-					tree: this.tree,
-					parent: this,
-					position: position,
-					radius: radius,
-					indexOctant: indexOctant
-				} );
-
-				// store
-
-				this.addNode( node, indexOctant );
-
-			}
-
-			return node;
-
-		},
-
-		expand: function ( objects, octants ) {
-
-			var i, l,
-				object,
-				objectsRemaining,
-				objectsExpand,
-				indexOctant,
-				flagsOutside,
-				indexOutside,
-				indexOctantInverse,
-				iom = this.tree.INDEX_OUTSIDE_MAP,
-				indexOutsideCounts,
-				infoIndexOutside1,
-				infoIndexOutside2,
-				infoIndexOutside3,
-				indexOutsideBitwise1,
-				indexOutsideBitwise2,
-				infoPotential1,
-				infoPotential2,
-				infoPotential3,
-				indexPotentialBitwise1,
-				indexPotentialBitwise2,
-				octantX, octantY, octantZ,
-				overlap,
-				radius,
-				radiusOffset,
-				radiusParent,
-				overlapParent,
-				offset = this.utilVec31Expand,
-				position,
-				parent;
-
-			// handle max depth down tree
-
-			if ( this.tree.root.getDepthEnd() < this.tree.depthMax ) {
-
-				objects = objects || this.objects;
-				octants = octants || [];
-
-				objectsRemaining = [];
-				objectsExpand = [];
-
-				// reset counts
-
-				for ( i = 0, l = iom.length; i < l; i ++ ) {
-
-					iom[ i ].count = 0;
-
-				}
-
-				// for all outside objects, find outside octants containing most objects
-
-				for ( i = 0, l = objects.length; i < l; i ++ ) {
-
-					object = objects[ i ];
-
-					// get object octant index
-
-					indexOctant = octants[ i ];
-
-					// if object outside this, include in calculations
-
-					if ( indexOctant < - 1 ) {
-
-						// convert octant index to outside flags
-
-						flagsOutside = - indexOctant - this.tree.INDEX_OUTSIDE_OFFSET;
-
-						// check against bitwise flags
-
-						// x
-
-						if ( flagsOutside & this.tree.FLAG_POS_X ) {
-
-							iom[ this.tree.INDEX_OUTSIDE_POS_X ].count ++;
-
-						} else if ( flagsOutside & this.tree.FLAG_NEG_X ) {
-
-							iom[ this.tree.INDEX_OUTSIDE_NEG_X ].count ++;
-
-						}
-
-						// y
-
-						if ( flagsOutside & this.tree.FLAG_POS_Y ) {
-
-							iom[ this.tree.INDEX_OUTSIDE_POS_Y ].count ++;
-
-						} else if ( flagsOutside & this.tree.FLAG_NEG_Y ) {
-
-							iom[ this.tree.INDEX_OUTSIDE_NEG_Y ].count ++;
-
-						}
-
-						// z
-
-						if ( flagsOutside & this.tree.FLAG_POS_Z ) {
-
-							iom[ this.tree.INDEX_OUTSIDE_POS_Z ].count ++;
-
-						} else if ( flagsOutside & this.tree.FLAG_NEG_Z ) {
-
-							iom[ this.tree.INDEX_OUTSIDE_NEG_Z ].count ++;
-
-						}
-
-						// store in expand list
-
-						objectsExpand.push( object );
-
-					} else {
-
-						objectsRemaining.push( object );
-
-					}
-
-				}
-
-				// if objects to expand
-
-				if ( objectsExpand.length > 0 ) {
-
-					// shallow copy index outside map
-
-					indexOutsideCounts = iom.slice( 0 );
-
-					// sort outside index count so highest is first
-
-					indexOutsideCounts.sort( function ( a, b ) {
-
-						return b.count - a.count;
-
-					} );
-
-					// get highest outside indices
-
-					// first is first
-					infoIndexOutside1 = indexOutsideCounts[ 0 ];
-					indexOutsideBitwise1 = infoIndexOutside1.index | 1;
-
-					// second is ( one of next two bitwise OR 1 ) that is not opposite of ( first bitwise OR 1 )
-
-					infoPotential1 = indexOutsideCounts[ 1 ];
-					infoPotential2 = indexOutsideCounts[ 2 ];
-
-					infoIndexOutside2 = ( infoPotential1.index | 1 ) !== indexOutsideBitwise1 ? infoPotential1 : infoPotential2;
-					indexOutsideBitwise2 = infoIndexOutside2.index | 1;
-
-					// third is ( one of next three bitwise OR 1 ) that is not opposite of ( first or second bitwise OR 1 )
-
-					infoPotential1 = indexOutsideCounts[ 2 ];
-					infoPotential2 = indexOutsideCounts[ 3 ];
-					infoPotential3 = indexOutsideCounts[ 4 ];
-
-					indexPotentialBitwise1 = infoPotential1.index | 1;
-					indexPotentialBitwise2 = infoPotential2.index | 1;
-
-					infoIndexOutside3 = indexPotentialBitwise1 !== indexOutsideBitwise1 && indexPotentialBitwise1 !== indexOutsideBitwise2 ? infoPotential1 : indexPotentialBitwise2 !== indexOutsideBitwise1 && indexPotentialBitwise2 !== indexOutsideBitwise2 ? infoPotential2 : infoPotential3;
-
-					// get this octant normal based on outside octant indices
-
-					octantX = infoIndexOutside1.x + infoIndexOutside2.x + infoIndexOutside3.x;
-					octantY = infoIndexOutside1.y + infoIndexOutside2.y + infoIndexOutside3.y;
-					octantZ = infoIndexOutside1.z + infoIndexOutside2.z + infoIndexOutside3.z;
-
-					// get this octant indices based on octant normal
-
-					indexOctant = this.getOctantIndexFromPosition( octantX, octantY, octantZ );
-					indexOctantInverse = this.getOctantIndexFromPosition( - octantX, - octantY, - octantZ );
-
-					// properties
-
-					overlap = this.overlap;
-					radius = this.radius;
-
-					// radius of parent comes from reversing overlap of this, unless overlap percent is 0
-
-					radiusParent = this.tree.overlapPct > 0 ? overlap / ( ( 0.5 * this.tree.overlapPct ) * ( 1 + this.tree.overlapPct ) ) : radius * 2;
-					overlapParent = radiusParent * this.tree.overlapPct;
-
-					// parent offset is difference between radius + overlap of parent and child
-
-					radiusOffset = ( radiusParent + overlapParent ) - ( radius + overlap );
-					offset.set( indexOctant & 1 ? radiusOffset : - radiusOffset, indexOctant & 2 ? radiusOffset : - radiusOffset, indexOctant & 4 ? radiusOffset : - radiusOffset );
-					position = new THREE.Vector3().addVectors( this.position, offset );
-
-					// parent
-
-					parent = new THREE.OctreeNode( {
-						tree: this.tree,
-						position: position,
-						radius: radiusParent
-					} );
-
-					// set self as node of parent
-
-					parent.addNode( this, indexOctantInverse );
-
-					// set parent as root
-
-					this.tree.setRoot( parent );
-
-					// add all expand objects to parent
-
-					for ( i = 0, l = objectsExpand.length; i < l; i ++ ) {
-
-						this.tree.root.addObject( objectsExpand[ i ] );
-
-					}
-
-				}
-
-				// if all objects, set remaining as new objects
-
-				if ( objects === this.objects ) {
-
-					this.objects = objectsRemaining;
-
-				}
-
-			} else {
-
-				objectsRemaining = objects;
-
-			}
-
-			return objectsRemaining;
-
-		},
-
-		shrink: function () {
-
-			// merge check
-
-			this.checkMerge();
-
-			// contract check
-
-			this.tree.root.checkContract();
-
-		},
-
-		checkMerge: function () {
-
-			var nodeParent = this,
-				nodeMerge;
-
-			// traverse up tree as long as node + entire subtree's object count is under minimum
-
-			while ( nodeParent.parent instanceof THREE.OctreeNode && nodeParent.getObjectCountEnd() < this.tree.objectsThreshold ) {
-
-				nodeMerge = nodeParent;
-				nodeParent = nodeParent.parent;
-
-			}
-
-			// if parent node is not this, merge entire subtree into merge node
-
-			if ( nodeParent !== this ) {
-
-				nodeParent.merge( nodeMerge );
-
-			}
-
-		},
-
-		merge: function ( nodes ) {
-
-			var i, l,
-				j, k,
-				node;
-
-			// handle nodes
-
-			nodes = toArray( nodes );
-
-			for ( i = 0, l = nodes.length; i < l; i ++ ) {
-
-				node = nodes[ i ];
-
-				// gather node + all subtree objects
-
-				this.addObjectWithoutCheck( node.getObjectsEnd() );
-
-				// reset node + entire subtree
-
-				node.reset( true, true );
-
-				// remove node
-
-				this.removeNode( node.indexOctant, node );
-
-			}
-
-			// merge check
-
-			this.checkMerge();
-
-		},
-
-		checkContract: function () {
-
-			var i, l,
-				node,
-				nodeObjectsCount,
-				nodeHeaviest,
-				nodeHeaviestObjectsCount,
-				outsideHeaviestObjectsCount;
-
-			// find node with highest object count
-
-			if ( this.nodesIndices.length > 0 ) {
-
-				nodeHeaviestObjectsCount = 0;
-				outsideHeaviestObjectsCount = this.objects.length;
-
-				for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
-					node = this.nodesByIndex[ this.nodesIndices[ i ] ];
-
-					nodeObjectsCount = node.getObjectCountEnd();
-					outsideHeaviestObjectsCount += nodeObjectsCount;
-
-					if ( nodeHeaviest instanceof THREE.OctreeNode === false || nodeObjectsCount > nodeHeaviestObjectsCount ) {
-
-						nodeHeaviest = node;
-						nodeHeaviestObjectsCount = nodeObjectsCount;
-
-					}
-
-				}
-
-				// subtract heaviest count from outside count
-
-				outsideHeaviestObjectsCount -= nodeHeaviestObjectsCount;
-
-				// if should contract
-
-				if ( outsideHeaviestObjectsCount < this.tree.objectsThreshold && nodeHeaviest instanceof THREE.OctreeNode ) {
-
-					this.contract( nodeHeaviest );
-
-				}
-
-			}
-
-		},
-
-		contract: function ( nodeRoot ) {
-
-			var i, l,
-				node;
-
-			// handle all nodes
-
-			for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
-				node = this.nodesByIndex[ this.nodesIndices[ i ] ];
-
-				// if node is not new root
-
-				if ( node !== nodeRoot ) {
-
-					// add node + all subtree objects to root
-
-					nodeRoot.addObjectWithoutCheck( node.getObjectsEnd() );
-
-					// reset node + entire subtree
-
-					node.reset( true, true );
-
-				}
-
-			}
-
-			// add own objects to root
-
-			nodeRoot.addObjectWithoutCheck( this.objects );
-
-			// reset self
-
-			this.reset( false, true );
-
-			// set new root
-
-			this.tree.setRoot( nodeRoot );
-
-			// contract check on new root
-
-			nodeRoot.checkContract();
-
-		},
-
-		getOctantIndex: function ( objectData ) {
-
-			var i, l,
-				positionObj,
-				radiusObj,
-				position = this.position,
-				radiusOverlap = this.radiusOverlap,
-				overlap = this.overlap,
-				deltaX, deltaY, deltaZ,
-				distX, distY, distZ,
-				distance,
-				indexOctant = 0;
-
-			// handle type
-
-			if ( objectData instanceof THREE.OctreeObjectData ) {
-
-				radiusObj = objectData.radius;
-
-				positionObj = objectData.position;
-
-				// update object data position last
-
-				objectData.positionLast.copy( positionObj );
-
-			} else if ( objectData instanceof THREE.OctreeNode ) {
-
-				positionObj = objectData.position;
-
-				radiusObj = 0;
-
-			}
-
-			// find delta and distance
-
-			deltaX = positionObj.x - position.x;
-			deltaY = positionObj.y - position.y;
-			deltaZ = positionObj.z - position.z;
-
-			distX = Math.abs( deltaX );
-			distY = Math.abs( deltaY );
-			distZ = Math.abs( deltaZ );
-			distance = Math.max( distX, distY, distZ );
-
-			// if outside, use bitwise flags to indicate on which sides object is outside of
-
-			if ( distance + radiusObj > radiusOverlap ) {
-
-				// x
-
-				if ( distX + radiusObj > radiusOverlap ) {
-
-					indexOctant = indexOctant ^ ( deltaX > 0 ? this.tree.FLAG_POS_X : this.tree.FLAG_NEG_X );
-
-				}
-
-				// y
-
-				if ( distY + radiusObj > radiusOverlap ) {
-
-					indexOctant = indexOctant ^ ( deltaY > 0 ? this.tree.FLAG_POS_Y : this.tree.FLAG_NEG_Y );
-
-				}
-
-				// z
-
-				if ( distZ + radiusObj > radiusOverlap ) {
-
-					indexOctant = indexOctant ^ ( deltaZ > 0 ? this.tree.FLAG_POS_Z : this.tree.FLAG_NEG_Z );
-
-				}
-
-				objectData.indexOctant = - indexOctant - this.tree.INDEX_OUTSIDE_OFFSET;
-
-				return objectData.indexOctant;
-
-			}
-
-			// return octant index from delta xyz
-
-			if ( deltaX - radiusObj > - overlap ) {
-
-				// x right
-
-				indexOctant = indexOctant | 1;
-
-			} else if ( ! ( deltaX + radiusObj < overlap ) ) {
-
-				// x left
-
-				objectData.indexOctant = this.tree.INDEX_INSIDE_CROSS;
-				return objectData.indexOctant;
-
-			}
-
-			if ( deltaY - radiusObj > - overlap ) {
-
-				// y right
-
-				indexOctant = indexOctant | 2;
-
-			} else if ( ! ( deltaY + radiusObj < overlap ) ) {
-
-				// y left
-
-				objectData.indexOctant = this.tree.INDEX_INSIDE_CROSS;
-				return objectData.indexOctant;
-
-			}
-
-
-			if ( deltaZ - radiusObj > - overlap ) {
-
-				// z right
-
-				indexOctant = indexOctant | 4;
-
-			} else if ( ! ( deltaZ + radiusObj < overlap ) ) {
-
-				// z left
-
-				objectData.indexOctant = this.tree.INDEX_INSIDE_CROSS;
-				return objectData.indexOctant;
-
-			}
-
-			objectData.indexOctant = indexOctant;
-			return objectData.indexOctant;
-
-		},
-
-		getOctantIndexFromPosition: function ( x, y, z ) {
-
-			var indexOctant = 0;
-
-			if ( x > 0 ) {
-
-				indexOctant = indexOctant | 1;
-
-			}
-
-			if ( y > 0 ) {
-
-				indexOctant = indexOctant | 2;
-
-			}
-
-			if ( z > 0 ) {
-
-				indexOctant = indexOctant | 4;
-
-			}
-
-			return indexOctant;
-
-		},
-
-		search: function ( position, radius, objects, direction, directionPct ) {
-
-			var i, l,
-				node,
-				intersects;
-
-			// test intersects by parameters
-
-			if ( direction ) {
-
-				intersects = this.intersectRay( position, direction, radius, directionPct );
-
-			} else {
-
-				intersects = this.intersectSphere( position, radius );
-
-			}
-
-			// if intersects
-
-			if ( intersects === true ) {
-
-				// gather objects
-
-				objects = objects.concat( this.objects );
-
-				// search subtree
-
-				for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
-					node = this.nodesByIndex[ this.nodesIndices[ i ] ];
-
-					objects = node.search( position, radius, objects, direction );
-
-				}
-
-			}
-
-			return objects;
-
-		},
-
-		intersectSphere: function ( position, radius ) {
-
-			var	distance = radius * radius,
-				px = position.x,
-				py = position.y,
-				pz = position.z;
-
-			if ( px < this.left ) {
-
-				distance -= Math.pow( px - this.left, 2 );
-
-			} else if ( px > this.right ) {
-
-				distance -= Math.pow( px - this.right, 2 );
-
-			}
-
-			if ( py < this.bottom ) {
-
-				distance -= Math.pow( py - this.bottom, 2 );
-
-			} else if ( py > this.top ) {
-
-				distance -= Math.pow( py - this.top, 2 );
-
-			}
-
-			if ( pz < this.back ) {
-
-				distance -= Math.pow( pz - this.back, 2 );
-
-			} else if ( pz > this.front ) {
-
-				distance -= Math.pow( pz - this.front, 2 );
-
-			}
-
-			return distance >= 0;
-
-		},
-
-		intersectRay: function ( origin, direction, distance, directionPct ) {
-
-			if ( typeof directionPct === 'undefined' ) {
-
-				directionPct = this.utilVec31Ray.set( 1, 1, 1 ).divide( direction );
-
-			}
-
-			var t1 = ( this.left - origin.x ) * directionPct.x,
-				t2 = ( this.right - origin.x ) * directionPct.x,
-				t3 = ( this.bottom - origin.y ) * directionPct.y,
-				t4 = ( this.top - origin.y ) * directionPct.y,
-				t5 = ( this.back - origin.z ) * directionPct.z,
-				t6 = ( this.front - origin.z ) * directionPct.z,
-				tmax = Math.min( Math.min( Math.max( t1, t2 ), Math.max( t3, t4 ) ), Math.max( t5, t6 ) ),
-				tmin;
-
-			// ray would intersect in reverse direction, i.e. this is behind ray
-			if ( tmax < 0 ) {
-
-				return false;
-
-			}
-
-			tmin = Math.max( Math.max( Math.min( t1, t2 ), Math.min( t3, t4 ) ), Math.min( t5, t6 ) );
-
-			// if tmin > tmax or tmin > ray distance, ray doesn't intersect AABB
-			if ( tmin > tmax || tmin > distance ) {
-
-				return false;
-
-			}
-
-			return true;
-
-		},
-
-		getDepthEnd: function ( depth ) {
-
-			var i, l,
-				node;
-
-			if ( this.nodesIndices.length > 0 ) {
-
-				for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
-					node = this.nodesByIndex[ this.nodesIndices[ i ] ];
-
-					depth = node.getDepthEnd( depth );
-
-				}
-
-			} else {
-
-				depth = ! depth || this.depth > depth ? this.depth : depth;
-
-			}
-
-			return depth;
-
-		},
-
-		getNodeCountEnd: function () {
-
-			return this.tree.root.getNodeCountRecursive() + 1;
-
-		},
-
-		getNodeCountRecursive: function () {
-
-			var i, l,
-				count = this.nodesIndices.length;
-
-			for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
-				count += this.nodesByIndex[ this.nodesIndices[ i ] ].getNodeCountRecursive();
-
-			}
-
-			return count;
-
-		},
-
-		getObjectsEnd: function ( objects ) {
-
-			var i, l,
-				node;
-
-			objects = ( objects || [] ).concat( this.objects );
-
-			for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
-				node = this.nodesByIndex[ this.nodesIndices[ i ] ];
-
-				objects = node.getObjectsEnd( objects );
-
-			}
-
-			return objects;
-
-		},
-
-		getObjectCountEnd: function () {
-
-			var i, l,
-				count = this.objects.length;
-
-			for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
-				count += this.nodesByIndex[ this.nodesIndices[ i ] ].getObjectCountEnd();
-
-			}
-
-			return count;
-
-		},
-
-		getObjectCountStart: function () {
-
-			var count = this.objects.length,
-				parent = this.parent;
-
-			while ( parent instanceof THREE.OctreeNode ) {
-
-				count += parent.objects.length;
-				parent = parent.parent;
-
-			}
-
-			return count;
-
-		},
-
-		toConsole: function ( space ) {
-
-			var i, l,
-				node,
-				spaceAddition = '   ';
-
-			space = typeof space === 'string' ? space : spaceAddition;
-
-			console.log( ( this.parent ? space + ' octree NODE > ' : ' octree ROOT > ' ), this, ' // id: ', this.id, ' // indexOctant: ', this.indexOctant, ' // position: ', this.position.x, this.position.y, this.position.z, ' // radius: ', this.radius, ' // depth: ', this.depth );
-			console.log( ( this.parent ? space + ' ' : ' ' ), '+ objects ( ', this.objects.length, ' ) ', this.objects );
-			console.log( ( this.parent ? space + ' ' : ' ' ), '+ children ( ', this.nodesIndices.length, ' )', this.nodesIndices, this.nodesByIndex );
-
-			for ( i = 0, l = this.nodesIndices.length; i < l; i ++ ) {
-
-				node = this.nodesByIndex[ this.nodesIndices[ i ] ];
-
-				node.toConsole( space + spaceAddition );
-
-			}
-
-		}
-
-	};
-
-	/*===================================================
-
-	raycaster additional functionality
-
-	=====================================================*/
-
-	THREE.Raycaster.prototype.intersectOctreeObject = function ( object, recursive ) {
-
-		var intersects,
-			octreeObject,
-			facesAll,
-			facesSearch;
-
-		if ( object.object instanceof THREE.Object3D ) {
-
-			octreeObject = object;
-			object = octreeObject.object;
-
-			// temporarily replace object geometry's faces with octree object faces
-
-			facesSearch = octreeObject.faces;
-			facesAll = object.geometry.faces;
-
-			if ( facesSearch.length > 0 ) {
-
-				object.geometry.faces = facesSearch;
-
-			}
-
-			// intersect
-
-			intersects = this.intersectObject( object, recursive );
-
-			// revert object geometry's faces
-
-			if ( facesSearch.length > 0 ) {
-
-				object.geometry.faces = facesAll;
-
-			}
-
-		} else {
-
-			intersects = this.intersectObject( object, recursive );
-
-		}
-
-		return intersects;
-
-	};
-
-	THREE.Raycaster.prototype.intersectOctreeObjects = function ( objects, recursive ) {
-
-		var i, il,
-			intersects = [];
-
-		for ( i = 0, il = objects.length; i < il; i ++ ) {
-
-			intersects = intersects.concat( this.intersectOctreeObject( objects[ i ], recursive ) );
-
-		}
-
-		return intersects;
-
-	};
-
-}( THREE ) );

+ 3 - 1
examples/js/VolumeSlice.js

@@ -196,13 +196,15 @@ THREE.VolumeSlice.prototype = {
 		this.ctx = this.canvas.getContext( '2d' );
 		this.ctxBuffer = this.canvasBuffer.getContext( '2d' );
 
+		if ( this.geometry ) this.geometry.dispose(); // dispose existing geometry
+
 		this.geometry = new THREE.PlaneBufferGeometry( extracted.planeWidth, extracted.planeHeight );
 
 		if ( this.mesh ) {
 
 			this.mesh.geometry = this.geometry;
 			//reset mesh matrix
-			this.mesh.matrix = ( new THREE.Matrix4() ).identity();
+			this.mesh.matrix.identity();
 			this.mesh.applyMatrix( this.matrix );
 
 		}

+ 13 - 13
examples/js/animation/MMDPhysics.js

@@ -1072,19 +1072,19 @@ THREE.MMDPhysics = ( function () {
 
 			var manager = this.manager;
 
-			var tr = this._getWorldTransformForBone();
-
-			var thV = manager.allocThreeVector3();
-
-			var o = manager.getOrigin( tr );
-			thV.set( o.x(), o.y(), o.z() );
-
-			var v = this.bone.worldToLocal( thV );
-			this.bone.position.add( v );
-
-			manager.freeThreeVector3( thV );
-
-			manager.freeTransform( tr );
+			var tr = this.body.getCenterOfMassTransform();
+			var origin = tr.getOrigin();
+			
+			var matrixInv = manager.allocThreeMatrix4();
+			matrixInv.copy( this.bone.parent.matrixWorld ).getInverse( matrixInv );
+			
+			var pos = manager.allocThreeVector3();
+			pos.set( origin.x(), origin.y(), origin.z() ).applyMatrix4( matrixInv );
+
+			this.bone.position.copy( pos );
+
+			manager.freeThreeVector3( pos );
+			manager.freeThreeMatrix4( matrixInv );
 
 		}
 

+ 3 - 2
examples/js/controls/EditorControls.js

@@ -32,6 +32,7 @@ THREE.EditorControls = function ( object, domElement ) {
 	var pointer = new THREE.Vector2();
 	var pointerOld = new THREE.Vector2();
 	var spherical = new THREE.Spherical();
+	var sphere = new THREE.Sphere();
 
 	// events
 
@@ -45,8 +46,8 @@ THREE.EditorControls = function ( object, domElement ) {
 
 		if ( box.isEmpty() === false ) {
 
-			center.copy( box.getCenter() );
-			distance = box.getBoundingSphere().radius;
+			box.getCenter( center );
+			distance = box.getBoundingSphere( sphere ).radius;
 
 		} else {
 

+ 28 - 17
examples/js/exporters/ColladaExporter.js

@@ -402,28 +402,35 @@ THREE.ColladaExporter.prototype = {
 
 					'</emission>' +
 
-					'<diffuse>' +
-
 					(
-						m.map ?
-							'<texture texture="diffuse-sampler" texcoord="TEXCOORD" />' :
-							`<color sid="diffuse">${ diffuse.r } ${ diffuse.g } ${ diffuse.b } 1</color>`
+						type !== 'constant' ?
+						'<diffuse>' +
+
+						(
+							m.map ?
+								'<texture texture="diffuse-sampler" texcoord="TEXCOORD" />' :
+								`<color sid="diffuse">${ diffuse.r } ${ diffuse.g } ${ diffuse.b } 1</color>`
+						) +
+						'</diffuse>'
+						: ''
 					) +
 
-					'</diffuse>' +
+					(
+						type === 'phong' ?
+						`<specular><color sid="specular">${ specular.r } ${ specular.g } ${ specular.b } 1</color></specular>` +
 
-					`<specular><color sid="specular">${ specular.r } ${ specular.g } ${ specular.b } 1</color></specular>` +
+						'<shininess>' +
 
-					'<shininess>' +
+						(
+							m.specularMap ?
+								'<texture texture="specular-sampler" texcoord="TEXCOORD" />' :
+								`<float sid="shininess">${ shininess }</float>`
+						) +
 
-					(
-						m.specularMap ?
-							'<texture texture="specular-sampler" texcoord="TEXCOORD" />' :
-							`<float sid="shininess">${ shininess }</float>`
+						'</shininess>' 
+						: ''
 					) +
 
-					'</shininess>' +
-
 					`<reflective><color>${ diffuse.r } ${ diffuse.g } ${ diffuse.b } 1</color></reflective>` +
 
 					`<reflectivity><float>${ reflectivity }</float></reflectivity>` +
@@ -502,17 +509,21 @@ THREE.ColladaExporter.prototype = {
 
 				// ids of the materials to bind to the geometry
 				var matids = null;
+				var matidsArray = [];
 
 				// get a list of materials to bind to the sub groups of the geometry.
 				// If the amount of subgroups is greater than the materials, than reuse
 				// the materials.
 				var mat = o.material || new THREE.MeshBasicMaterial();
 				var materials = Array.isArray( mat ) ? mat : [ mat ];
-				matids = new Array( geometry.groups.length )
-					.fill()
+				if ( geometry.groups.length > materials.length ) {
+					matidsArray = new Array( geometry.groups.length );
+				} else {
+					matidsArray = new Array( materials.length )
+				}
+				matids = matidsArray.fill()
 					.map( ( v, i ) => processMaterial( materials[ i % materials.length ] ) );
 
-
 				node +=
 					`<instance_geometry url="#${ meshid }">` +
 

+ 66 - 19
examples/js/exporters/GLTFExporter.js

@@ -28,19 +28,26 @@ var WEBGL_CONSTANTS = {
 	NEAREST_MIPMAP_NEAREST: 0x2700,
 	LINEAR_MIPMAP_NEAREST: 0x2701,
 	NEAREST_MIPMAP_LINEAR: 0x2702,
-	LINEAR_MIPMAP_LINEAR: 0x2703
-};
+	LINEAR_MIPMAP_LINEAR: 0x2703,
 
-var THREE_TO_WEBGL = {
-	// @TODO Replace with computed property name [THREE.*] when available on es6
-	1003: WEBGL_CONSTANTS.NEAREST,
-	1004: WEBGL_CONSTANTS.NEAREST_MIPMAP_NEAREST,
-	1005: WEBGL_CONSTANTS.NEAREST_MIPMAP_LINEAR,
-	1006: WEBGL_CONSTANTS.LINEAR,
-	1007: WEBGL_CONSTANTS.LINEAR_MIPMAP_NEAREST,
-	1008: WEBGL_CONSTANTS.LINEAR_MIPMAP_LINEAR
+	CLAMP_TO_EDGE: 33071,
+	MIRRORED_REPEAT: 33648,
+	REPEAT: 10497
 };
 
+var THREE_TO_WEBGL = {};
+
+THREE_TO_WEBGL[ THREE.NearestFilter ] = WEBGL_CONSTANTS.NEAREST;
+THREE_TO_WEBGL[ THREE.NearestMipMapNearestFilter ] = WEBGL_CONSTANTS.NEAREST_MIPMAP_NEAREST;
+THREE_TO_WEBGL[ THREE.NearestMipMapLinearFilter ] = WEBGL_CONSTANTS.NEAREST_MIPMAP_LINEAR;
+THREE_TO_WEBGL[ THREE.LinearFilter ] = WEBGL_CONSTANTS.LINEAR;
+THREE_TO_WEBGL[ THREE.LinearMipMapNearestFilter ] = WEBGL_CONSTANTS.LINEAR_MIPMAP_NEAREST;
+THREE_TO_WEBGL[ THREE.LinearMipMapLinearFilter ] = WEBGL_CONSTANTS.LINEAR_MIPMAP_LINEAR;
+
+THREE_TO_WEBGL[ THREE.ClampToEdgeWrapping ] = WEBGL_CONSTANTS.CLAMP_TO_EDGE;
+THREE_TO_WEBGL[ THREE.RepeatWrapping ] = WEBGL_CONSTANTS.REPEAT;
+THREE_TO_WEBGL[ THREE.MirroredRepeatWrapping ] = WEBGL_CONSTANTS.MIRRORED_REPEAT;
+
 var PATH_PROPERTIES = {
 	scale: 'scale',
 	position: 'translation',
@@ -104,7 +111,9 @@ THREE.GLTFExporter.prototype = {
 		var extensionsUsed = {};
 		var cachedData = {
 
+			meshes: new Map(),
 			attributes: new Map(),
+			attributesNormalized: new Map(),
 			materials: new Map(),
 			textures: new Map(),
 			images: new Map()
@@ -214,7 +223,7 @@ THREE.GLTFExporter.prototype = {
 		 */
 		function isNormalizedNormalAttribute( normal ) {
 
-			if ( cachedData.attributes.has( normal ) ) {
+			if ( cachedData.attributesNormalized.has( normal ) ) {
 
 				return false;
 
@@ -242,9 +251,9 @@ THREE.GLTFExporter.prototype = {
 		 */
 		function createNormalizedNormalAttribute( normal ) {
 
-			if ( cachedData.attributes.has( normal ) ) {
+			if ( cachedData.attributesNormalized.has( normal ) ) {
 
-				return cachedData.attributes.get( normal );
+				return cachedData.attributesNormalized.get( normal );
 
 			}
 
@@ -271,7 +280,7 @@ THREE.GLTFExporter.prototype = {
 
 			}
 
-			cachedData.attributes.set( normal, attribute );
+			cachedData.attributesNormalized.set( normal, attribute );
 
 			return attribute;
 
@@ -1001,6 +1010,13 @@ THREE.GLTFExporter.prototype = {
 		 */
 		function processMesh( mesh ) {
 
+			var cacheKey = mesh.geometry.uuid + ':' + mesh.material.uuid;
+			if ( cachedData.meshes.has( cacheKey ) ) {
+
+				return cachedData.meshes.get( cacheKey );
+
+			}
+
 			var geometry = mesh.geometry;
 
 			var mode;
@@ -1083,23 +1099,32 @@ THREE.GLTFExporter.prototype = {
 				var attribute = geometry.attributes[ attributeName ];
 				attributeName = nameConversion[ attributeName ] || attributeName.toUpperCase();
 
+				if ( cachedData.attributes.has( attribute ) ) {
+
+					attributes[ attributeName ] = cachedData.attributes.get( attribute );
+					continue;
+
+				}
+
 				// JOINTS_0 must be UNSIGNED_BYTE or UNSIGNED_SHORT.
+				var modifiedAttribute;
 				var array = attribute.array;
 				if ( attributeName === 'JOINTS_0' &&
 					! ( array instanceof Uint16Array ) &&
 					! ( array instanceof Uint8Array ) ) {
 
 					console.warn( 'GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.' );
-					attribute = new THREE.BufferAttribute( new Uint16Array( array ), attribute.itemSize, attribute.normalized );
+					modifiedAttribute = new THREE.BufferAttribute( new Uint16Array( array ), attribute.itemSize, attribute.normalized );
 
 				}
 
 				if ( attributeName.substr( 0, 5 ) !== 'MORPH' ) {
 
-					var accessor = processAccessor( attribute, geometry );
+					var accessor = processAccessor( modifiedAttribute || attribute, geometry );
 					if ( accessor !== null ) {
 
 						attributes[ attributeName ] = accessor;
+						cachedData.attributes.set( attribute, accessor );
 
 					}
 
@@ -1158,6 +1183,7 @@ THREE.GLTFExporter.prototype = {
 						}
 
 						var attribute = geometry.morphAttributes[ attributeName ][ i ];
+						var gltfAttributeName = attributeName.toUpperCase();
 
 						// Three.js morph attribute has absolute values while the one of glTF has relative values.
 						//
@@ -1165,6 +1191,14 @@ THREE.GLTFExporter.prototype = {
 						// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#morph-targets
 
 						var baseAttribute = geometry.attributes[ attributeName ];
+
+						if ( cachedData.attributes.has( baseAttribute ) ) {
+
+							target[ gltfAttributeName ] = cachedData.attributes.get( baseAttribute );
+							continue;
+
+						}
+
 						// Clones attribute not to override
 						var relativeAttribute = attribute.clone();
 
@@ -1179,7 +1213,8 @@ THREE.GLTFExporter.prototype = {
 
 						}
 
-						target[ attributeName.toUpperCase() ] = processAccessor( relativeAttribute, geometry );
+						target[ gltfAttributeName ] = processAccessor( relativeAttribute, geometry );
+						cachedData.attributes.set( baseAttribute, target[ gltfAttributeName ] );
 
 					}
 
@@ -1250,7 +1285,16 @@ THREE.GLTFExporter.prototype = {
 
 				if ( geometry.index !== null ) {
 
-					primitive.indices = processAccessor( geometry.index, geometry, groups[ i ].start, groups[ i ].count );
+					if ( cachedData.attributes.has( geometry.index ) ) {
+
+						primitive.indices = cachedData.attributes.get( geometry.index );
+
+					} else {
+
+						primitive.indices = processAccessor( geometry.index, geometry, groups[ i ].start, groups[ i ].count );
+						cachedData.attributes.set( geometry.index, primitive.indices );
+
+					}
 
 				}
 
@@ -1282,7 +1326,10 @@ THREE.GLTFExporter.prototype = {
 
 			outputJSON.meshes.push( gltfMesh );
 
-			return outputJSON.meshes.length - 1;
+			var index = outputJSON.meshes.length - 1;
+			cachedData.meshes.set( cacheKey, index );
+
+			return index;
 
 		}
 

+ 1005 - 0
examples/js/geometries/LightningStrike.js

@@ -0,0 +1,1005 @@
+/**
+ * @author yomboprime https://github.com/yomboprime
+ *
+ * @fileoverview LightningStrike object for creating lightning strikes and voltaic arcs.
+ * 
+ * 
+ * Usage
+ * 
+ * var myRay = new THREE.LightningStrike( paramsObject );
+ * var myRayMesh = new THREE.Mesh( myRay, myMaterial );
+ * scene.add( myRayMesh );
+ * ...
+ * myRay.update( currentTime );
+ * 
+ * The "currentTime" can vary its rate, go forwards, backwards or even jump, but it cannot be negative.
+ * 
+ * You should normally leave the ray position to (0, 0, 0). You should control it by changing the sourceOffset and destOffset parameters.
+ * 
+ * 
+ * LightningStrike parameters
+ * 
+ * The paramsObject can contain any of the following parameters.
+ * 
+ * Legend:
+ * 'LightningStrike' (also called 'ray'): An independent voltaic arc with its ramifications and defined with a set of parameters.
+ * 'Subray': A ramification of the ray. It is not a LightningStrike object.
+ * 'Segment': A linear segment piece of a subray.
+ * 'Leaf segment': A ray segment which cannot be smaller.
+ * 
+ * 
+ * The following parameters can be changed any time and if they vary smoothly, the ray form will also change smoothly:
+ * 
+ * @param {Vector3} sourceOffset The point where the ray starts.
+ * 
+ * @param {Vector3} destOffset The point where the ray ends.
+ * 
+ * @param {double} timeScale The rate at wich the ray form changes in time. Default: 1
+ * 
+ * @param {double} roughness From 0 to 1. The higher the value, the more wrinkled is the ray. Default: 0.9
+ * 
+ * @param {double} straightness From 0 to 1. The higher the value, the more straight will be a subray path. Default: 0.7
+ * 
+ * @param {Vector3} up0 Ray 'up' direction at the ray starting point. Must be normalized. It should be perpendicular to the ray forward direction but it doesn't matter much.
+ * 
+ * @param {Vector3} up1 Like the up0 parameter but at the end of the ray. Must be normalized.
+ * 
+ * @param {double} radius0 Radius of the main ray trunk at the start point. Default: 1
+ * 
+ * @param {double} radius1 Radius of the main ray trunk at the end point. Default: 1
+ * 
+ * @param {double} radius0Factor The radius0 of a subray is this factor times the radius0 of its parent subray. Default: 0.5
+ * 
+ * @param {double} radius1Factor The radius1 of a subray is this factor times the radius1 of its parent subray. Default: 0.2
+ * 
+ * @param {minRadius} Minimum value a subray radius0 or radius1 can get. Default: 0.1
+ * 
+ * 
+ * The following parameters should not be changed after lightning creation. They can be changed but the ray will change its form abruptly:
+ * 
+ * @param {boolean} isEternal If true the ray never extinguishes. Otherwise its life is controlled by the 'birthTime' and 'deathTime' parameters. Default: true if any of those two parameters is undefined.
+ * 
+ * @param {double} birthTime The time at which the ray starts its life and begins propagating. Only if isEternal is false. Default: None.
+ * 
+ * @param {double} deathTime The time at which the ray ends vanishing and its life. Only if isEternal is false. Default: None.
+ * 
+ * @param {double} propagationTimeFactor From 0 to 1. Lifetime factor at which the ray ends propagating and enters the steady phase. For example, 0.1 means it is propagating 1/10 of its lifetime. Default: 0.1
+ * 
+ * @param {double} vanishingTimeFactor From 0 to 1. Lifetime factor at which the ray ends the steady phase and begins vanishing. For example, 0.9 means it is vanishing 1/10 of its lifetime. Default: 0.9
+ * 
+ * @param {double} subrayPeriod Subrays cycle periodically. This is their time period. Default: 4
+ * 
+ * @param {double} subrayDutyCycle From 0 to 1. This is the fraction of time a subray is active. Default: 0.6
+ * 
+ * 
+ * These parameters cannot change after lightning creation:
+ * 
+ * @param {integer} maxIterations: Greater than 0. The number of ray's leaf segments is 2**maxIterations. Default: 9
+ * 
+ * @param {boolean} isStatic Set to true only for rays which won't change over time and are not attached to moving objects (Rare case). It is used to set the vertex buffers non-dynamic. You can omit calling update() for these rays.
+ *  
+ * @param {integer} ramification Greater than 0. Maximum number of child subrays a subray can have. Default: 5
+ *
+ * @param {integer} maxSubrayRecursion Greater than 0. Maximum level of recursion (subray descendant generations). Default: 3 
+ *
+ * @param {double} recursionProbability From 0 to 1. The lower the value, the less chance each new generation of subrays has to generate new subrays. Default: 0.6
+ *
+ * @param {boolean} generateUVs If true, the ray geometry will have uv coordinates generated. u runs along the ray, and v across its perimeter. Default: false.
+ *
+ * @param {Object} randomGenerator Set here your random number generator which will seed the SimplexNoise and other decisions during ray tree creation.
+ * It can be used to generate repeatable rays. For that, set also the noiseSeed parameter, and each ray created with that generator and seed pair will be identical in time.
+ * The randomGenerator parameter should be an object with a random() function similar to Math.random, but seedable.
+ * It must have also a getSeed() method, which returns the current seed, and a setSeed( seed ) method, which accepts as seed a fractional number from 0 to 1, as well as any other number.
+ * The default value is an internal generator for some uses and Math.random for others (It is non-repeatable even if noiseSeed is supplied)
+ * 
+ * @param {double} noiseSeed Seed used to make repeatable rays (see the randomGenerator)
+ * 
+ * @param {function} onDecideSubrayCreation Set this to change the callback which decides subray creation. You can look at the default callback in the code (createDefaultSubrayCreationCallbacks)for more info.
+ * 
+ * @param {function} onSubrayCreation This is another callback, more simple than the previous one. It can be used to adapt the form of subrays or other parameters once a subray has been created and initialized. It is used in the examples to adapt subrays to a sphere or to a plane.
+ * 
+ *
+*/
+
+THREE.LightningStrike = function ( rayParameters ) {
+
+	THREE.BufferGeometry.call( this );
+
+	this.type = 'LightningStrike';
+
+	// Set parameters, and set undefined parameters to default values
+	rayParameters = rayParameters || {};
+	this.init( THREE.LightningStrike.copyParameters( rayParameters, rayParameters ) );
+
+	// Creates and populates the mesh
+	this.createMesh();
+
+};
+
+THREE.LightningStrike.prototype = Object.create( THREE.BufferGeometry.prototype );
+
+THREE.LightningStrike.prototype.constructor = THREE.LightningStrike;
+
+THREE.LightningStrike.prototype.isLightningStrike = true;
+
+// Ray states
+THREE.LightningStrike.RAY_INITIALIZED = 0;
+THREE.LightningStrike.RAY_UNBORN = 1;
+THREE.LightningStrike.RAY_PROPAGATING = 2;
+THREE.LightningStrike.RAY_STEADY = 3;
+THREE.LightningStrike.RAY_VANISHING = 4;
+THREE.LightningStrike.RAY_EXTINGUISHED = 5;
+
+THREE.LightningStrike.COS30DEG = Math.cos( 30 * Math.PI / 180 );
+THREE.LightningStrike.SIN30DEG = Math.sin( 30 * Math.PI / 180 );
+
+THREE.LightningStrike.createRandomGenerator = function () {
+
+	var numSeeds = 2053;
+	var seeds = [];
+
+	for ( var i = 0; i < numSeeds; i++ ) {
+
+		seeds.push( Math.random() );
+
+	}
+
+	var generator = {
+
+		currentSeed: 0,
+
+		random: function () {
+
+			var value = seeds[ generator.currentSeed ];
+
+			generator.currentSeed = ( generator.currentSeed + 1 ) % numSeeds;
+
+			return value;
+
+		},
+
+		getSeed: function () {
+
+			return generator.currentSeed / numSeeds;
+
+		},
+
+		setSeed: function ( seed ) {
+
+			generator.currentSeed = Math.floor( seed * numSeeds ) % numSeeds;
+
+		}
+
+	};
+
+	return generator;
+
+};
+
+THREE.LightningStrike.copyParameters = function ( dest, source) {
+
+	source = source || {};
+	dest = dest || {};
+
+	var vecCopy = function( v ) {
+
+		if ( source === dest ) {
+
+			return v;
+
+		}
+		else {
+
+			return v.clone();
+
+		}
+
+	}
+
+	dest.sourceOffset = source.sourceOffset !== undefined ? vecCopy( source.sourceOffset ) : new THREE.Vector3( 0, 100, 0 ),
+	dest.destOffset = source.destOffset !== undefined ? vecCopy( source.destOffset ) : new THREE.Vector3( 0, 0, 0 ),
+
+	dest.timeScale = source.timeScale !== undefined ? source.timeScale : 1,
+	dest.roughness = source.roughness !== undefined ? source.roughness : 0.9,
+	dest.straightness = source.straightness !== undefined ? source.straightness : 0.7,
+
+	dest.up0 = source.up0 !== undefined ? vecCopy( source.up0 ) : new THREE.Vector3( 0, 0, 1 );
+	dest.up1 = source.up1 !== undefined ? vecCopy( source.up1 ) : new THREE.Vector3( 0, 0, 1 ),
+	dest.radius0 = source.radius0 !== undefined ? source.radius0 : 1,
+	dest.radius1 = source.radius1 !== undefined ? source.radius1 : 1,
+	dest.radius0Factor = source.radius0Factor !== undefined ? source.radius0Factor : 0.5,
+	dest.radius1Factor = source.radius1Factor !== undefined ? source.radius1Factor : 0.2,
+	dest.minRadius = source.minRadius !== undefined ? source.minRadius : 0.2,
+
+	// These parameters should not be changed after lightning creation. They can be changed but the ray will change its form abruptly:
+
+	dest.isEternal = source.isEternal !== undefined ? source.isEternal : ( source.birthTime === undefined || source.deathTime === undefined ),
+	dest.birthTime = source.birthTime,
+	dest.deathTime = source.deathTime,
+	dest.propagationTimeFactor = source.propagationTimeFactor !== undefined ? source.propagationTimeFactor : 0.1,
+	dest.vanishingTimeFactor = source.vanishingTimeFactor !== undefined ? source.vanishingTimeFactor : 0.9,
+	dest.subrayPeriod = source.subrayPeriod !== undefined ? source.subrayPeriod : 4,
+	dest.subrayDutyCycle = source.subrayDutyCycle !== undefined ? source.subrayDutyCycle : 0.6;
+
+	// These parameters cannot change after lightning creation:
+
+	dest.maxIterations =  source.maxIterations !== undefined ? source.maxIterations : 9;
+	dest.isStatic = source.isStatic !== undefined ? source.isStatic : false;
+	dest.ramification = source.ramification !== undefined ? source.ramification : 5;
+	dest.maxSubrayRecursion = source.maxSubrayRecursion !== undefined ? source.maxSubrayRecursion : 3;
+	dest.recursionProbability = source.recursionProbability !== undefined ? source.recursionProbability : 0.6;
+	dest.generateUVs = source.generateUVs !== undefined ? source.generateUVs : false;
+	dest.randomGenerator = source.randomGenerator,
+	dest.noiseSeed = source.noiseSeed,
+	dest.onDecideSubrayCreation = source.onDecideSubrayCreation,
+	dest.onSubrayCreation = source.onSubrayCreation;
+
+	return dest;
+
+};
+
+THREE.LightningStrike.prototype.update = function ( time ) {
+
+	if ( this.isStatic ) {
+		return;
+	}
+	
+	if ( this.rayParameters.isEternal || ( this.rayParameters.birthTime <= time && time <= this.rayParameters.deathTime ) ) {
+
+		this.updateMesh( time );
+
+		if ( time < this.subrays[ 0 ].endPropagationTime ) {
+		
+			this.state = THREE.LightningStrike.RAY_PROPAGATING;
+
+		}	
+		else if ( time > this.subrays[ 0 ].beginVanishingTime ) {
+
+			this.state = THREE.LightningStrike.RAY_VANISHING;
+
+		}
+		else {
+
+			this.state = THREE.LightningStrike.RAY_STEADY;
+
+		}
+
+		this.visible = true;
+
+	}
+	else {
+
+		this.visible = false;
+
+		if ( time < this.rayParameters.birthTime ) {
+
+			this.state = THREE.LightningStrike.RAY_UNBORN;
+
+		}
+		else {
+
+			this.state = THREE.LightningStrike.RAY_EXTINGUISHED;
+
+		}
+
+	}
+
+};
+
+THREE.LightningStrike.prototype.init = function ( rayParameters ) {
+
+	// Init all the state from the parameters
+
+	this.rayParameters = rayParameters;
+
+	// These parameters cannot change after lightning creation:
+
+	this.maxIterations =  rayParameters.maxIterations !== undefined ? Math.floor( rayParameters.maxIterations ) : 9;
+	rayParameters.maxIterations = this.maxIterations;
+	this.isStatic = rayParameters.isStatic !== undefined ? rayParameters.isStatic : false;
+	rayParameters.isStatic = this.isStatic;
+	this.ramification = rayParameters.ramification !== undefined ? Math.floor( rayParameters.ramification ) : 5;
+	rayParameters.ramification = this.ramification;
+	this.maxSubrayRecursion = rayParameters.maxSubrayRecursion !== undefined ? Math.floor( rayParameters.maxSubrayRecursion ) : 3;
+	rayParameters.maxSubrayRecursion = this.maxSubrayRecursion;
+	this.recursionProbability = rayParameters.recursionProbability !== undefined ? rayParameters.recursionProbability : 0.6;
+	rayParameters.recursionProbability = this.recursionProbability;
+	this.generateUVs = rayParameters.generateUVs !== undefined ? rayParameters.generateUVs : false;
+	rayParameters.generateUVs = this.generateUVs;
+
+	// Random generator
+	if ( rayParameters.randomGenerator !== undefined ) {
+
+		this.randomGenerator = rayParameters.randomGenerator;
+		this.seedGenerator = rayParameters.randomGenerator;
+
+		if ( rayParameters.noiseSeed !== undefined ) {
+		
+			this.seedGenerator.setSeed( rayParameters.noiseSeed );
+
+		}
+
+	}
+	else {
+
+		this.randomGenerator = THREE.LightningStrike.createRandomGenerator();
+		this.seedGenerator = Math;
+
+	}
+
+	// Ray creation callbacks
+	if ( rayParameters.onDecideSubrayCreation !== undefined ) {
+
+		this.onDecideSubrayCreation = rayParameters.onDecideSubrayCreation;
+
+	}
+	else {
+
+		this.createDefaultSubrayCreationCallbacks();
+
+		if ( rayParameters.onSubrayCreation !== undefined ) {
+
+			this.onSubrayCreation = rayParameters.onSubrayCreation;
+
+		}
+
+	}
+
+	// Internal state
+
+	this.state = THREE.LightningStrike.RAY_INITIALIZED;
+
+	this.maxSubrays = Math.ceil( 1 + Math.pow( this.ramification, Math.max( 0, this.maxSubrayRecursion - 1 ) ) );
+	rayParameters.maxSubrays = this.maxSubrays;
+	
+	this.maxRaySegments = 2 * ( 1 << this.maxIterations );
+
+	this.subrays = [];
+
+	for ( var i = 0; i < this.maxSubrays; i++ ) {
+
+		this.subrays.push( this.createSubray() );
+
+	}
+
+	this.raySegments = [];
+
+	for ( var i = 0; i < this.maxRaySegments; i++ ) {
+
+		this.raySegments.push( this.createSegment() );
+
+	}
+
+	this.time = 0;
+	this.timeFraction = 0;
+	this.currentSegmentCallback = null;
+	this.currentCreateTriangleVertices = this.generateUVs ? this.createTriangleVerticesWithUVs : this.createTriangleVerticesWithoutUVs;
+	this.numSubrays = 0;
+	this.currentSubray = null;
+	this.currentSegmentIndex = 0;
+	this.isInitialSegment = false;
+	this.subrayProbability = 0;
+
+	this.currentVertex = 0;
+	this.currentIndex = 0;
+	this.currentCoordinate = 0;
+	this.currentUVCoordinate = 0;
+	this.vertices = null;
+	this.uvs = null;
+	this.indices = null;
+	this.positionAttribute = null;
+	this.uvsAttribute = null;
+	
+	this.simplexX = new SimplexNoise( this.seedGenerator );
+	this.simplexY = new SimplexNoise( this.seedGenerator );
+	this.simplexZ = new SimplexNoise( this.seedGenerator );
+
+	// Temp vectors
+	this.forwards = new THREE.Vector3();
+	this.forwardsFill = new THREE.Vector3();
+	this.side = new THREE.Vector3();
+	this.down = new THREE.Vector3();
+	this.middlePos = new THREE.Vector3();
+	this.middleLinPos = new THREE.Vector3();
+	this.newPos = new THREE.Vector3();
+	this.vPos = new THREE.Vector3();
+	this.cross1 = new THREE.Vector3();
+
+};
+
+THREE.LightningStrike.prototype.createMesh = function () {
+
+	var maxDrawableSegmentsPerSubRay = 1 << this.maxIterations;
+	
+	var maxVerts = 3 * ( maxDrawableSegmentsPerSubRay + 1 ) * this.maxSubrays;
+	var maxIndices = 18 * maxDrawableSegmentsPerSubRay * this.maxSubrays;
+
+	this.vertices = new Float32Array( maxVerts * 3 );
+	this.indices = new Uint32Array( maxIndices );
+	if ( this.generateUVs ) {
+		this.uvs = new Float32Array( maxVerts * 2 );
+	}
+
+	// Populate the mesh
+	this.fillMesh( 0 );
+	
+	this.setIndex( new THREE.Uint32BufferAttribute( this.indices, 1 ) );
+
+	this.positionAttribute = new THREE.Float32BufferAttribute( this.vertices, 3 );
+	this.addAttribute( 'position', this.positionAttribute );
+
+	if ( this.generateUVs ) {1
+		this.uvsAttribute = new THREE.Float32BufferAttribute( new Float32Array( this.uvs ), 2 );
+		this.addAttribute( 'uv', this.uvsAttribute );
+	}
+
+	if ( ! this.isStatic ) {
+		this.index.dynamic = true;
+		this.positionAttribute.dynamic = true;
+		if ( this.generateUVs ) {
+			this.uvsAttribute.dynamic = true;
+		}
+	}
+
+	// Store buffers for later modification
+	this.vertices = this.positionAttribute.array;
+	this.indices = this.index.array;
+	if ( this.generateUVs ) {
+		this.uvs = this.uvsAttribute.array;
+	}
+
+};
+	
+THREE.LightningStrike.prototype.updateMesh = function ( time ) {
+
+	this.fillMesh( time );
+
+	this.drawRange.count = this.currentIndex;
+
+	this.index.needsUpdate = true;
+
+	this.positionAttribute.needsUpdate = true;
+
+	if ( this.generateUVs ) {
+		this.uvsAttribute.needsUpdate = true;
+	}
+
+};
+
+THREE.LightningStrike.prototype.fillMesh = function ( time ) {
+
+	var scope = this;
+
+	this.currentVertex = 0;
+	this.currentIndex = 0;
+	this.currentCoordinate = 0;
+	this.currentUVCoordinate = 0;
+
+	this.fractalRay( time, function fillVertices ( segment ) {
+
+		var subray = scope.currentSubray;
+
+		if ( time < subray.birthTime ) {//&& ( ! this.rayParameters.isEternal || scope.currentSubray.recursion > 0 ) ) {
+
+			return;
+
+		}
+		else if ( this.rayParameters.isEternal && scope.currentSubray.recursion == 0 ) {
+
+			// Eternal rays don't propagate nor vanish, but its subrays do
+
+			scope.createPrism( segment );
+
+			scope.onDecideSubrayCreation( segment, scope );
+
+		}
+		else if ( time < subray.endPropagationTime ) {
+
+			if ( scope.timeFraction >= segment.fraction0 * subray.propagationTimeFactor ) {
+
+				// Ray propagation has arrived to this segment
+
+				scope.createPrism( segment );
+
+				scope.onDecideSubrayCreation( segment, scope );
+
+			}
+
+		}
+		else if ( time < subray.beginVanishingTime ) {
+
+			// Ray is steady (nor propagating nor vanishing)
+
+			scope.createPrism( segment );
+
+			scope.onDecideSubrayCreation( segment, scope );
+
+		}
+		else {
+
+			if ( scope.timeFraction <= subray.vanishingTimeFactor + segment.fraction1  * ( 1 - subray.vanishingTimeFactor ) ) {
+
+				// Segment has not yet vanished
+
+				scope.createPrism( segment );
+
+			}
+
+			scope.onDecideSubrayCreation( segment, scope );
+
+		}
+
+	} );
+
+};
+
+THREE.LightningStrike.prototype.addNewSubray = function ( rayParameters ) {
+
+	return this.subrays[ this.numSubrays++ ];
+
+};
+
+THREE.LightningStrike.prototype.initSubray = function ( subray, rayParameters ) {
+
+	subray.pos0.copy( rayParameters.sourceOffset );
+	subray.pos1.copy( rayParameters.destOffset );
+	subray.up0.copy( rayParameters.up0 );
+	subray.up1.copy( rayParameters.up1 );
+	subray.radius0 = rayParameters.radius0;
+	subray.radius1 = rayParameters.radius1;
+	subray.birthTime = rayParameters.birthTime;
+	subray.deathTime = rayParameters.deathTime;
+	subray.timeScale = rayParameters.timeScale;
+	subray.roughness = rayParameters.roughness;
+	subray.straightness = rayParameters.straightness;
+	subray.propagationTimeFactor = rayParameters.propagationTimeFactor;
+	subray.vanishingTimeFactor = rayParameters.vanishingTimeFactor;
+
+	subray.maxIterations = this.maxIterations;
+	subray.seed = rayParameters.noiseSeed !== undefined ? rayParameters.noiseSeed : 0;
+	subray.recursion = 0;
+
+};
+
+THREE.LightningStrike.prototype.fractalRay = function ( time, segmentCallback ) {
+
+	this.time = time;
+	this.currentSegmentCallback = segmentCallback;
+	this.numSubrays = 0;
+
+	// Add the top level subray
+	this.initSubray( this.addNewSubray(), this.rayParameters );
+
+	// Process all subrays that are being generated until consuming all of them
+	for ( var subrayIndex = 0; subrayIndex < this.numSubrays; subrayIndex++ ) {
+
+		var subray = this.subrays[ subrayIndex ];
+		this.currentSubray = subray;
+
+		this.randomGenerator.setSeed( subray.seed );
+
+		subray.endPropagationTime = THREE.Math.lerp( subray.birthTime, subray.deathTime, subray.propagationTimeFactor );
+		subray.beginVanishingTime = THREE.Math.lerp( subray.deathTime, subray.birthTime, 1 - subray.vanishingTimeFactor );
+
+		var random1 = this.randomGenerator.random;
+		subray.linPos0.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+		subray.linPos1.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+
+		this.timeFraction = ( time - subray.birthTime ) / ( subray.deathTime - subray.birthTime );
+
+		this.currentSegmentIndex  = 0;
+		this.isInitialSegment = true;
+
+		var segment = this.getNewSegment();
+		segment.iteration = 0;
+		segment.pos0.copy( subray.pos0 );
+		segment.pos1.copy( subray.pos1 );
+		segment.linPos0.copy( subray.linPos0 );
+		segment.linPos1.copy( subray.linPos1 );
+		segment.up0.copy( subray.up0 );
+		segment.up1.copy( subray.up1 );
+		segment.radius0 = subray.radius0;
+		segment.radius1 = subray.radius1;
+		segment.fraction0 = 0;
+		segment.fraction1 = 1;
+		segment.positionVariationFactor = 1 - subray.straightness;
+
+		this.subrayProbability = this.ramification * Math.pow( this.recursionProbability, subray.recursion ) / ( 1 << subray.maxIterations );
+
+		this.fractalRayRecursive( segment );
+
+	}
+
+	this.currentSegmentCallback = null;
+	this.currentSubray = null;
+
+};
+
+THREE.LightningStrike.prototype.fractalRayRecursive = function ( segment ) {
+
+	// Leave recursion condition
+	if ( segment.iteration >= this.currentSubray.maxIterations ) {
+
+		this.currentSegmentCallback( segment );
+
+		return;
+
+	}
+
+	// Interpolation
+	this.forwards.subVectors( segment.pos1, segment.pos0 );
+	var lForwards = this.forwards.length();
+
+	if ( lForwards < 0.000001) {
+		this.forwards.set( 0, 0, 0.01 );
+		lForwards = this.forwards.length();
+	}
+
+	var middleRadius = ( segment.radius0 + segment.radius1 ) * 0.5;
+	var middleFraction = ( segment.fraction0 + segment.fraction1 ) * 0.5;
+
+	var timeDimension = this.time * this.currentSubray.timeScale * Math.pow( 2, segment.iteration );
+
+	this.middlePos.lerpVectors( segment.pos0, segment.pos1, 0.5 );
+	this.middleLinPos.lerpVectors( segment.linPos0, segment.linPos1, 0.5 );
+	var p = this.middleLinPos;
+
+	// Noise	
+	this.newPos.set( this.simplexX.noise4d( p.x, p.y, p.z, timeDimension ),
+						this.simplexY.noise4d( p.x, p.y, p.z, timeDimension ),
+						this.simplexZ.noise4d( p.x, p.y, p.z, timeDimension ) );
+
+	this.newPos.multiplyScalar( segment.positionVariationFactor * lForwards );
+	this.newPos.add( this.middlePos );
+
+	// Recursion
+
+	var newSegment1 = this.getNewSegment();
+	newSegment1.pos0.copy( segment.pos0 );
+	newSegment1.pos1.copy( this.newPos );
+	newSegment1.linPos0.copy( segment.linPos0 );
+	newSegment1.linPos1.copy( this.middleLinPos );
+	newSegment1.up0.copy( segment.up0 );
+	newSegment1.up1.copy( segment.up1 );
+	newSegment1.radius0 = segment.radius0;
+	newSegment1.radius1 = middleRadius;
+	newSegment1.fraction0 = segment.fraction0;
+	newSegment1.fraction1 = middleFraction;
+	newSegment1.positionVariationFactor = segment.positionVariationFactor * this.currentSubray.roughness;
+	newSegment1.iteration = segment.iteration + 1;
+
+	var newSegment2 = this.getNewSegment();
+	newSegment2.pos0.copy( this.newPos );
+	newSegment2.pos1.copy( segment.pos1 );
+	newSegment2.linPos0.copy( this.middleLinPos );
+	newSegment2.linPos1.copy( segment.linPos1 );
+	this.cross1.crossVectors( segment.up0, this.forwards.normalize() );
+	newSegment2.up0.crossVectors( this.forwards, this.cross1 ).normalize();
+	newSegment2.up1.copy( segment.up1 );
+	newSegment2.radius0 = middleRadius;
+	newSegment2.radius1 = segment.radius1;
+	newSegment2.fraction0 = middleFraction;
+	newSegment2.fraction1 = segment.fraction1;
+	newSegment2.positionVariationFactor = segment.positionVariationFactor * this.currentSubray.roughness;
+	newSegment2.iteration = segment.iteration + 1;
+
+	this.fractalRayRecursive( newSegment1 );
+
+	this.fractalRayRecursive( newSegment2 );
+
+};
+
+THREE.LightningStrike.prototype.createPrism = function ( segment ) {
+
+	// Creates one triangular prism and its vertices at the segment
+
+	this.forwardsFill.subVectors( segment.pos1, segment.pos0 ).normalize();
+
+	if ( this.isInitialSegment ) {
+
+		this.currentCreateTriangleVertices( segment.pos0, segment.up0, this.forwardsFill, segment.radius0, 0 );
+		
+		this.isInitialSegment = false;
+
+	}
+
+	this.currentCreateTriangleVertices( segment.pos1, segment.up0, this.forwardsFill, segment.radius1, segment.fraction1 );
+
+	this.createPrismFaces();
+
+};
+
+THREE.LightningStrike.prototype.createTriangleVerticesWithoutUVs = function ( pos, up, forwards, radius ) {
+
+	// Create an equilateral triangle (only vertices)
+	
+	this.side.crossVectors( up, forwards ).multiplyScalar( radius * THREE.LightningStrike.COS30DEG );
+	this.down.copy( up ).multiplyScalar( - radius * THREE.LightningStrike.SIN30DEG );
+
+	var p = this.vPos;
+	var v = this.vertices;
+
+	p.copy( pos ).sub( this.side ).add( this.down );
+
+	v[ this.currentCoordinate++ ] = p.x;
+	v[ this.currentCoordinate++ ] = p.y;
+	v[ this.currentCoordinate++ ] = p.z;
+
+	p.copy( pos ).add( this.side ).add( this.down );
+
+	v[ this.currentCoordinate++ ] = p.x;
+	v[ this.currentCoordinate++ ] = p.y;
+	v[ this.currentCoordinate++ ] = p.z;
+
+	p.copy( up ).multiplyScalar( radius ).add( pos );
+	
+	v[ this.currentCoordinate++ ] = p.x;
+	v[ this.currentCoordinate++ ] = p.y;
+	v[ this.currentCoordinate++ ] = p.z;
+
+	this.currentVertex += 3;
+
+};
+
+THREE.LightningStrike.prototype.createTriangleVerticesWithUVs = function ( pos, up, forwards, radius, u ) {
+
+	// Create an equilateral triangle (only vertices)
+	
+	this.side.crossVectors( up, forwards ).multiplyScalar( radius * THREE.LightningStrike.COS30DEG );
+	this.down.copy( up ).multiplyScalar( - radius * THREE.LightningStrike.SIN30DEG );
+
+	var p = this.vPos;
+	var v = this.vertices;
+	var uv = this.uvs;
+
+	p.copy( pos ).sub( this.side ).add( this.down );
+
+	v[ this.currentCoordinate++ ] = p.x;
+	v[ this.currentCoordinate++ ] = p.y;
+	v[ this.currentCoordinate++ ] = p.z;
+
+	uv[ this.currentUVCoordinate++ ] = u;
+	uv[ this.currentUVCoordinate++ ] = 0;
+
+	p.copy( pos ).add( this.side ).add( this.down );
+
+	v[ this.currentCoordinate++ ] = p.x;
+	v[ this.currentCoordinate++ ] = p.y;
+	v[ this.currentCoordinate++ ] = p.z;
+
+	uv[ this.currentUVCoordinate++ ] = u;
+	uv[ this.currentUVCoordinate++ ] = 0.5;
+
+	p.copy( up ).multiplyScalar( radius ).add( pos );
+	
+	v[ this.currentCoordinate++ ] = p.x;
+	v[ this.currentCoordinate++ ] = p.y;
+	v[ this.currentCoordinate++ ] = p.z;
+
+	uv[ this.currentUVCoordinate++ ] = u;
+	uv[ this.currentUVCoordinate++ ] = 1;
+
+	this.currentVertex += 3;
+
+};
+
+THREE.LightningStrike.prototype.createPrismFaces = function ( vertex, index ) {
+
+	var indices = this.indices;
+	var vertex = this.currentVertex - 6;
+
+	indices[ this.currentIndex++ ] = vertex + 1;
+	indices[ this.currentIndex++ ] = vertex + 2;
+	indices[ this.currentIndex++ ] = vertex + 5;
+	indices[ this.currentIndex++ ] = vertex + 1;
+	indices[ this.currentIndex++ ] = vertex + 5;
+	indices[ this.currentIndex++ ] = vertex + 4;
+	indices[ this.currentIndex++ ] = vertex + 0;
+	indices[ this.currentIndex++ ] = vertex + 1;
+	indices[ this.currentIndex++ ] = vertex + 4;
+	indices[ this.currentIndex++ ] = vertex + 0;
+	indices[ this.currentIndex++ ] = vertex + 4;
+	indices[ this.currentIndex++ ] = vertex + 3;
+	indices[ this.currentIndex++ ] = vertex + 2;
+	indices[ this.currentIndex++ ] = vertex + 0;
+	indices[ this.currentIndex++ ] = vertex + 3;
+	indices[ this.currentIndex++ ] = vertex + 2;
+	indices[ this.currentIndex++ ] = vertex + 3;
+	indices[ this.currentIndex++ ] = vertex + 5;
+
+};
+
+THREE.LightningStrike.prototype.createDefaultSubrayCreationCallbacks = function () {
+
+	var random1 = this.randomGenerator.random;
+
+	this.onDecideSubrayCreation = function ( segment, lightningStrike ) {
+
+		// Decide subrays creation at parent (sub)ray segment
+
+		var subray = lightningStrike.currentSubray;
+
+		var period = lightningStrike.rayParameters.subrayPeriod;
+		var dutyCycle = lightningStrike.rayParameters.subrayDutyCycle;
+		
+		var phase0 = ( lightningStrike.rayParameters.isEternal && subray.recursion == 0 ) ? - random1() * period : THREE.Math.lerp( subray.birthTime, subray.endPropagationTime, segment.fraction0 ) - random1() * period;
+		
+		var phase = lightningStrike.time - phase0;
+		var currentCycle = Math.floor( phase / period );
+
+		var childSubraySeed = random1() * ( currentCycle + 1 );
+
+		var isActive = phase % period <= dutyCycle * period;
+
+		probability = lightningStrike.subrayProbability;
+		var probability = 0;
+		if ( isActive ) {
+			probability = lightningStrike.subrayProbability;
+			// Distribution test: probability *= segment.fraction0 > 0.5 && segment.fraction0 < 0.9 ? 1 / 0.4 : 0;
+		}
+
+		if ( subray.recursion < lightningStrike.maxSubrayRecursion && lightningStrike.numSubrays < lightningStrike.maxSubrays && random1() < probability ) {
+
+			var childSubray = lightningStrike.addNewSubray();
+
+			var parentSeed = lightningStrike.randomGenerator.getSeed();
+			childSubray.seed = childSubraySeed;
+			lightningStrike.randomGenerator.setSeed( childSubraySeed );
+
+			childSubray.recursion = subray.recursion + 1;
+			childSubray.maxIterations = Math.max( 1, subray.maxIterations - 1 );
+
+			childSubray.linPos0.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+			childSubray.linPos1.set( random1(), random1(), random1() ).multiplyScalar( 1000 );;
+			childSubray.up0.copy( subray.up0 );
+			childSubray.up1.copy( subray.up1 );
+			childSubray.radius0 = segment.radius0 * lightningStrike.rayParameters.radius0Factor;
+			childSubray.radius1 = Math.min( lightningStrike.rayParameters.minRadius, segment.radius1 * lightningStrike.rayParameters.radius1Factor );
+			
+			childSubray.birthTime = phase0 + ( currentCycle ) * period;
+			childSubray.deathTime = childSubray.birthTime + period * dutyCycle;
+
+			if ( ! lightningStrike.rayParameters.isEternal && subray.recursion == 0 ) {
+
+				childSubray.birthTime = Math.max( childSubray.birthTime, subray.birthTime );
+				childSubray.deathTime = Math.min( childSubray.deathTime, subray.deathTime );
+
+			}
+
+			childSubray.timeScale = subray.timeScale * 2;
+			childSubray.roughness = subray.roughness;
+			childSubray.straightness = subray.straightness;
+			childSubray.propagationTimeFactor = subray.propagationTimeFactor;
+			childSubray.vanishingTimeFactor = subray.vanishingTimeFactor;
+
+			lightningStrike.onSubrayCreation( segment, subray, childSubray, lightningStrike );
+
+			lightningStrike.randomGenerator.setSeed( parentSeed );
+
+		}
+
+	};
+
+	var vec1Pos = new THREE.Vector3();
+	var vec2Forward = new THREE.Vector3();
+	var vec3Side = new THREE.Vector3();
+	var vec4Up = new THREE.Vector3();
+	
+	this.onSubrayCreation = function ( segment, parentSubray, childSubray, lightningStrike ) {
+
+		// Decide childSubray origin and destination positions (pos0 and pos1) and possibly other properties of childSubray
+
+		// Just use the default cone position generator
+		lightningStrike.subrayCylinderPosition( segment, parentSubray, childSubray, 0.5, 0.6, 0.2 );
+
+	};
+
+	this.subrayConePosition = function ( segment, parentSubray, childSubray, heightFactor, sideWidthFactor, minSideWidthFactor ) {
+		
+		// Sets childSubray pos0 and pos1 in a cone
+		
+		childSubray.pos0.copy( segment.pos0 );
+
+		vec1Pos.subVectors( parentSubray.pos1, parentSubray.pos0 );
+		vec2Forward.copy( vec1Pos ).normalize();
+		vec1Pos.multiplyScalar( segment.fraction0 + ( 1 - segment.fraction0 ) * ( random1() * heightFactor ) );
+		var length = vec1Pos.length();
+		vec3Side.crossVectors( parentSubray.up0, vec2Forward );
+		var angle = 2 * Math.PI * random1();
+		vec3Side.multiplyScalar( Math.cos ( angle ) );
+		vec4Up.copy( parentSubray.up0 ).multiplyScalar( Math.sin ( angle ) );
+
+		childSubray.pos1.copy( vec3Side ).add( vec4Up ).multiplyScalar( length * sideWidthFactor * ( minSideWidthFactor + random1() * ( 1 - minSideWidthFactor ) ) ).add( vec1Pos ).add( parentSubray.pos0 );
+
+	}
+
+	this.subrayCylinderPosition = function ( segment, parentSubray, childSubray, heightFactor, sideWidthFactor, minSideWidthFactor ) {
+		
+		// Sets childSubray pos0 and pos1 in a cylinder
+
+		childSubray.pos0.copy( segment.pos0 );
+
+		vec1Pos.subVectors( parentSubray.pos1, parentSubray.pos0 );
+		vec2Forward.copy( vec1Pos ).normalize();
+		vec1Pos.multiplyScalar( segment.fraction0 + ( 1 - segment.fraction0 ) * ( ( 2 * random1() - 1 ) * heightFactor ) );
+		var length = vec1Pos.length();
+		vec3Side.crossVectors( parentSubray.up0, vec2Forward );
+		var angle = 2 * Math.PI * random1();
+		vec3Side.multiplyScalar( Math.cos ( angle ) );
+		vec4Up.copy( parentSubray.up0 ).multiplyScalar( Math.sin ( angle ) );
+
+		childSubray.pos1.copy( vec3Side ).add( vec4Up ).multiplyScalar( length * sideWidthFactor * ( minSideWidthFactor + random1() * ( 1 - minSideWidthFactor ) ) ).add( vec1Pos ).add( parentSubray.pos0 );
+
+	}
+
+};
+
+THREE.LightningStrike.prototype.createSubray = function () {
+
+	return {
+
+		seed: 0,
+		maxIterations: 0,
+		recursion: 0,
+		pos0: new THREE.Vector3(),
+		pos1: new THREE.Vector3(),
+		linPos0: new THREE.Vector3(),
+		linPos1: new THREE.Vector3(),
+		up0: new THREE.Vector3(),
+		up1: new THREE.Vector3(),
+		radius0: 0,
+		radius1: 0,
+		birthTime: 0,
+		deathTime: 0,
+		timeScale: 0,
+		roughness: 0,
+		straightness: 0,
+		propagationTimeFactor: 0,
+		vanishingTimeFactor: 0,
+		endPropagationTime: 0,
+		beginVanishingTime: 0
+
+	};
+
+};
+
+THREE.LightningStrike.prototype.createSegment = function () {
+
+	return {
+		iteration: 0,
+		pos0: new THREE.Vector3(),
+		pos1: new THREE.Vector3(),
+		linPos0: new THREE.Vector3(),
+		linPos1: new THREE.Vector3(),
+		up0: new THREE.Vector3(),
+		up1: new THREE.Vector3(),
+		radius0: 0,
+		radius1: 0,
+		fraction0: 0,
+		fraction1: 0,
+		positionVariationFactor: 0
+	}
+
+};
+
+THREE.LightningStrike.prototype.getNewSegment = function () {
+
+	return this.raySegments[ this.currentSegmentIndex++ ];
+
+};
+
+THREE.LightningStrike.prototype.copy = function ( source ) {
+	
+	BufferGeometry.prototype.copy.call( this, source );
+
+	this.init( THREE.LightningStrike.copyParameters( {}, source.rayParameters ) );
+
+	return this;
+
+};
+
+THREE.LightningStrike.prototype.clone = function () {
+
+	return new this.constructor( THREE.LightningStrike.copyParameters( {}, this.rayParameters ) );
+
+};

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

@@ -1228,6 +1228,8 @@ THREE.ColladaLoader.prototype = {
 					case 'emission':
 					case 'diffuse':
 					case 'specular':
+					case 'bump':
+					case 'ambient':
 					case 'shininess':
 					case 'transparency':
 						data[ child.nodeName ] = parseEffectParameter( child );
@@ -1590,6 +1592,12 @@ THREE.ColladaLoader.prototype = {
 						if ( parameter.color && material.specular ) material.specular.fromArray( parameter.color );
 						if ( parameter.texture ) material.specularMap = getTexture( parameter.texture );
 						break;
+					case 'bump':
+						if ( parameter.texture ) material.normalMap = getTexture( parameter.texture );
+						break;
+					case 'ambient':
+						if ( parameter.texture ) material.lightMap = getTexture( parameter.texture );
+						break;
 					case 'shininess':
 						if ( parameter.float && material.shininess ) material.shininess = parameter.float;
 						break;
@@ -2122,7 +2130,9 @@ THREE.ColladaLoader.prototype = {
 						var id = parseId( child.getAttribute( 'source' ) );
 						var semantic = child.getAttribute( 'semantic' );
 						var offset = parseInt( child.getAttribute( 'offset' ) );
-						primitive.inputs[ semantic ] = { id: id, offset: offset };
+						var set = parseInt( child.getAttribute( 'set' ) );
+						var inputname = ( set > 0 ? semantic + set : semantic );
+						primitive.inputs[ inputname ] = { id: id, offset: offset };
 						primitive.stride = Math.max( primitive.stride, offset + 1 );
 						if ( semantic === 'TEXCOORD' ) primitive.hasUV = true;
 						break;
@@ -2225,6 +2235,7 @@ THREE.ColladaLoader.prototype = {
 			var position = { array: [], stride: 0 };
 			var normal = { array: [], stride: 0 };
 			var uv = { array: [], stride: 0 };
+			var uv2 = { array: [], stride: 0 };
 			var color = { array: [], stride: 0 };
 
 			var skinIndex = { array: [], stride: 4 };
@@ -2357,6 +2368,11 @@ THREE.ColladaLoader.prototype = {
 										uv.stride = sources[ id ].stride;
 										break;
 
+									case 'TEXCOORD1':
+										buildGeometryData( primitive, sources[ id ], input.offset, uv2.array );
+										uv.stride = sources[ id ].stride;
+										break;
+
 									default:
 										console.warn( 'THREE.ColladaLoader: Semantic "%s" not handled in geometry build process.', key );
 
@@ -2380,6 +2396,11 @@ THREE.ColladaLoader.prototype = {
 							uv.stride = sources[ input.id ].stride;
 							break;
 
+						case 'TEXCOORD1':
+							buildGeometryData( primitive, sources[ input.id ], input.offset, uv2.array );
+							uv2.stride = sources[ input.id ].stride;
+							break;
+
 					}
 
 				}
@@ -2392,6 +2413,7 @@ THREE.ColladaLoader.prototype = {
 			if ( normal.array.length > 0 ) geometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( normal.array, normal.stride ) );
 			if ( color.array.length > 0 ) geometry.addAttribute( 'color', new THREE.Float32BufferAttribute( color.array, color.stride ) );
 			if ( uv.array.length > 0 ) geometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( uv.array, uv.stride ) );
+			if ( uv2.array.length > 0 ) geometry.addAttribute( 'uv2', new THREE.Float32BufferAttribute( uv2.array, uv2.stride ) );
 
 			if ( skinIndex.array.length > 0 ) geometry.addAttribute( 'skinIndex', new THREE.Float32BufferAttribute( skinIndex.array, skinIndex.stride ) );
 			if ( skinWeight.array.length > 0 ) geometry.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( skinWeight.array, skinWeight.stride ) );

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

@@ -1231,6 +1231,7 @@ THREE.FBXLoader = ( function () {
 				} );
 
 				model = new THREE.SkinnedMesh( geometry, material );
+				model.normalizeSkinWeights();
 
 			} else {
 

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

@@ -1611,12 +1611,12 @@ THREE.GLTFLoader = ( function () {
 			var itemSize = attribute.itemSize;
 			var array = attribute.array.slice( 0, count * itemSize );
 
-			for ( var i = 0; i < count; ++ i ) {
+			for ( var i = 0, j = 0; i < count; ++ i ) {
 
-				array[ i ] = attribute.getX( i );
-				if ( itemSize >= 2 ) array[ i + 1 ] = attribute.getY( i );
-				if ( itemSize >= 3 ) array[ i + 2 ] = attribute.getZ( i );
-				if ( itemSize >= 4 ) array[ i + 3 ] = attribute.getW( i );
+				array[ j ++ ] = attribute.getX( i );
+				if ( itemSize >= 2 ) array[ j ++ ] = attribute.getY( i );
+				if ( itemSize >= 3 ) array[ j ++ ] = attribute.getZ( i );
+				if ( itemSize >= 4 ) array[ j ++ ] = attribute.getW( i );
 
 			}
 
@@ -3129,16 +3129,16 @@ THREE.GLTFLoader = ( function () {
 
 		var nodeDef = json.nodes[ nodeIndex ];
 
-		return new Promise( function ( resolve ) {
+		return ( function() {
 
 			// .isBone isn't in glTF spec. See .markDefs
 			if ( nodeDef.isBone === true ) {
 
-				resolve( new THREE.Bone() );
+				return Promise.resolve( new THREE.Bone() );
 
 			} else if ( nodeDef.mesh !== undefined ) {
 
-				parser.getDependency( 'mesh', nodeDef.mesh ).then( function ( mesh ) {
+				return parser.getDependency( 'mesh', nodeDef.mesh ).then( function ( mesh ) {
 
 					var node;
 
@@ -3165,27 +3165,44 @@ THREE.GLTFLoader = ( function () {
 
 					}
 
-					resolve( node );
+					// if weights are provided on the node, override weights on the mesh.
+					if ( nodeDef.weights !== undefined ) {
+
+						node.traverse( function ( o ) {
+
+							if ( ! o.isMesh ) return;
+
+							for ( var i = 0, il = nodeDef.weights.length; i < il; i ++ ) {
+
+								o.morphTargetInfluences[ i ] = nodeDef.weights[ i ];
+
+							}
+
+						} );
+
+					}
+
+					return node;
 
 				} );
 
 			} else if ( nodeDef.camera !== undefined ) {
 
-				parser.getDependency( 'camera', nodeDef.camera ).then( resolve );
+				return parser.getDependency( 'camera', nodeDef.camera );
 
 			} else if ( nodeDef.extensions
 				&& nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ]
 				&& nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].light !== undefined ) {
 
-				parser.getDependency( 'light', nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].light ).then( resolve );
+				return parser.getDependency( 'light', nodeDef.extensions[ EXTENSIONS.KHR_LIGHTS_PUNCTUAL ].light );
 
 			} else {
 
-				resolve( new THREE.Object3D() );
+				return Promise.resolve( new THREE.Object3D() );
 
 			}
 
-		} ).then( function ( node ) {
+		}() ).then( function ( node ) {
 
 			if ( nodeDef.name !== undefined ) {
 

+ 18 - 24
examples/js/loaders/KTXLoader.js

@@ -68,23 +68,24 @@ var KhronosTextureContainer = ( function () {
 
 		}
 
-		// load the reset of the header in native 32 bit int
-		var header = new Int32Array( this.arrayBuffer, 12, 13 );
-		// determine of the remaining header values are recorded in the opposite endianness & require conversion
-		var oppositeEndianess = header[ 0 ] === 0x01020304;
-		// read all the header elements in order they exist in the file, without modification (sans endainness)
-		this.glType = oppositeEndianess ? this.switchEndainness( header[ 1 ] ) : header[ 1 ]; // must be 0 for compressed textures
-		this.glTypeSize = oppositeEndianess ? this.switchEndainness( header[ 2 ] ) : header[ 2 ]; // must be 1 for compressed textures
-		this.glFormat = oppositeEndianess ? this.switchEndainness( header[ 3 ] ) : header[ 3 ]; // must be 0 for compressed textures
-		this.glInternalFormat = oppositeEndianess ? this.switchEndainness( header[ 4 ] ) : header[ 4 ]; // the value of arg passed to gl.compressedTexImage2D(,,x,,,,)
-		this.glBaseInternalFormat = oppositeEndianess ? this.switchEndainness( header[ 5 ] ) : header[ 5 ]; // specify GL_RGB, GL_RGBA, GL_ALPHA, etc (un-compressed only)
-		this.pixelWidth = oppositeEndianess ? this.switchEndainness( header[ 6 ] ) : header[ 6 ]; // level 0 value of arg passed to gl.compressedTexImage2D(,,,x,,,)
-		this.pixelHeight = oppositeEndianess ? this.switchEndainness( header[ 7 ] ) : header[ 7 ]; // level 0 value of arg passed to gl.compressedTexImage2D(,,,,x,,)
-		this.pixelDepth = oppositeEndianess ? this.switchEndainness( header[ 8 ] ) : header[ 8 ]; // level 0 value of arg passed to gl.compressedTexImage3D(,,,,,x,,)
-		this.numberOfArrayElements = oppositeEndianess ? this.switchEndainness( header[ 9 ] ) : header[ 9 ]; // used for texture arrays
-		this.numberOfFaces = oppositeEndianess ? this.switchEndainness( header[ 10 ] ) : header[ 10 ]; // used for cubemap textures, should either be 1 or 6
-		this.numberOfMipmapLevels = oppositeEndianess ? this.switchEndainness( header[ 11 ] ) : header[ 11 ]; // number of levels; disregard possibility of 0 for compressed textures
-		this.bytesOfKeyValueData = oppositeEndianess ? this.switchEndainness( header[ 12 ] ) : header[ 12 ]; // the amount of space after the header for meta-data
+		// load the reset of the header in native 32 bit uint
+		var dataSize = Uint32Array.BYTES_PER_ELEMENT;
+		var headerDataView = new DataView( this.arrayBuffer, 12, 13 * dataSize );
+		var endianness = headerDataView.getUint32( 0, true );
+		var littleEndian = endianness === 0x04030201;
+
+		this.glType = headerDataView.getUint32( 1 * dataSize, littleEndian ); // must be 0 for compressed textures
+		this.glTypeSize = headerDataView.getUint32( 2 * dataSize, littleEndian ); // must be 1 for compressed textures
+		this.glFormat = headerDataView.getUint32( 3 * dataSize, littleEndian ); // must be 0 for compressed textures
+		this.glInternalFormat = headerDataView.getUint32( 4 * dataSize, littleEndian ); // the value of arg passed to gl.compressedTexImage2D(,,x,,,,)
+		this.glBaseInternalFormat = headerDataView.getUint32( 5 * dataSize, littleEndian ); // specify GL_RGB, GL_RGBA, GL_ALPHA, etc (un-compressed only)
+		this.pixelWidth = headerDataView.getUint32( 6 * dataSize, littleEndian ); // level 0 value of arg passed to gl.compressedTexImage2D(,,,x,,,)
+		this.pixelHeight = headerDataView.getUint32( 7 * dataSize, littleEndian ); // level 0 value of arg passed to gl.compressedTexImage2D(,,,,x,,)
+		this.pixelDepth = headerDataView.getUint32( 8 * dataSize, littleEndian ); // level 0 value of arg passed to gl.compressedTexImage3D(,,,,,x,,)
+		this.numberOfArrayElements = headerDataView.getUint32( 9 * dataSize, littleEndian ); // used for texture arrays
+		this.numberOfFaces = headerDataView.getUint32( 10 * dataSize, littleEndian ); // used for cubemap textures, should either be 1 or 6
+		this.numberOfMipmapLevels = headerDataView.getUint32( 11 * dataSize, littleEndian ); // number of levels; disregard possibility of 0 for compressed textures
+		this.bytesOfKeyValueData = headerDataView.getUint32( 12 * dataSize, littleEndian ); // the amount of space after the header for meta-data
 
 		// Make sure we have a compressed type.  Not only reduces work, but probably better to let dev know they are not compressing.
 		if ( this.glType !== 0 ) {
@@ -122,13 +123,6 @@ var KhronosTextureContainer = ( function () {
 
 	}
 
-	// not as fast hardware based, but will probably never need to use
-	KhronosTextureContainer.prototype.switchEndainness = function ( val ) {
-
-		return ( ( val & 0xFF ) << 24 ) | ( ( val & 0xFF00 ) << 8 ) | ( ( val >> 8 ) & 0xFF00 ) | ( ( val >> 24 ) & 0xFF );
-
-	};
-
 	// return mipmaps for THREE.js
 	KhronosTextureContainer.prototype.mipmaps = function ( loadMipmaps ) {
 

+ 1340 - 0
examples/js/loaders/LDrawLoader.js

@@ -0,0 +1,1340 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author yomboprime / https://github.com/yomboprime/
+ *
+ *
+ */
+
+THREE.LDrawLoader = ( function () {
+
+	function LineParser( line, lineNumber ) {
+
+		this.line = line;
+		this.lineLength = line.length;
+		this.currentCharIndex = 0;
+		this.currentChar = ' ';
+		this.lineNumber = lineNumber;
+
+	}
+
+	LineParser.prototype = {
+
+		constructor: LineParser,
+
+		seekNonSpace: function () {
+
+			while ( this.currentCharIndex < this.lineLength ) {
+
+				this.currentChar = this.line.charAt( this.currentCharIndex );
+
+				if ( this.currentChar !== ' ' && this.currentChar !== '\t' ) {
+
+					return;
+
+				}
+
+				this.currentCharIndex ++;
+
+			}
+
+		},
+
+		getToken: function () {
+
+			var pos0 = this.currentCharIndex ++;
+
+			// Seek space
+			while ( this.currentCharIndex < this.lineLength ) {
+
+				this.currentChar = this.line.charAt( this.currentCharIndex );
+
+				if ( this.currentChar === ' ' || this.currentChar === '\t' ) {
+
+					break;
+
+				}
+
+				this.currentCharIndex ++;
+
+			}
+
+			var pos1 = this.currentCharIndex;
+
+			this.seekNonSpace();
+
+			return this.line.substring( pos0, pos1 );
+
+		},
+
+		getRemainingString: function() {
+
+			return this.line.substring( this.currentCharIndex, this.lineLength );
+
+		},
+
+		isAtTheEnd: function() {
+
+			return this.currentCharIndex >= this.lineLength;
+
+		},
+
+		setToEnd: function () {
+
+			this.currentCharIndex = this.lineLength;
+
+		},
+
+		getLineNumberString: function () {
+
+			return this.lineNumber >= 0? " at line " + this.lineNumber: "";
+
+		}
+
+
+	};
+
+	function sortByMaterial ( a, b ) {
+
+		if ( a.colourCode === b.colourCode ) {
+			return 0;
+		}
+		if ( a.colourCode < b.colourCode ) {
+			return -1;
+		}
+		return 1;
+
+	}
+
+	function createObject( elements, elementSize ) {
+
+		// Creates a THREE.LineSegments (elementSize = 2) or a THREE.Mesh (elementSize = 3 )
+		// With per face / segment material, implemented with mesh groups and materials array
+
+		// Sort the triangles or line segments by colour code to make later the mesh groups
+		elements.sort( sortByMaterial );
+
+		var vertices = [];
+		var materials = [];
+
+		var bufferGeometry = new THREE.BufferGeometry();
+		bufferGeometry.clearGroups();
+		var prevMaterial = null;
+		var index0 = 0;
+		var numGroupVerts = 0;
+
+		for ( var iElem = 0, nElem = elements.length; iElem < nElem; iElem ++ ) {
+
+			var elem = elements[ iElem ];
+			var v0 = elem.v0;
+			var v1 = elem.v1;
+			// Note that LDraw coordinate system is rotated 180 deg. in the X axis w.r.t. Three.js's one
+			vertices.push( v0.x, v0.y, v0.z, v1.x, v1.y, v1.z );
+			if ( elementSize === 3 ) {
+
+				vertices.push( elem.v2.x, elem.v2.y, elem.v2.z );
+
+			}
+
+			if ( prevMaterial !== elem.material ) {
+
+				if ( prevMaterial !== null ) {
+
+					bufferGeometry.addGroup( index0, numGroupVerts, materials.length - 1 );
+
+				}
+
+				materials.push( elem.material );
+
+				prevMaterial = elem.material;
+				index0 = iElem * elementSize;
+				numGroupVerts = elementSize;
+
+			}
+			else {
+
+				numGroupVerts += elementSize;
+
+			}
+
+		}
+		if ( numGroupVerts > 0 ) {
+
+			bufferGeometry.addGroup( index0, Infinity, materials.length - 1 );
+
+		}
+
+		bufferGeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
+
+		var object3d = null;
+		if ( elementSize === 2 ) {
+
+			object3d = new THREE.LineSegments( bufferGeometry, materials );
+
+		}
+		else if ( elementSize === 3 ) {
+
+			bufferGeometry.computeVertexNormals();
+
+			object3d = new THREE.Mesh( bufferGeometry, materials );
+
+		}
+
+		return object3d;
+
+	}
+
+	//
+
+	function LDrawLoader( manager ) {
+
+		this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+
+		// This is a stack of 'parse scopes' with one level per subobject loaded file.
+		// Each level contains a material lib and also other runtime variables passed between parent and child subobjects
+		// When searching for a material code, the stack is read from top of the stack to bottom
+		// Each material library is an object map keyed by colour codes.
+		this.parseScopesStack = null;
+
+		this.path = '';
+
+		// Array of THREE.Material
+		this.materials = [];
+
+		// Not using THREE.Cache here because it returns the previous HTML error response instead of calling onError()
+		// This also allows to handle the embedded text files ("0 FILE" lines)
+		this.subobjectCache = {};
+
+		// This object is a map from file names to paths. It agilizes the paths search. If it is not set then files will be searched by trial and error.
+		this.fileMap = null;
+
+		// Add default main triangle and line edge materials (used in piecess that can be coloured with a main color)
+		this.setMaterials( [
+			this.parseColourMetaDirective( new LineParser( "Main_Colour CODE 16 VALUE #FF8080 EDGE #333333" ) ),
+			this.parseColourMetaDirective( new LineParser( "Edge_Colour CODE 24 VALUE #A0A0A0 EDGE #333333" ) )
+		] );
+
+		// If this flag is set to true, each subobject will be a THREE.Object.
+		// If not (the default), only one object which contains all the merged primitives will be created.
+		this.separateObjects = false;
+
+		// Current merged object and primitives
+		this.currentGroupObject = null;
+		this.currentTriangles = null;
+		this.currentLineSegments = null;
+
+	}
+
+	// Special surface finish tag types.
+	// Note: "MATERIAL" tag (e.g. GLITTER, SPECKLE) is not implemented
+	LDrawLoader.FINISH_TYPE_DEFAULT = 0;
+	LDrawLoader.FINISH_TYPE_CHROME = 1;
+	LDrawLoader.FINISH_TYPE_PEARLESCENT = 2;
+	LDrawLoader.FINISH_TYPE_RUBBER = 3;
+	LDrawLoader.FINISH_TYPE_MATTE_METALLIC = 4;
+	LDrawLoader.FINISH_TYPE_METAL = 5;
+
+	// State machine to search a subobject path.
+	// The LDraw standard establishes these various possible subfolders.
+	LDrawLoader.FILE_LOCATION_AS_IS = 0;
+	LDrawLoader.FILE_LOCATION_TRY_PARTS = 1;
+	LDrawLoader.FILE_LOCATION_TRY_P = 2;
+	LDrawLoader.FILE_LOCATION_TRY_MODELS = 3;
+	LDrawLoader.FILE_LOCATION_TRY_RELATIVE = 4;
+	LDrawLoader.FILE_LOCATION_TRY_ABSOLUTE = 5;
+	LDrawLoader.FILE_LOCATION_NOT_FOUND = 6;
+
+	LDrawLoader.prototype = {
+
+		constructor: LDrawLoader,
+
+		load: function ( url, onLoad, onProgress, onError ) {
+
+			if ( ! this.fileMap ) {
+
+				this.fileMap = {};
+
+			}
+
+			var scope = this;
+
+			var fileLoader = new THREE.FileLoader( this.manager );
+			fileLoader.setPath( this.path );
+			fileLoader.load( url, function( text ) {
+
+				processObject( text, onLoad );
+
+			}, onProgress, onError );
+
+			function processObject( text, onProcessed ) {
+
+				var parseScope = scope.newParseScopeLevel();
+				parseScope.url = url;
+
+				var parentParseScope = scope.getParentParseScope();
+
+				// Add to cache
+				var currentFileName = parentParseScope.currentFileName;
+				if ( scope.subobjectCache[ currentFileName ] === undefined ) {
+
+					scope.subobjectCache[ currentFileName ] = text;
+
+
+				}
+
+				// Parse the object (returns a THREE.Group)
+				var objGroup = scope.parse( text );
+
+				// Load subobjects
+				parseScope.subobjects = objGroup.userData.subobjects;
+				parseScope.numSubobjects = parseScope.subobjects.length;
+				parseScope.subobjectIndex = 0;
+
+				if ( parseScope.numSubobjects > 0 ) {
+
+					// Load the first subobject
+					var subobjectGroup = loadSubobject( parseScope.subobjects[ 0 ], true );
+
+					// Optimization for loading pack: If subobjects are obtained from cache, keep loading them iteratively rather than recursively
+					if ( subobjectGroup ) {
+
+						while ( subobjectGroup && parseScope.subobjectIndex < parseScope.numSubobjects - 1 ) {
+
+							subobjectGroup = loadSubobject( parseScope.subobjects[ ++ parseScope.subobjectIndex ], true );
+
+						}
+
+						if ( subobjectGroup ) {
+
+							finalizeObject();
+
+						}
+					}
+
+				}
+				else {
+
+					// No subobjects, finish object
+					finalizeObject();
+
+				}
+
+				return objGroup;
+
+				function finalizeObject() {
+
+					if ( ! scope.separateObjects && ! parentParseScope.isFromParse ) {
+
+						// We are finalizing the root object and merging primitives is activated, so create the entire Mesh and LineSegments objects now
+						if ( scope.currentLineSegments.length > 0 ) {
+
+							objGroup.add( createObject( scope.currentLineSegments, 2 ) );
+
+						}
+
+						if ( scope.currentTriangles.length > 0 ) {
+
+							objGroup.add( createObject( scope.currentTriangles, 3 ) );
+
+						}
+
+					}
+
+					scope.removeScopeLevel();
+
+					if ( onProcessed ) {
+
+						onProcessed( objGroup );
+
+					}
+
+				}
+
+				function loadSubobject ( subobject, sync ) {
+
+					parseScope.mainColourCode = subobject.material.userData.code;
+					parseScope.mainEdgeColourCode = subobject.material.userData.edgeMaterial.userData.code;
+					parseScope.currentFileName = subobject.originalFileName;
+
+					if ( ! scope.separateObjects ) {
+
+						// Set current matrix
+						parseScope.currentMatrix.multiplyMatrices( parentParseScope.currentMatrix, subobject.matrix );
+
+					}
+
+					// If subobject was cached previously, use the cached one
+					var cached = scope.subobjectCache[ subobject.originalFileName ];
+					if ( cached ) {
+
+						var subobjectGroup = processObject( cached, sync ? undefined : onSubobjectLoaded );
+						if ( sync ) {
+
+							addSubobject( subobject, subobjectGroup );
+							return subobjectGroup;
+
+						}
+
+						return;
+
+					}
+
+					// Adjust file name to locate the subobject file path in standard locations (always under directory scope.path)
+					// Update also subobject.locationState for the next try if this load fails.
+					var subobjectURL = subobject.fileName;
+					var newLocationState = LDrawLoader.FILE_LOCATION_NOT_FOUND;
+
+					switch ( subobject.locationState ) {
+
+						case LDrawLoader.FILE_LOCATION_AS_IS:
+							newLocationState = subobject.locationState + 1;
+							break;
+
+						case LDrawLoader.FILE_LOCATION_TRY_PARTS:
+							subobjectURL = 'parts/' + subobjectURL;
+							newLocationState = subobject.locationState + 1;
+							break;
+
+						case LDrawLoader.FILE_LOCATION_TRY_P:
+							subobjectURL = 'p/' + subobjectURL;
+							newLocationState = subobject.locationState + 1;
+							break;
+
+						case LDrawLoader.FILE_LOCATION_TRY_MODELS:
+							subobjectURL = 'models/' + subobjectURL;
+							newLocationState = subobject.locationState + 1;
+							break;
+
+						case LDrawLoader.FILE_LOCATION_TRY_RELATIVE:
+							subobjectURL = url.substring( 0, url.lastIndexOf( "/" ) + 1 ) + subobjectURL;
+							newLocationState = subobject.locationState + 1;
+							break;
+
+						case LDrawLoader.FILE_LOCATION_TRY_ABSOLUTE:
+
+							if ( subobject.triedLowerCase ) {
+
+								// Try absolute path
+								newLocationState = LDrawLoader.FILE_LOCATION_NOT_FOUND;
+
+							}
+							else {
+
+								// Next attempt is lower case
+								subobject.fileName = subobject.fileName.toLowerCase();
+								subobjectURL = subobject.fileName;
+								subobject.triedLowerCase = true;
+								newLocationState = LDrawLoader.FILE_LOCATION_AS_IS;
+
+							}
+							break;
+
+						case LDrawLoader.FILE_LOCATION_NOT_FOUND:
+
+							// All location possibilities have been tried, give up loading this object
+							console.warn( 'LDrawLoader: Subobject "' + subobject.originalFileName + '" could not be found.' );
+
+							// Try to read the next subobject
+							parseScope.subobjectIndex ++;
+
+							if ( parseScope.subobjectIndex >= parseScope.numSubobjects ) {
+
+								// All subojects have been loaded. Finish parent object
+								scope.removeScopeLevel();
+								onProcessed( objGroup );
+
+							}
+							else {
+
+								// Load next subobject
+								loadSubobject( parseScope.subobjects[ parseScope.subobjectIndex ] );
+
+							}
+
+							return;
+
+					}
+
+					subobject.locationState = newLocationState;
+					subobject.url = subobjectURL;
+
+					// Load the subobject
+					scope.load( subobjectURL, onSubobjectLoaded, undefined, onSubobjectError );
+
+				}
+
+				function onSubobjectLoaded( subobjectGroup ) {
+
+					var subobject = parseScope.subobjects[ parseScope.subobjectIndex ];
+
+					if ( subobjectGroup === null ) {
+
+						// Try to reload
+						loadSubobject( subobject );
+						return;
+
+					}
+
+					// Add the subobject just loaded
+					addSubobject( subobject, subobjectGroup );
+
+					// Proceed to load the next subobject, or finish the parent object
+
+					parseScope.subobjectIndex ++;
+
+					if ( parseScope.subobjectIndex < parseScope.numSubobjects ) {
+
+						loadSubobject( parseScope.subobjects[ parseScope.subobjectIndex ] );
+
+					}
+					else {
+
+						finalizeObject();
+
+					}
+
+				}
+
+				function addSubobject ( subobject, subobjectGroup ) {
+
+					if ( scope.separateObjects ) {
+
+						subobjectGroup.name = subobject.fileName;
+						objGroup.add( subobjectGroup );
+						subobjectGroup.matrix.copy( subobject.matrix );
+						subobjectGroup.matrixAutoUpdate = false;
+
+					}
+
+					scope.fileMap[ subobject.originalFileName ] = subobject.url;
+
+				}
+
+				function onSubobjectError( err ) {
+
+					// Retry download from a different default possible location
+					loadSubobject( parseScope.subobjects[ parseScope.subobjectIndex ] );
+
+				}
+
+			}
+
+		},
+
+		setPath: function ( value ) {
+
+			this.path = value;
+
+			return this;
+
+		},
+
+		setMaterials: function ( materials ) {
+
+			// Clears parse scopes stack, adds new scope with material library
+
+			this.parseScopesStack = [];
+
+			this.newParseScopeLevel( materials );
+
+			this.getCurrentParseScope().isFromParse = false;
+
+			this.materials = materials;
+
+			this.currentGroupObject = null;
+
+			return this;
+
+		},
+
+		setFileMap: function( fileMap ) {
+
+			this.fileMap = fileMap;
+
+			return this;
+
+		},
+
+		newParseScopeLevel: function ( materials ) {
+
+			// Adds a new scope level, assign materials to it and returns it
+
+			var matLib = {};
+
+			if ( materials ) {
+
+				for ( var i = 0, n = materials.length; i < n; i ++ ) {
+
+					var material = materials[ i ];
+					matLib[ material.userData.code ] = material;
+
+				}
+
+			}
+
+			var topParseScope = this.getCurrentParseScope();
+
+			var parentParseScope = this.getParentParseScope();
+
+			var newParseScope = {
+
+				lib: matLib,
+				url: null,
+
+				// Subobjects
+				subobjects: null,
+				numSubobjects: 0,
+				subobjectIndex: 0,
+
+				// Current subobject
+				currentFileName: null,
+				mainColourCode: topParseScope ? topParseScope.mainColourCode : '16',
+				mainEdgeColourCode: topParseScope ? topParseScope.mainEdgeColourCode : '24',
+				currentMatrix: new THREE.Matrix4(),
+
+				// If false, it is a root material scope previous to parse
+				isFromParse: true
+			};
+
+			this.parseScopesStack.push( newParseScope );
+
+			return newParseScope;
+
+		},
+
+		removeScopeLevel: function() {
+
+			this.parseScopesStack.pop();
+
+			return this;
+
+		},
+
+		addMaterial: function ( material ) {
+
+			// Adds a material to the material library which is on top of the parse scopes stack. And also to the materials array
+
+			var matLib = this.getCurrentParseScope().lib;
+
+			if ( ! matLib[ material.userData.code ] ) {
+
+				this.materials.push( material );
+
+			}
+
+			matLib[ material.userData.code ] = material;
+
+			return this;
+
+		},
+
+		getMaterial: function ( colourCode ) {
+
+			// Given a colour code search its material in the parse scopes stack
+
+			if ( colourCode.startsWith( "0x2" ) ) {
+
+				// Special 'direct' material value (RGB colour)
+
+				var colour = colourCode.substring( 3 );
+
+				return this.parseColourMetaDirective( new LineParser( "Direct_Color_" + colour + " CODE -1 VALUE #" + colour + " EDGE #" + colour + "" ) );
+
+			}
+
+			for ( var i = this.parseScopesStack.length - 1; i >= 0; i-- ) {
+
+				var material = this.parseScopesStack[ i ].lib[ colourCode ];
+
+				if ( material ) {
+
+					return material;
+
+				}
+
+			}
+
+			// Material was not found
+			return null;
+
+		},
+
+		getParentParseScope: function () {
+
+			if ( this.parseScopesStack.length > 1 ) {
+
+				return this.parseScopesStack[ this.parseScopesStack.length - 2 ];
+
+			}
+
+			return null;
+
+		},
+
+		getCurrentParseScope: function () {
+
+			if ( this.parseScopesStack.length > 0 ) {
+
+				return this.parseScopesStack[ this.parseScopesStack.length - 1 ];
+
+			}
+
+			return null;
+
+		},
+
+		parseColourMetaDirective: function ( lineParser ) {
+
+			// Parses a colour definition and returns a THREE.Material or null if error
+
+			var code = null;
+
+			// Triangle and line colours
+			var colour = 0xFF00FF;
+			var edgeColour = 0xFF00FF;
+
+			// Transparency
+			var alpha = 1;
+			var isTransparent = false;
+			// Self-illumination:
+			var luminance = 0;
+
+			var finishType = LDrawLoader.FINISH_TYPE_DEFAULT;
+			var canHaveEnvMap = true;
+
+			var edgeMaterial = null;
+
+			var name = lineParser.getToken();
+			if ( ! name ) {
+
+				throw 'LDrawLoader: Material name was expected after "!COLOUR tag' + lineParser.getLineNumberString() + ".";
+
+			}
+
+			// Parse tag tokens and their parameters
+			var token = null;
+			while ( true ) {
+
+				token = lineParser.getToken();
+
+				if ( ! token ) {
+
+					break;
+
+				}
+
+				switch ( token.toUpperCase() ) {
+
+					case "CODE":
+
+						code = lineParser.getToken();
+						break;
+
+					case "VALUE":
+
+						colour = lineParser.getToken();
+						if ( colour.startsWith( '0x' ) ) {
+
+							colour = '#' + colour.substring( 2 );
+
+						}
+						else if ( ! colour.startsWith( '#' ) ) {
+							throw 'LDrawLoader: Invalid colour while parsing material' + lineParser.getLineNumberString() + ".";
+						}
+						break;
+
+					case "EDGE":
+
+						edgeColour = lineParser.getToken();
+						if ( edgeColour.startsWith( '0x' ) ) {
+
+							edgeColour = '#' + edgeColour.substring( 2 );
+
+						}
+						else if ( ! edgeColour.startsWith( '#' ) ) {
+
+							// Try to see if edge colour is a colour code
+							edgeMaterial = this.getMaterial( edgeColour );
+							if ( ! edgeMaterial ) {
+
+								throw 'LDrawLoader: Invalid edge colour while parsing material' + lineParser.getLineNumberString() + ".";
+
+							}
+
+							// Get the edge material for this triangle material
+							edgeMaterial = edgeMaterial.userData.edgeMaterial;
+
+						}
+						break;
+
+					case 'ALPHA':
+
+						alpha = parseInt( lineParser.getToken() );
+
+						if ( isNaN( alpha ) ) {
+
+							throw 'LDrawLoader: Invalid alpha value in material definition' + lineParser.getLineNumberString() + ".";
+
+						}
+
+						alpha = Math.max( 0, Math.min( 1, alpha / 255 ) );
+
+						if ( alpha < 1 ) {
+
+							isTransparent = true;
+
+						}
+
+						break;
+
+					case 'LUMINANCE':
+
+						luminance = parseInt( lineParser.getToken() );
+
+						if ( isNaN( luminance ) ) {
+
+							throw 'LDrawLoader: Invalid luminance value in material definition' + LineParser.getLineNumberString() + ".";
+
+						}
+
+						luminance = Math.max( 0, Math.min( 1, luminance / 255 ) );
+
+						break;
+
+					case 'CHROME':
+						finishType = LDrawLoader.FINISH_TYPE_CHROME;
+						break;
+
+					case 'PEARLESCENT':
+						finishType = LDrawLoader.FINISH_TYPE_PEARLESCENT;
+						break;
+
+					case 'RUBBER':
+						finishType = LDrawLoader.FINISH_TYPE_RUBBER;
+						break;
+
+					case 'MATTE_METALLIC':
+						finishType = LDrawLoader.FINISH_TYPE_MATTE_METALLIC;
+						break;
+
+					case 'METAL':
+						finishType = LDrawLoader.FINISH_TYPE_METAL;
+						break;
+
+					case 'MATERIAL':
+						// Not implemented
+						lineParser.setToEnd();
+						break;
+
+					default:
+						throw 'LDrawLoader: Unknown token "' + token + '" while parsing material' + lineParser.getLineNumberString() + ".";
+						break;
+
+				}
+
+			}
+
+			var material = null;
+
+			switch ( finishType ) {
+
+				case LDrawLoader.FINISH_TYPE_DEFAULT:
+				case LDrawLoader.FINISH_TYPE_PEARLESCENT:
+
+					var specular = new THREE.Color( colour );
+					var shininess = 35;
+					var hsl = specular.getHSL( { h: 0, s: 0, l: 0 } );
+
+					if ( finishType === LDrawLoader.FINISH_TYPE_DEFAULT ) {
+
+						// Default plastic material with shiny specular
+						hsl.l = Math.min( 1, hsl.l + ( 1 - hsl.l ) * 0.12 );
+
+					}
+					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 );
+
+					material = new THREE.MeshPhongMaterial( { color: colour, specular: specular, shininess: shininess, reflectivity: 0.3 } );
+					break;
+
+				case LDrawLoader.FINISH_TYPE_CHROME:
+
+					// Mirror finish surface
+					material = new THREE.MeshStandardMaterial( { color: colour, roughness: 0, metalness: 1 } );
+					break;
+
+				case LDrawLoader.FINISH_TYPE_RUBBER:
+
+					// Rubber is best simulated with Lambert
+					material = new THREE.MeshLambertMaterial( { color: colour } );
+					canHaveEnvMap = false;
+					break;
+
+				case LDrawLoader.FINISH_TYPE_MATTE_METALLIC:
+
+					// Brushed metal finish
+					material = new THREE.MeshStandardMaterial( { color: colour, roughness: 0.8, metalness: 0.4 } );
+					break;
+
+				case LDrawLoader.FINISH_TYPE_METAL:
+
+					// Average metal finish
+					material = new THREE.MeshStandardMaterial( { color: colour, roughness: 0.2, metalness: 0.85 } );
+					break;
+
+				default:
+					// Should not happen
+					break;
+			}
+
+			// BFC (Back Face Culling) LDraw language meta extension is not implemented, so set all materials double-sided:
+			material.side = THREE.DoubleSide;
+
+			material.transparent = isTransparent;
+			material.opacity = alpha;
+
+			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;
+			material.name = name;
+
+			material.userData.edgeMaterial = edgeMaterial;
+
+			return material;
+
+		},
+
+		//
+
+		parse: function ( text ) {
+
+			//console.time( 'LDrawLoader' );
+
+			// Retrieve data from the parent parse scope
+			var parentParseScope = this.getParentParseScope();
+
+			// Main colour codes passed to this subobject (or default codes 16 and 24 if it is the root object)
+			var mainColourCode = parentParseScope.mainColourCode;
+			var mainEdgeColourCode = parentParseScope.mainEdgeColourCode;
+
+			var url = parentParseScope.url;
+
+			var currentParseScope = this.getCurrentParseScope();
+
+			// Parse result variables
+			var triangles;
+			var lineSegments;
+
+			if ( this.separateObjects ) {
+
+				triangles = [];
+				lineSegments = [];
+
+			}
+			else {
+
+				if ( this.currentGroupObject === null ) {
+
+					this.currentGroupObject = new THREE.Group();
+					this.currentTriangles = [];
+					this.currentLineSegments = [];
+
+				}
+
+				triangles = this.currentTriangles;
+				lineSegments = this.currentLineSegments;
+
+			}
+
+			var subobjects = [];
+
+			var category = null;
+			var keywords = null;
+
+			if ( text.indexOf( '\r\n' ) !== - 1 ) {
+
+				// This is faster than String.split with regex that splits on both
+				text = text.replace( /\r\n/g, '\n' );
+
+			}
+
+			var lines = text.split( '\n' );
+			var numLines = lines.length;
+			var lineIndex = 0;
+
+			var parsingEmbeddedFiles = false;
+			var currentEmbeddedFileName = null;
+			var currentEmbeddedText = null;
+
+			var scope = this;
+			function parseColourCode( lineParser, forEdge ) {
+
+				// Parses next colour code and returns a THREE.Material
+
+				var colourCode = lineParser.getToken();
+
+				if ( ! forEdge && colourCode === '16' ) {
+
+					colourCode = mainColourCode;
+
+				}
+				if ( forEdge && colourCode === '24' ) {
+
+					colourCode = mainEdgeColourCode;
+
+				}
+
+				var material = scope.getMaterial( colourCode );
+
+				if ( ! material ) {
+
+					throw 'LDrawLoader: Unknown colour code "' + colourCode + '" is used' + lineParser.getLineNumberString() + ' but it was not defined previously.';
+
+				}
+
+				return material;
+
+			}
+
+			function parseVector ( lp ) {
+
+				var v = new THREE.Vector3( parseFloat( lp.getToken() ), parseFloat( lp.getToken() ), parseFloat( lp.getToken() ) );
+
+				if ( ! scope.separateObjects ) {
+
+					v.applyMatrix4( parentParseScope.currentMatrix );
+
+				}
+
+				return v;
+
+			}
+
+			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 ];
+
+				if ( line.length === 0 ) continue;
+
+				if ( parsingEmbeddedFiles ) {
+
+					if ( line.startsWith( '0 FILE ' ) ) {
+
+						// Save previous embedded file in the cache
+						this.subobjectCache[ currentEmbeddedFileName ] = currentEmbeddedText;
+
+						// New embedded text file
+						currentEmbeddedFileName = line.substring( 7 );
+						currentEmbeddedText = '';
+
+					}
+					else {
+
+						currentEmbeddedText += line + '\n';
+
+					}
+
+					continue;
+
+				}
+
+				var lp = new LineParser( line, lineIndex + 1 );
+
+				lp.seekNonSpace();
+
+				if ( lp.isAtTheEnd() ) {
+					// Empty line
+					continue;
+				}
+
+				// Parse the line type
+				var lineType = lp.getToken();
+
+				switch ( lineType ) {
+
+					// Line type 0: Comment or META
+					case '0':
+
+						// Parse meta directive
+						var meta = lp.getToken();
+
+						if ( meta ) {
+
+							switch ( meta ) {
+
+								case '!COLOUR':
+
+									var material = this.parseColourMetaDirective( lp );
+									if ( material ) {
+
+										this.addMaterial( material );
+
+									}
+									else {
+
+										console.warn( 'LDrawLoader: Error parsing material' + lineParser.getLineNumberString() );
+
+									}
+									break;
+
+								case '!CATEGORY':
+
+									category = lp.getToken();
+									break;
+
+								case '!KEYWORDS':
+
+										var newKeywords = lp.getRemainingString().split( ',' );
+										if ( newKeywords.length > 0 ) {
+
+											if ( ! keywords ) {
+
+												keywords = [];
+
+											}
+
+											newKeywords.forEach( function( keyword ) {
+
+												keywords.push( keyword.trim() );
+
+											} );
+
+										}
+									break;
+
+								case 'FILE':
+
+									if ( lineIndex > 0 ) {
+
+										// Start embedded text files parsing
+										parsingEmbeddedFiles = true;
+										currentEmbeddedFileName = lp.getRemainingString();
+										currentEmbeddedText = '';
+
+									}
+
+									break;
+
+								default:
+									// Other meta directives are not implemented
+									break;
+
+							}
+
+						}
+
+						break;
+
+					// Line type 1: Sub-object file
+					case '1':
+
+						var material = parseColourCode( lp );
+
+						var posX = parseFloat( lp.getToken() );
+						var posY = parseFloat( lp.getToken() );
+						var posZ = parseFloat( lp.getToken() );
+						var m0 = parseFloat( lp.getToken() );
+						var m1 = parseFloat( lp.getToken() );
+						var m2 = parseFloat( lp.getToken() );
+						var m3 = parseFloat( lp.getToken() );
+						var m4 = parseFloat( lp.getToken() );
+						var m5 = parseFloat( lp.getToken() );
+						var m6 = parseFloat( lp.getToken() );
+						var m7 = parseFloat( lp.getToken() );
+						var m8 = parseFloat( lp.getToken() );
+
+						var matrix = new THREE.Matrix4().set(
+							m0, m1, m2, posX,
+							m3, m4, m5, posY,
+							m6, m7, m8, posZ,
+							0, 0, 0, 1
+						);
+
+						var fileName = lp.getRemainingString().trim().replace( "\\", "/" );
+
+						if ( scope.fileMap[ fileName ] ) {
+
+							// Found the subobject path in the preloaded file path map
+							fileName = scope.fileMap[ fileName ];
+
+						}
+						else {
+
+							// Standardized subfolders
+							if ( fileName.startsWith( 's/' ) ) {
+
+								fileName = 'parts/' + fileName;
+
+							}
+							else if ( fileName.startsWith( '48/' ) ) {
+
+								fileName = 'p/' + fileName;
+
+							}
+
+						}
+
+						subobjects.push( {
+							material: material,
+							matrix: matrix,
+							fileName: fileName,
+							originalFileName: fileName,
+							locationState: LDrawLoader.FILE_LOCATION_AS_IS,
+							url: null,
+							triedLowerCase: false
+						} );
+
+						break;
+
+					// Line type 2: Line segment
+					case '2':
+
+						var material = parseColourCode( lp, true );
+
+						lineSegments.push( {
+							material: material.userData.edgeMaterial,
+							colourCode: material.userData.code,
+							v0: parseVector( lp ),
+							v1: parseVector( lp )
+						} );
+
+						break;
+
+					// Line type 3: Triangle
+					case '3':
+
+						var material = parseColourCode( lp );
+
+						triangles.push( {
+							material: material,
+							colourCode: material.userData.code,
+							v0: parseVector( lp ),
+							v1: parseVector( lp ),
+							v2: parseVector( lp )
+						} );
+
+						break;
+
+					// Line type 4: Quadrilateral
+					case '4':
+
+						var material = parseColourCode( lp );
+
+						var v0 = parseVector( lp );
+						var v1 = parseVector( lp );
+						var v2 = parseVector( lp );
+						var v3 = parseVector( lp );
+
+						triangles.push( {
+							material: material,
+							colourCode: material.userData.code,
+							v0: v0,
+							v1: v1,
+							v2: v2
+						} );
+
+						triangles.push( {
+							material: material,
+							colourCode: material.userData.code,
+							v0: v0,
+							v1: v2,
+							v2: v3
+						} );
+
+						break;
+
+					// Line type 5: Optional line
+					case '5':
+						// Line type 5 is not implemented
+						break;
+
+					default:
+						throw 'LDrawLoader: Unknown line type "' + lineType + '"' + lp.getLineNumberString() + '.';
+						break;
+
+				}
+
+			}
+
+			if ( parsingEmbeddedFiles ) {
+
+				this.subobjectCache[ currentEmbeddedFileName ] = currentEmbeddedText;
+
+			}
+
+			//
+
+			var groupObject = null;
+
+			if ( this.separateObjects ) {
+
+				groupObject = new THREE.Group();
+
+				if ( lineSegments.length > 0 ) {
+
+					groupObject.add( createObject( lineSegments, 2 ) );
+
+
+				}
+
+				if ( triangles.length > 0 ) {
+
+					groupObject.add( createObject( triangles, 3 ) );
+
+				}
+
+			}
+			else {
+
+				groupObject = this.currentGroupObject;
+
+			}
+
+			groupObject.userData.category = category;
+			groupObject.userData.keywords = keywords;
+			groupObject.userData.subobjects = subobjects;
+
+			//console.timeEnd( 'LDrawLoader' );
+
+			return groupObject;
+
+		}
+
+	};
+
+	return LDrawLoader;
+
+} )();

+ 16 - 1
examples/js/loaders/MTLLoader.js

@@ -149,7 +149,7 @@ THREE.MTLLoader.prototype = {
 
 			} else {
 
-				if ( key === 'ka' || key === 'kd' || key === 'ks' ) {
+				if ( key === 'ka' || key === 'kd' || key === 'ks' || key ==='ke' ) {
 
 					var ss = value.split( delimiter_pattern, 3 );
 					info[ key ] = [ parseFloat( ss[ 0 ] ), parseFloat( ss[ 1 ] ), parseFloat( ss[ 2 ] ) ];
@@ -413,6 +413,13 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 
 					break;
 
+				case 'ke':
+
+					// Emissive using RGB values
+					params.emissive = new THREE.Color().fromArray( value );
+
+					break;
+
 				case 'map_kd':
 
 					// Diffuse texture map
@@ -429,6 +436,14 @@ THREE.MTLLoader.MaterialCreator.prototype = {
 
 					break;
 
+				case 'map_ke':
+
+					// Emissive map
+
+					setMapForType( "emissiveMap", value );
+
+					break;
+
 				case 'norm':
 
 					setMapForType( "normalMap", value );

+ 6 - 8
examples/js/loaders/SVGLoader.js

@@ -143,10 +143,10 @@ THREE.SVGLoader.prototype = {
 				var type = command.charAt( 0 );
 				var data = command.substr( 1 ).trim();
 
-				if ( isFirstPoint ) {
+				if ( isFirstPoint === true ) {
 					doSetFirstPoint = true;
+					isFirstPoint = false;
 				}
-				isFirstPoint = false;
 
 				switch ( type ) {
 
@@ -432,13 +432,11 @@ THREE.SVGLoader.prototype = {
 
 				// console.log( type, parseFloats( data ), parseFloats( data ).length  )
 
-				if ( doSetFirstPoint ) {
-
+				if ( doSetFirstPoint === true ) {
 					firstPoint.copy( point );
-
 					doSetFirstPoint = false;
-
 				}
+
 			}
 
 			return path;
@@ -759,7 +757,7 @@ THREE.SVGLoader.prototype = {
 			var transform = new THREE.Matrix3();
 			var currentTransform = tempTransform0;
 			var transformsTexts = node.getAttribute( 'transform' ).split( ' ' );
-			
+
 			for ( var tIndex = transformsTexts.length - 1; tIndex >= 0; tIndex-- ) {
 
 				var transformText = transformsTexts[ tIndex ];
@@ -771,7 +769,7 @@ THREE.SVGLoader.prototype = {
 					var transformType = transformText.substr( 0, openParPos );
 
 					var array = parseFloats( transformText.substr( openParPos + 1, closeParPos - openParPos - 1 ) );
-					
+
 					currentTransform.identity();
 
 					switch ( transformType ) {

+ 46 - 2
examples/js/loaders/XLoader.js

@@ -1415,9 +1415,9 @@
 					}
 
 					var bufferGeometry = this._buildGeometry();
-					bufferGeometry.bones = putBones;
 					mesh = new THREE.SkinnedMesh( bufferGeometry, this._currentGeo.Materials.length === 1 ? this._currentGeo.Materials[ 0 ] : this._currentGeo.Materials );
-					mesh.skeleton.boneInverses = offsetList;
+
+					this._initSkeleton( mesh, putBones, offsetList );
 
 				} else {
 
@@ -1450,6 +1450,50 @@
 				this.Meshes.push( mesh );
 
 			}
+		}, {
+			key: '_initSkeleton',
+			value: function _initSkeleton( mesh, boneList, boneInverses ) {
+
+				var bones = [], bone, gbone;
+				var i, il;
+
+				for ( i = 0, il = boneList.length; i < il; i ++ ) {
+
+					gbone = boneList[ i ];
+
+					bone = new THREE.Bone();
+					bones.push( bone );
+
+					bone.name = gbone.name;
+					bone.position.fromArray( gbone.pos );
+					bone.quaternion.fromArray( gbone.rotq );
+					if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl );
+
+				}
+
+				for ( i = 0, il = boneList.length; i < il; i ++ ) {
+
+					gbone = boneList[ i ];
+
+					if ( ( gbone.parent !== - 1 ) && ( gbone.parent !== null ) && ( bones[ gbone.parent ] !== undefined ) ) {
+
+						bones[ gbone.parent ].add( bones[ i ] );
+
+					} else {
+
+						mesh.add( bones[ i ] );
+
+					}
+
+				}
+
+				mesh.updateMatrixWorld( true );
+
+				var skeleton = new THREE.Skeleton( bones, boneInverses );
+				mesh.bind( skeleton, mesh.matrixWorld );
+
+			}
+
 		}, {
 			key: '_readAnimationKey',
 			value: function _readAnimationKey() {

+ 1 - 1
examples/js/nodes/math/Math1Node.js

@@ -26,7 +26,7 @@ Math1Node.FLOOR = 'floor';
 Math1Node.CEIL = 'ceil';
 Math1Node.NORMALIZE = 'normalize';
 Math1Node.FRACT = 'fract';
-Math1Node.SAT = 'saturate';
+Math1Node.SATURATE = 'saturate';
 Math1Node.SIN = 'sin';
 Math1Node.COS = 'cos';
 Math1Node.TAN = 'tan';

+ 1 - 0
examples/js/nodes/math/Math3Node.js

@@ -17,6 +17,7 @@ function Math3Node( a, b, c, method ) {
 }
 
 Math3Node.MIX = 'mix';
+Math3Node.CLAMP = 'clamp';
 Math3Node.REFRACT = 'refract';
 Math3Node.SMOOTHSTEP = 'smoothstep';
 Math3Node.FACEFORWARD = 'faceforward';

+ 1069 - 0
examples/js/objects/Fire.js

@@ -0,0 +1,1069 @@
+/**
+ * @author Mike Piecuch / https://github.com/mikepiecuch
+ *
+ * Based on research paper "Real-Time Fluid Dynamics for Games" by Jos Stam
+ * http://www.dgp.toronto.edu/people/stam/reality/Research/pdf/GDC03.pdf
+ *
+ */
+
+THREE.Fire = function ( geometry, options ) {
+
+	THREE.Mesh.call( this, geometry );
+
+	this.type = 'Fire';
+
+	this.clock = new THREE.Clock();
+
+	options = options || {};
+
+	var textureWidth = options.textureWidth || 512;
+	var textureHeight = options.textureHeight || 512;
+	var oneOverWidth = 1.0 / textureWidth;
+	var oneOverHeight = 1.0 / textureHeight;
+
+	var debug = ( options.debug === undefined ) ? false : options.debug;
+	this.color1 = options.color1 || new THREE.Color( 0xffffff );
+	this.color2 = options.color2 || new THREE.Color( 0xffa000 );
+	this.color3 = options.color3 || new THREE.Color( 0x000000 );
+	this.colorBias = ( options.colorBias === undefined ) ? 0.8 : options.colorBias;
+	this.diffuse = ( options.diffuse === undefined ) ? 1.33 : options.diffuse;
+	this.viscosity = ( options.viscosity === undefined ) ? 0.25 : options.viscosity;
+	this.expansion = ( options.expansion === undefined ) ? - 0.25 : options.expansion;
+	this.swirl = ( options.swirl === undefined ) ? 50.0 : options.swirl;
+	this.burnRate = ( options.burnRate === undefined ) ? 0.3 : options.burnRate;
+	this.drag = ( options.drag === undefined ) ? 0.35 : options.drag;
+	this.airSpeed = ( options.airSpeed === undefined ) ? 6.0 : options.airSpeed;
+	this.windVector = options.windVector || new THREE.Vector2( 0.0, 0.75 );
+	this.speed = ( options.speed === undefined ) ? 500.0 : options.speed;
+	this.massConservation = ( options.massConservation === undefined ) ? false : options.massConservation;
+
+	var size = textureWidth * textureHeight;
+	this.sourceData = new Uint8Array( 4 * size );
+
+	this.clearSources = function () {
+
+		for ( var y = 0; y < textureHeight; y ++ ) {
+
+			for ( var x = 0; x < textureWidth; x ++ ) {
+
+				var i = y * textureWidth + x;
+				var stride = i * 4;
+
+				this.sourceData[ stride ] = 0;
+				this.sourceData[ stride + 1 ] = 0;
+				this.sourceData[ stride + 2 ] = 0;
+				this.sourceData[ stride + 3 ] = 0;
+
+			}
+
+		}
+
+		this.sourceMaterial.uniforms.sourceMap.value = this.internalSource;
+		this.sourceMaterial.needsUpdate = true;
+
+		return this.sourceData;
+
+	};
+
+	this.addSource = function ( u, v, radius, density = null, windX = null, windY = null ) {
+
+		var startX = Math.max( Math.floor( ( u - radius ) * textureWidth ), 0 );
+		var startY = Math.max( Math.floor( ( v - radius ) * textureHeight ), 0 );
+		var endX = Math.min( Math.floor( ( u + radius ) * textureWidth ), textureWidth );
+		var endY = Math.min( Math.floor( ( v + radius ) * textureHeight ), textureHeight );
+
+		for ( var y = startY; y < endY; y ++ ) {
+
+			for ( var x = startX; x < endX; x ++ ) {
+
+				var diffX = x * oneOverWidth - u;
+				var diffY = y * oneOverHeight - v;
+
+				if ( diffX * diffX + diffY * diffY < radius * radius ) {
+
+					var i = y * textureWidth + x;
+					var stride = i * 4;
+
+					if ( density != null ) {
+
+						this.sourceData[ stride ] = Math.min( Math.max( density, 0.0 ), 1.0 ) * 255;
+
+					}
+					if ( windX != null ) {
+
+						var wind = Math.min( Math.max( windX, - 1.0 ), 1.0 );
+						wind = ( wind < 0.0 ) ? Math.floor( wind * 127 ) + 255 : Math.floor( wind * 127 );
+						this.sourceData[ stride + 1 ] = wind;
+
+					}
+					if ( windY != null ) {
+
+						var wind = Math.min( Math.max( windY, - 1.0 ), 1.0 );
+						wind = ( wind < 0.0 ) ? Math.floor( wind * 127 ) + 255 : Math.floor( wind * 127 );
+						this.sourceData[ stride + 2 ] = wind;
+
+					}
+
+				}
+
+			}
+
+		}
+
+		this.internalSource.needsUpdate = true;
+
+		return this.sourceData;
+
+	};
+
+	// When setting source map, red channel is density. Green and blue channels
+	// encode x and y velocity respectively as signed chars:
+	// (0 -> 127 = 0.0 -> 1.0, 128 -> 255 = -1.0 -> 0.0 )
+	this.setSourceMap = function ( texture ) {
+
+		this.sourceMaterial.uniforms.sourceMap.value = texture;
+
+	};
+
+	var parameters = {
+		minFilter: THREE.NearestFilter,
+		magFilter: THREE.NearestFilter,
+		depthBuffer: false,
+		stencilBuffer: false
+	};
+
+
+	this.field0 = new THREE.WebGLRenderTarget( textureWidth, textureHeight, parameters );
+
+	this.field0.background = new THREE.Color( 0x000000 );
+
+	this.field1 = new THREE.WebGLRenderTarget( textureWidth, textureHeight, parameters );
+
+	this.field0.background = new THREE.Color( 0x000000 );
+
+	this.fieldProj = new THREE.WebGLRenderTarget( textureWidth, textureHeight, parameters );
+
+	this.field0.background = new THREE.Color( 0x000000 );
+
+	if ( ! THREE.Math.isPowerOfTwo( textureWidth ) ||
+		 ! THREE.Math.isPowerOfTwo( textureHeight ) ) {
+
+		this.field0.texture.generateMipmaps = false;
+		this.field1.texture.generateMipmaps = false;
+		this.fieldProj.texture.generateMipmaps = false;
+
+	}
+
+
+	this.fieldScene = new THREE.Scene();
+	this.fieldScene.background = new THREE.Color( 0x000000 );
+
+	this.orthoCamera = new THREE.OrthographicCamera( textureWidth / - 2, textureWidth / 2, textureHeight / 2, textureHeight / - 2, 1, 2 );
+	this.orthoCamera.position.z = 1;
+
+	this.fieldGeometry = new THREE.PlaneBufferGeometry( textureWidth, textureHeight );
+
+	this.internalSource = new THREE.DataTexture( this.sourceData, textureWidth, textureHeight, THREE.RGBAFormat );
+
+	// Source Shader
+
+	var shader = THREE.Fire.SourceShader;
+	this.sourceMaterial = new THREE.ShaderMaterial( {
+		uniforms: shader.uniforms,
+		vertexShader: shader.vertexShader,
+		fragmentShader: shader.fragmentShader,
+		transparent: false
+	} );
+
+	this.clearSources();
+
+	this.sourceMesh = new THREE.Mesh( this.fieldGeometry, this.sourceMaterial );
+	this.fieldScene.add( this.sourceMesh );
+
+	// Diffuse Shader
+
+	var shader = THREE.Fire.DiffuseShader;
+	this.diffuseMaterial = new THREE.ShaderMaterial( {
+		uniforms: shader.uniforms,
+		vertexShader: shader.vertexShader,
+		fragmentShader: shader.fragmentShader,
+		transparent: false
+	} );
+
+	this.diffuseMaterial.uniforms.oneOverWidth.value = oneOverWidth;
+	this.diffuseMaterial.uniforms.oneOverHeight.value = oneOverHeight;
+
+	this.diffuseMesh = new THREE.Mesh( this.fieldGeometry, this.diffuseMaterial );
+	this.fieldScene.add( this.diffuseMesh );
+
+	// Drift Shader
+
+	shader = THREE.Fire.DriftShader;
+	this.driftMaterial = new THREE.ShaderMaterial( {
+		uniforms: shader.uniforms,
+		vertexShader: shader.vertexShader,
+		fragmentShader: shader.fragmentShader,
+		transparent: false
+	} );
+
+	this.driftMaterial.uniforms.oneOverWidth.value = oneOverWidth;
+	this.driftMaterial.uniforms.oneOverHeight.value = oneOverHeight;
+
+	this.driftMesh = new THREE.Mesh( this.fieldGeometry, this.driftMaterial );
+	this.fieldScene.add( this.driftMesh );
+
+	// Projection Shader 1
+
+	shader = THREE.Fire.ProjectionShader1;
+	this.projMaterial1 = new THREE.ShaderMaterial( {
+		uniforms: shader.uniforms,
+		vertexShader: shader.vertexShader,
+		fragmentShader: shader.fragmentShader,
+		transparent: false
+	} );
+
+	this.projMaterial1.uniforms.oneOverWidth.value = oneOverWidth;
+	this.projMaterial1.uniforms.oneOverHeight.value = oneOverHeight;
+
+	this.projMesh1 = new THREE.Mesh( this.fieldGeometry, this.projMaterial1 );
+	this.fieldScene.add( this.projMesh1 );
+
+	// Projection Shader 2
+
+	shader = THREE.Fire.ProjectionShader2;
+	this.projMaterial2 = new THREE.ShaderMaterial( {
+		uniforms: shader.uniforms,
+		vertexShader: shader.vertexShader,
+		fragmentShader: shader.fragmentShader,
+		transparent: false
+	} );
+
+
+	this.projMaterial2.uniforms.oneOverWidth.value = oneOverWidth;
+	this.projMaterial2.uniforms.oneOverHeight.value = oneOverHeight;
+
+	this.projMesh2 = new THREE.Mesh( this.fieldGeometry, this.projMaterial2 );
+	this.fieldScene.add( this.projMesh2 );
+
+	// Projection Shader 3
+
+	shader = THREE.Fire.ProjectionShader3;
+	this.projMaterial3 = new THREE.ShaderMaterial( {
+		uniforms: shader.uniforms,
+		vertexShader: shader.vertexShader,
+		fragmentShader: shader.fragmentShader,
+		transparent: false
+	} );
+
+
+	this.projMaterial3.uniforms.oneOverWidth.value = oneOverWidth;
+	this.projMaterial3.uniforms.oneOverHeight.value = oneOverHeight;
+
+	this.projMesh3 = new THREE.Mesh( this.fieldGeometry, this.projMaterial3 );
+	this.fieldScene.add( this.projMesh3 );
+
+	// Color Shader
+
+	if ( debug ) {
+
+		shader = THREE.Fire.DebugShader;
+
+	} else {
+
+		shader = THREE.Fire.ColorShader;
+
+	}
+	this.material = new THREE.ShaderMaterial( {
+		uniforms: shader.uniforms,
+		vertexShader: shader.vertexShader,
+		fragmentShader: shader.fragmentShader,
+		transparent: true
+	} );
+
+	this.material.uniforms.densityMap.value = this.field1.texture;
+
+	this.configShaders = function ( dt ) {
+
+		this.diffuseMaterial.uniforms.diffuse.value = dt * 0.05 * this.diffuse;
+		this.diffuseMaterial.uniforms.viscosity.value = dt * 0.05 * this.viscosity;
+		this.diffuseMaterial.uniforms.expansion.value = Math.exp( this.expansion * - 1.0 );
+		this.diffuseMaterial.uniforms.swirl.value = Math.exp( this.swirl * - 0.1 );
+		this.diffuseMaterial.uniforms.drag.value = Math.exp( this.drag * - 0.1 );
+		this.diffuseMaterial.uniforms.burnRate.value = this.burnRate * dt * 0.01;
+		this.driftMaterial.uniforms.windVector.value = this.windVector;
+		this.driftMaterial.uniforms.airSpeed.value = dt * this.airSpeed * 0.001 * textureHeight;
+		this.material.uniforms.color1.value = this.color1;
+		this.material.uniforms.color2.value = this.color2;
+		this.material.uniforms.color3.value = this.color3;
+		this.material.uniforms.colorBias.value = this.colorBias;
+
+	};
+
+	this.clearDiffuse = function () {
+
+		this.diffuseMaterial.uniforms.expansion.value = 1.0;
+		this.diffuseMaterial.uniforms.swirl.value = 1.0;
+		this.diffuseMaterial.uniforms.drag.value = 1.0;
+		this.diffuseMaterial.uniforms.burnRate.value = 0.0;
+
+	};
+
+	this.swapTextures = function () {
+
+		var swap = this.field0;
+		this.field0 = this.field1;
+		this.field1 = swap;
+
+	};
+
+	this.saveRenderState = function ( renderer ) {
+
+		this.savedRenderTarget = renderer.getRenderTarget();
+		this.savedVrEnabled = renderer.vr.enabled;
+		this.savedShadowAutoUpdate = renderer.shadowMap.autoUpdate;
+		this.savedAntialias = renderer.antialias;
+		this.savedToneMapping = renderer.toneMapping;
+
+	};
+
+	this.restoreRenderState = function ( renderer ) {
+
+		renderer.vr.enabled = this.savedVrEnabled;
+		renderer.shadowMap.autoUpdate = this.savedShadowAutoUpdate;
+		renderer.setRenderTarget( this.savedRenderTarget );
+		renderer.antialias = this.savedAntialias;
+		renderer.toneMapping = this.savedToneMapping;
+
+	};
+
+	this.renderSource = function ( renderer ) {
+
+		this.sourceMesh.visible = true;
+
+		this.sourceMaterial.uniforms.densityMap.value = this.field0.texture;
+
+		renderer.render( this.fieldScene, this.orthoCamera, this.field1 );
+
+		this.sourceMesh.visible = false;
+
+		this.swapTextures();
+
+	};
+
+	this.renderDiffuse = function ( renderer ) {
+
+		this.diffuseMesh.visible = true;
+
+		this.diffuseMaterial.uniforms.densityMap.value = this.field0.texture;
+
+		renderer.render( this.fieldScene, this.orthoCamera, this.field1 );
+
+		this.diffuseMesh.visible = false;
+
+		this.swapTextures();
+
+	};
+
+	this.renderDrift = function ( renderer ) {
+
+		this.driftMesh.visible = true;
+
+		this.driftMaterial.uniforms.densityMap.value = this.field0.texture;
+
+		renderer.render( this.fieldScene, this.orthoCamera, this.field1 );
+
+		this.driftMesh.visible = false;
+
+		this.swapTextures();
+
+	};
+
+	this.renderProject = function ( renderer ) {
+
+		// Projection pass 1
+
+		this.projMesh1.visible = true;
+
+		this.projMaterial1.uniforms.densityMap.value = this.field0.texture;
+
+		renderer.render( this.fieldScene, this.orthoCamera, this.fieldProj );
+
+		this.projMesh1.visible = false;
+
+		this.projMaterial2.uniforms.densityMap.value = this.fieldProj.texture;
+
+		// Projection pass 2
+
+		this.projMesh2.visible = true;
+
+		for ( var i = 0; i < 20; i ++ ) {
+
+			renderer.render( this.fieldScene, this.orthoCamera, this.field1 );
+
+			var temp = this.field1;
+			this.field1 = this.fieldProj;
+			this.fieldProj = temp;
+
+			this.projMaterial2.uniforms.densityMap.value = this.fieldProj.texture;
+
+		}
+
+		this.projMesh2.visible = false;
+
+		this.projMaterial3.uniforms.densityMap.value = this.field0.texture;
+		this.projMaterial3.uniforms.projMap.value = this.fieldProj.texture;
+
+		// Projection pass 3
+
+		this.projMesh3.visible = true;
+
+		renderer.render( this.fieldScene, this.orthoCamera, this.field1 );
+
+		this.projMesh3.visible = false;
+
+		this.swapTextures();
+
+	};
+
+	this.onBeforeRender = function ( renderer, scene, camera ) {
+
+		var delta = this.clock.getDelta();
+		if ( delta > 0.1 ) {
+
+			delta = 0.1;
+
+		}
+		var dt = delta * ( this.speed * 0.1 );
+
+		this.configShaders( dt );
+
+		this.saveRenderState( renderer );
+
+		renderer.vr.enabled = false; // Avoid camera modification and recursion
+		renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
+		renderer.antialias = false;
+		renderer.toneMapping = THREE.NoToneMapping;
+
+		this.sourceMesh.visible = false;
+		this.diffuseMesh.visible = false;
+		this.driftMesh.visible = false;
+		this.projMesh1.visible = false;
+		this.projMesh2.visible = false;
+		this.projMesh3.visible = false;
+
+		this.renderSource( renderer );
+
+		this.clearDiffuse();
+		for ( var i = 0; i < 21; i ++ ) {
+
+			this.renderDiffuse( renderer );
+
+		}
+		this.configShaders( dt );
+		this.renderDiffuse( renderer );
+
+		this.renderDrift( renderer );
+
+		if ( this.massConservation ) {
+
+			this.renderProject( renderer );
+			this.renderProject( renderer );
+
+		}
+
+		// Final result out for coloring
+
+		this.material.map = this.field1.texture;
+		this.material.transparent = true;
+		this.material.minFilter = THREE.LinearFilter,
+		this.material.magFilter = THREE.LinearFilter,
+
+		this.restoreRenderState( renderer );
+
+	};
+
+};
+
+
+THREE.Fire.prototype = Object.create( THREE.Mesh.prototype );
+THREE.Fire.prototype.constructor = THREE.Fire;
+
+THREE.Fire.SourceShader = {
+
+	uniforms: {
+		'sourceMap': {
+			type: 't',
+			value: null
+		},
+		'densityMap': {
+			type: 't',
+			value: null
+		}
+	},
+
+	vertexShader: [
+		'varying vec2 vUv;',
+
+		'void main() {',
+
+		' 	  vUv = uv;',
+
+		'     vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
+		'     gl_Position = projectionMatrix * mvPosition;',
+
+		'}'
+
+	].join( "\n" ),
+
+	fragmentShader: [
+		'uniform sampler2D sourceMap;',
+		'uniform sampler2D densityMap;',
+
+		'varying vec2 vUv;',
+
+		'void main() {',
+		'    vec4 source = texture2D( sourceMap, vUv );',
+		'    vec4 current = texture2D( densityMap, vUv );',
+
+		'    vec2 v0 = (current.gb - step(0.5, current.gb)) * 2.0;',
+		'    vec2 v1 = (source.gb - step(0.5, source.gb)) * 2.0;',
+
+		'    vec2 newVel = v0 + v1;',
+
+		'    newVel = clamp(newVel, -0.99, 0.99);',
+		'    newVel = newVel * 0.5 + step(0.0, -newVel);',
+
+		'    float newDensity = source.r + current.a;',
+		'    float newTemp = source.r + current.r;',
+
+		'    newDensity = clamp(newDensity, 0.0, 1.0);',
+		'    newTemp = clamp(newTemp, 0.0, 1.0);',
+
+		'    gl_FragColor = vec4(newTemp, newVel.xy, newDensity);',
+
+		'}'
+
+	].join( "\n" )
+};
+
+
+THREE.Fire.DiffuseShader = {
+
+	uniforms: {
+		'oneOverWidth': {
+			type: 'f',
+			value: null
+		},
+		'oneOverHeight': {
+			type: 'f',
+			value: null
+		},
+		'diffuse': {
+			type: 'f',
+			value: null
+		},
+		'viscosity': {
+			type: 'f',
+			value: null
+		},
+		'expansion': {
+			type: 'f',
+			value: null
+		},
+		'swirl': {
+			type: 'f',
+			value: null
+		},
+		'drag': {
+			type: 'f',
+			value: null
+		},
+		'burnRate': {
+			type: 'f',
+			value: null
+		},
+		'densityMap': {
+			type: 't',
+			value: null
+		}
+	},
+
+	vertexShader: [
+		'varying vec2 vUv;',
+
+		'void main() {',
+
+		' 	  vUv = uv;',
+
+		'     vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
+		'     gl_Position = projectionMatrix * mvPosition;',
+
+		'}'
+
+	].join( "\n" ),
+
+	fragmentShader: [
+		'uniform float oneOverWidth;',
+		'uniform float oneOverHeight;',
+		'uniform float diffuse;',
+		'uniform float viscosity;',
+		'uniform float expansion;',
+		'uniform float swirl;',
+		'uniform float burnRate;',
+		'uniform float drag;',
+		'uniform sampler2D densityMap;',
+
+		'varying vec2 vUv;',
+
+		'void main() {',
+
+		'    vec4 dC = texture2D( densityMap, vUv );',
+		'    vec4 dL = texture2D( densityMap, vec2(vUv.x - oneOverWidth, vUv.y) );',
+		'    vec4 dR = texture2D( densityMap, vec2(vUv.x + oneOverWidth, vUv.y) );',
+		'    vec4 dU = texture2D( densityMap, vec2(vUv.x, vUv.y - oneOverHeight) );',
+		'    vec4 dD = texture2D( densityMap, vec2(vUv.x, vUv.y + oneOverHeight) );',
+		'    vec4 dUL = texture2D( densityMap, vec2(vUv.x - oneOverWidth, vUv.y - oneOverHeight) );',
+		'    vec4 dUR = texture2D( densityMap, vec2(vUv.x + oneOverWidth, vUv.y - oneOverHeight) );',
+		'    vec4 dDL = texture2D( densityMap, vec2(vUv.x - oneOverWidth, vUv.y + oneOverHeight) );',
+		'    vec4 dDR = texture2D( densityMap, vec2(vUv.x + oneOverWidth, vUv.y + oneOverHeight) );',
+
+		'    dC.yz = (dC.yz - step(0.5, dC.yz)) * 2.0;',
+		'    dL.yz = (dL.yz - step(0.5, dL.yz)) * 2.0;',
+		'    dR.yz = (dR.yz - step(0.5, dR.yz)) * 2.0;',
+		'    dU.yz = (dU.yz - step(0.5, dU.yz)) * 2.0;',
+		'    dD.yz = (dD.yz - step(0.5, dD.yz)) * 2.0;',
+		'    dUL.yz = (dUL.yz - step(0.5, dUL.yz)) * 2.0;',
+		'    dUR.yz = (dUR.yz - step(0.5, dUR.yz)) * 2.0;',
+		'    dDL.yz = (dDL.yz - step(0.5, dDL.yz)) * 2.0;',
+		'    dDR.yz = (dDR.yz - step(0.5, dDR.yz)) * 2.0;',
+
+		'    vec4 result = (dC + vec4(diffuse, viscosity, viscosity, diffuse) * ( dL + dR + dU + dD + dUL + dUR + dDL + dDR )) / (1.0 + 8.0 * vec4(diffuse, viscosity, viscosity, diffuse)) - vec4(0.0, 0.0, 0.0, 0.001);',
+
+		'    float temperature = result.r;',
+		'    temperature = clamp(temperature - burnRate, 0.0, 1.0);',
+
+		'    vec2 velocity = result.yz;',
+
+		'    vec2 expansionVec = vec2(dL.w - dR.w, dU.w - dD.w);',
+
+		'    vec2 swirlVec = vec2((dL.z - dR.z) * 0.5, (dU.y - dD.y) * 0.5);',
+
+		'    velocity = velocity + (1.0 - expansion) * expansionVec + (1.0 - swirl) * swirlVec;',
+
+		'    velocity = velocity - (1.0 - drag) * velocity;',
+
+		'    gl_FragColor = vec4(temperature, velocity * 0.5 + step(0.0, -velocity), result.w);',
+
+		'    gl_FragColor = gl_FragColor * step(oneOverWidth, vUv.x);',
+		'    gl_FragColor = gl_FragColor * step(oneOverHeight, vUv.y);',
+		'    gl_FragColor = gl_FragColor * step(vUv.x, 1.0 - oneOverWidth);',
+		'    gl_FragColor = gl_FragColor * step(vUv.y, 1.0 - oneOverHeight);',
+
+		'}'
+
+	].join( "\n" )
+};
+
+THREE.Fire.DriftShader = {
+
+	uniforms: {
+		'oneOverWidth': {
+			type: 'f',
+			value: null
+		},
+		'oneOverHeight': {
+			type: 'f',
+			value: null
+		},
+		'windVector': {
+			type: 'v2',
+			value: new THREE.Vector2( 0.0, 0.0 )
+		},
+		'airSpeed': {
+			type: 'f',
+			value: null
+		},
+		'densityMap': {
+			type: 't',
+			value: null
+		}
+	},
+
+	vertexShader: [
+		'varying vec2 vUv;',
+
+		'void main() {',
+
+		' 	  vUv = uv;',
+
+		'     vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
+		'     gl_Position = projectionMatrix * mvPosition;',
+
+		'}'
+
+	].join( "\n" ),
+
+	fragmentShader: [
+		'uniform float oneOverWidth;',
+		'uniform float oneOverHeight;',
+		'uniform vec2 windVector;',
+		'uniform float airSpeed;',
+		'uniform sampler2D densityMap;',
+
+		'varying vec2 vUv;',
+
+		'void main() {',
+		'    vec2 velocity = texture2D( densityMap, vUv ).gb;',
+		'    velocity = (velocity - step(0.5, velocity)) * 2.0;',
+
+		'    velocity = velocity + windVector;',
+
+		'    vec2 sourcePos = vUv - airSpeed * vec2(oneOverWidth, oneOverHeight) * velocity;',
+
+		'    vec2 units = sourcePos / vec2(oneOverWidth, oneOverHeight);',
+
+		'    vec2 intPos = floor(units);',
+		'    vec2 frac = units - intPos;',
+		'    intPos = intPos * vec2(oneOverWidth, oneOverHeight);',
+
+		'    vec4 dX0Y0 = texture2D( densityMap, intPos + vec2(0.0, -oneOverHeight) );',
+		'    vec4 dX1Y0 = texture2D( densityMap, intPos + vec2(oneOverWidth, 0.0) );',
+		'    vec4 dX0Y1 = texture2D( densityMap, intPos + vec2(0.0, oneOverHeight) );',
+		'    vec4 dX1Y1 = texture2D( densityMap, intPos + vec2(oneOverWidth, oneOverHeight) );',
+
+
+		'    dX0Y0.gb = (dX0Y0.gb - step(0.5, dX0Y0.gb)) * 2.0;',
+		'    dX1Y0.gb = (dX1Y0.gb - step(0.5, dX1Y0.gb)) * 2.0;',
+		'    dX0Y1.gb = (dX0Y1.gb - step(0.5, dX0Y1.gb)) * 2.0;',
+		'    dX1Y1.gb = (dX1Y1.gb - step(0.5, dX1Y1.gb)) * 2.0;',
+
+		'    vec4 source = mix(mix(dX0Y0, dX1Y0, frac.x), mix(dX0Y1, dX1Y1, frac.x), frac.y);',
+
+		'    source.gb = source.gb * 0.5 + step(0.0, -source.gb);',
+
+		'    gl_FragColor = source;',
+
+		'}'
+
+	].join( "\n" )
+};
+
+
+THREE.Fire.ProjectionShader1 = {
+
+	uniforms: {
+		'oneOverWidth': {
+			type: 'f',
+			value: null
+		},
+		'oneOverHeight': {
+			type: 'f',
+			value: null
+		},
+		'densityMap': {
+			type: 't',
+			value: null
+		}
+	},
+
+	vertexShader: [
+		'varying vec2 vUv;',
+
+		'void main() {',
+
+		' 	  vUv = uv;',
+
+		'     vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
+		'     gl_Position = projectionMatrix * mvPosition;',
+
+		'}'
+
+	].join( "\n" ),
+
+	fragmentShader: [
+		'uniform float oneOverWidth;',
+		'uniform float oneOverHeight;',
+		'uniform sampler2D densityMap;',
+
+		'varying vec2 vUv;',
+
+		'void main() {',
+		'    float dL = texture2D( densityMap, vec2(vUv.x - oneOverWidth, vUv.y) ).g;',
+		'    float dR = texture2D( densityMap, vec2(vUv.x + oneOverWidth, vUv.y) ).g;',
+		'    float dU = texture2D( densityMap, vec2(vUv.x, vUv.y - oneOverHeight) ).b;',
+		'    float dD = texture2D( densityMap, vec2(vUv.x, vUv.y + oneOverHeight) ).b;',
+
+		'    dL = (dL - step(0.5, dL)) * 2.0;',
+		'    dR = (dR - step(0.5, dR)) * 2.0;',
+		'    dU = (dU - step(0.5, dU)) * 2.0;',
+		'    dD = (dD - step(0.5, dD)) * 2.0;',
+
+		'    float h = (oneOverWidth + oneOverHeight) * 0.5;',
+		'    float div = -0.5 * h * (dR - dL + dD - dU);',
+
+		'    gl_FragColor = vec4( 0.0, 0.0, div * 0.5 + step(0.0, -div), 0.0);',
+
+		'}'
+
+	].join( "\n" )
+};
+
+
+THREE.Fire.ProjectionShader2 = {
+
+	uniforms: {
+		'oneOverWidth': {
+			type: 'f',
+			value: null
+		},
+		'oneOverHeight': {
+			type: 'f',
+			value: null
+		},
+		'densityMap': {
+			type: 't',
+			value: null
+		}
+	},
+
+	vertexShader: [
+		'varying vec2 vUv;',
+
+		'void main() {',
+
+		' 	  vUv = uv;',
+
+		'     vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
+		'     gl_Position = projectionMatrix * mvPosition;',
+
+		'}'
+
+	].join( "\n" ),
+
+	fragmentShader: [
+		'uniform float oneOverWidth;',
+		'uniform float oneOverHeight;',
+		'uniform sampler2D densityMap;',
+
+		'varying vec2 vUv;',
+
+		'void main() {',
+		'    float div = texture2D( densityMap, vUv ).b;',
+		'    float pL = texture2D( densityMap, vec2(vUv.x - oneOverWidth, vUv.y) ).g;',
+		'    float pR = texture2D( densityMap, vec2(vUv.x + oneOverWidth, vUv.y) ).g;',
+		'    float pU = texture2D( densityMap, vec2(vUv.x, vUv.y - oneOverHeight) ).g;',
+		'    float pD = texture2D( densityMap, vec2(vUv.x, vUv.y + oneOverHeight) ).g;',
+
+		'    float divNorm = (div - step(0.5, div)) * 2.0;',
+		'    pL = (pL - step(0.5, pL)) * 2.0;',
+		'    pR = (pR - step(0.5, pR)) * 2.0;',
+		'    pU = (pU - step(0.5, pU)) * 2.0;',
+		'    pD = (pD - step(0.5, pD)) * 2.0;',
+
+		'    float p = (divNorm + pR + pL + pD + pU) * 0.25;',
+
+		'    gl_FragColor = vec4( 0.0, p * 0.5 + step(0.0, -p), div, 0.0);',
+
+		'}'
+
+	].join( "\n" )
+};
+
+
+THREE.Fire.ProjectionShader3 = {
+
+	uniforms: {
+		'oneOverWidth': {
+			type: 'f',
+			value: null
+		},
+		'oneOverHeight': {
+			type: 'f',
+			value: null
+		},
+		'densityMap': {
+			type: 't',
+			value: null
+		},
+		'projMap': {
+			type: 't',
+			value: null
+		}
+	},
+
+	vertexShader: [
+		'varying vec2 vUv;',
+
+		'void main() {',
+
+		' 	  vUv = uv;',
+
+		'     vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
+		'     gl_Position = projectionMatrix * mvPosition;',
+
+		'}'
+
+	].join( "\n" ),
+
+	fragmentShader: [
+		'uniform float oneOverWidth;',
+		'uniform float oneOverHeight;',
+		'uniform sampler2D densityMap;',
+		'uniform sampler2D projMap;',
+
+		'varying vec2 vUv;',
+
+		'void main() {',
+		'    vec4 orig = texture2D(densityMap, vUv);',
+
+		'    float pL = texture2D( projMap, vec2(vUv.x - oneOverWidth, vUv.y) ).g;',
+		'    float pR = texture2D( projMap, vec2(vUv.x + oneOverWidth, vUv.y) ).g;',
+		'    float pU = texture2D( projMap, vec2(vUv.x, vUv.y - oneOverHeight) ).g;',
+		'    float pD = texture2D( projMap, vec2(vUv.x, vUv.y + oneOverHeight) ).g;',
+
+		'    float uNorm = (orig.g - step(0.5, orig.g)) * 2.0;',
+		'    float vNorm = (orig.b - step(0.5, orig.b)) * 2.0;',
+
+		'    pL = (pL - step(0.5, pL)) * 2.0;',
+		'    pR = (pR - step(0.5, pR)) * 2.0;',
+		'    pU = (pU - step(0.5, pU)) * 2.0;',
+		'    pD = (pD - step(0.5, pD)) * 2.0;',
+
+		'    float h = (oneOverWidth + oneOverHeight) * 0.5;',
+		'    float u = uNorm - (0.5 * (pR - pL) / h);',
+		'    float v = vNorm - (0.5 * (pD - pU) / h);',
+
+		'    gl_FragColor = vec4( orig.r, u * 0.5 + step(0.0, -u), v * 0.5 + step(0.0, -v), orig.a);',
+
+		'}'
+
+	].join( "\n" )
+};
+
+THREE.Fire.ColorShader = {
+
+	uniforms: {
+		'color1': {
+			type: 'c',
+			value: null
+		},
+		'color2': {
+			type: 'c',
+			value: null
+		},
+		'color3': {
+			type: 'c',
+			value: null
+		},
+		'colorBias': {
+			type: 'f',
+			value: null
+		},
+		'densityMap': {
+			type: 't',
+			value: null
+		}
+	},
+
+	vertexShader: [
+		'varying vec2 vUv;',
+
+		'void main() {',
+
+		' 	  vUv = uv;',
+
+		'     vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
+		'     gl_Position = projectionMatrix * mvPosition;',
+
+		'}'
+
+	].join( "\n" ),
+
+	fragmentShader: [
+		'uniform vec3 color1;',
+		'uniform vec3 color2;',
+		'uniform vec3 color3;',
+		'uniform float colorBias;',
+		'uniform sampler2D densityMap;',
+
+		'varying vec2 vUv;',
+
+		'void main() {',
+		'    float density = texture2D( densityMap, vUv ).a;',
+		'    float temperature = texture2D( densityMap, vUv ).r;',
+
+		'    float bias = clamp(colorBias, 0.0001, 0.9999);',
+
+		'    vec3 blend1 = mix(color3, color2, temperature / bias) * (1.0 - step(bias, temperature));',
+		'    vec3 blend2 = mix(color2, color1, (temperature - bias) / (1.0 - bias) ) * step(bias, temperature);',
+
+		'    gl_FragColor = vec4(blend1 + blend2, density);',
+		'}'
+
+	].join( "\n" )
+};
+
+
+THREE.Fire.DebugShader = {
+
+	uniforms: {
+		'color1': {
+			type: 'c',
+			value: null
+		},
+		'color2': {
+			type: 'c',
+			value: null
+		},
+		'color3': {
+			type: 'c',
+			value: null
+		},
+		'colorBias': {
+			type: 'f',
+			value: null
+		},
+		'densityMap': {
+			type: 't',
+			value: null
+		}
+	},
+
+	vertexShader: [
+		'varying vec2 vUv;',
+
+		'void main() {',
+
+		' 	  vUv = uv;',
+
+		'     vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );',
+		'     gl_Position = projectionMatrix * mvPosition;',
+
+		'}'
+
+	].join( "\n" ),
+
+	fragmentShader: [
+		'uniform sampler2D densityMap;',
+
+		'varying vec2 vUv;',
+
+		'void main() {',
+		'    float density;',
+		'    density = texture2D( densityMap, vUv ).a;',
+
+		'    vec2 vel = texture2D( densityMap, vUv ).gb;',
+
+		'    vel = (vel - step(0.5, vel)) * 2.0;',
+
+		'    float r = density;',
+		'    float g = max(abs(vel.x), density * 0.5);',
+		'    float b = max(abs(vel.y), density * 0.5);',
+		'    float a = max(density * 0.5, max(abs(vel.x), abs(vel.y)));',
+
+		'    gl_FragColor = vec4(r, g, b, a);',
+
+		'}'
+
+	].join( "\n" )
+};

+ 6 - 3
examples/js/objects/Lensflare.js

@@ -14,6 +14,7 @@ THREE.Lensflare = function () {
 	//
 
 	var positionScreen = new THREE.Vector3();
+	var positionView = new THREE.Vector3();
 
 	// textures
 
@@ -175,10 +176,12 @@ THREE.Lensflare = function () {
 
 		// calculate position in screen space
 
-		positionScreen.setFromMatrixPosition( this.matrixWorld );
+		positionView.setFromMatrixPosition( this.matrixWorld );
+		positionView.applyMatrix4( camera.matrixWorldInverse );
 
-		positionScreen.applyMatrix4( camera.matrixWorldInverse );
-		positionScreen.applyMatrix4( camera.projectionMatrix );
+		if ( positionView.z > 0 ) return; // lensflare is behind the camera
+
+		positionScreen.copy( positionView ).applyMatrix4( camera.projectionMatrix );
 
 		// horizontal and vertical coordinate of the lower left corner of the pixels to copy
 

+ 240 - 0
examples/js/objects/LightningStorm.js

@@ -0,0 +1,240 @@
+/**
+ * @author yomboprime https://github.com/yomboprime
+ *
+ * @fileoverview Lightning strike object generator
+ *
+ * 
+ * Usage
+ * 
+ * var myStorm = new THREE.LightningStorm( paramsObject );
+ * myStorm.position.set( ... );
+ * scene.add( myStorm );
+ * ...
+ * myStorm.update( currentTime );
+ * 
+ * The "currentTime" can only go forwards or be stopped.
+ * 
+ * 
+ * LightningStorm parameters:
+ *
+ * @param {double} size Size of the storm. If no 'onRayPosition' parameter is defined, it means the side of the rectangle the storm covers.
+ *
+ * @param {double} minHeight Minimum height a ray can start at. If no 'onRayPosition' parameter is defined, it means the height above plane y = 0.
+ * 
+ * @param {double} maxHeight Maximum height a ray can start at. If no 'onRayPosition' parameter is defined, it means the height above plane y = 0.
+ * 
+ * @param {double} maxSlope The maximum inclination slope of a ray. If no 'onRayPosition' parameter is defined, it means the slope relative to plane y = 0.
+ * 
+ * @param {integer} maxLightnings Greater than 0. The maximum number of simultaneous rays.
+ * 
+ * @param {double} lightningMinPeriod minimum time between two consecutive rays.
+ * 
+ * @param {double} lightningMaxPeriod maximum time between two consecutive rays.
+ * 
+ * @param {double} lightningMinDuration The minimum time a ray can last.
+ * 
+ * @param {double} lightningMaxDuration The maximum time a ray can last.
+ * 
+ * @param {Object} lightningParameters The parameters for created rays. See THREE.LightningStrike (geometry)
+ * 
+ * @param {Material} lightningMaterial The THREE.Material used for the created rays.
+ * 
+ * @param {function} onRayPosition Optional callback with two Vector3 parameters (source, dest). You can set here the start and end points for each created ray, using the standard size, minHeight, etc parameters and other values in your algorithm.
+ * 
+ * @param {function} onLightningDown This optional callback is called with one parameter (lightningStrike) when a ray ends propagating, so it has hit the ground.
+ * 
+ *
+*/
+
+THREE.LightningStorm = function ( stormParams ) {
+
+	THREE.Object3D.call( this );
+	
+	// Parameters
+
+	stormParams = stormParams || {};
+	this.stormParams = stormParams;
+
+	stormParams.size = stormParams.size !== undefined ? stormParams.size : 1000.0;
+	stormParams.minHeight = stormParams.minHeight !== undefined ? stormParams.minHeight : 80.0;
+	stormParams.maxHeight = stormParams.maxHeight !== undefined ? stormParams.maxHeight : 100.0;
+	stormParams.maxSlope = stormParams.maxSlope !== undefined ? stormParams.maxSlope : 1.1;
+
+	stormParams.maxLightnings = stormParams.maxLightnings !== undefined ? stormParams.maxLightnings : 3;
+
+	stormParams.lightningMinPeriod = stormParams.lightningMinPeriod !== undefined ? stormParams.lightningMinPeriod : 3.0;
+	stormParams.lightningMaxPeriod = stormParams.lightningMaxPeriod !== undefined ? stormParams.lightningMaxPeriod : 7.0;
+
+	stormParams.lightningMinDuration = stormParams.lightningMinDuration !== undefined ? stormParams.lightningMinDuration : 1.0;
+	stormParams.lightningMaxDuration = stormParams.lightningMaxDuration !== undefined ? stormParams.lightningMaxDuration : 2.5;
+
+	this.lightningParameters = THREE.LightningStrike.copyParameters( stormParams.lightningParameters, stormParams.lightningParameters );
+
+	this.lightningParameters.isEternal = false;
+	
+	this.lightningMaterial = stormParams.lightningMaterial !== undefined ? stormParams.lightningMaterial : new THREE.MeshBasicMaterial( { color: 0xB0FFFF } );
+
+	if ( stormParams.onRayPosition !== undefined ) {
+
+		this.onRayPosition = stormParams.onRayPosition;
+
+	}
+	else {
+
+		this.onRayPosition = function( source, dest ) {
+
+			dest.set( ( Math.random() - 0.5 ) * stormParams.size, 0, ( Math.random() - 0.5 ) * stormParams.size );
+			
+			var height = THREE.Math.lerp( stormParams.minHeight, stormParams.maxHeight, Math.random() );;
+
+			source.set( stormParams.maxSlope * ( 2 * Math.random() - 1 ), 1, stormParams.maxSlope * ( 2 * Math.random() - 1 ) ).multiplyScalar( height ).add( dest );
+
+		};
+
+	}
+
+	this.onLightningDown = stormParams.onLightningDown;
+
+	// Internal state
+
+	this.inited = false;
+	this.nextLightningTime = 0;
+	this.lightningsMeshes = [];
+	this.deadLightningsMeshes = [];
+
+	for ( var i = 0; i < this.stormParams.maxLightnings; i++ ) {
+
+		var lightning = new THREE.LightningStrike( THREE.LightningStrike.copyParameters( {}, this.lightningParameters ) );
+		var mesh = new THREE.Mesh( lightning, this.lightningMaterial );
+		this.deadLightningsMeshes.push( mesh );
+
+	}
+
+};
+
+THREE.LightningStorm.prototype = Object.create( THREE.Object3D.prototype );
+
+THREE.LightningStorm.prototype.constructor = THREE.LightningStorm;
+
+THREE.LightningStorm.prototype.isLightningStorm = true;
+
+THREE.LightningStorm.prototype.update = function ( time ) {
+
+	if ( ! this.inited ) {
+
+		this.nextLightningTime = this.getNextLightningTime( time ) * Math.random();
+		this.inited = true;
+
+	}
+
+	if ( time >= this.nextLightningTime ) {
+
+		// Lightning creation
+
+		var lightningMesh = this.deadLightningsMeshes.pop();
+
+		if ( lightningMesh ) {
+
+			var lightningParams1 = THREE.LightningStrike.copyParameters( lightningMesh.geometry.rayParameters, this.lightningParameters );
+
+			lightningParams1.birthTime = time;
+			lightningParams1.deathTime = time + THREE.Math.lerp( this.stormParams.lightningMinDuration, this.stormParams.lightningMaxDuration, Math.random() );
+
+			this.onRayPosition( lightningParams1.sourceOffset, lightningParams1.destOffset );
+
+			lightningParams1.noiseSeed = Math.random();
+
+			this.add( lightningMesh );
+
+			this.lightningsMeshes.push( lightningMesh );
+
+		}
+
+		// Schedule next lightning
+		this.nextLightningTime = this.getNextLightningTime( time );
+
+	}
+
+	var i = 0; il = this.lightningsMeshes.length;
+
+	while ( i < il ){
+
+		var mesh = this.lightningsMeshes[ i ];
+
+		var lightning = mesh.geometry;
+
+		var prevState = lightning.state;
+
+		lightning.update( time );
+
+		if ( prevState === THREE.LightningStrike.RAY_PROPAGATING && lightning.state > prevState ) {
+
+			if ( this.onLightningDown ) {
+
+				this.onLightningDown( lightning );
+
+			}
+
+		}
+
+		if ( lightning.state === THREE.LightningStrike.RAY_EXTINGUISHED ) {
+
+			// Lightning is to be destroyed
+
+			this.lightningsMeshes.splice( this.lightningsMeshes.indexOf( mesh ), 1 ); 
+
+			this.deadLightningsMeshes.push( mesh );
+
+			this.remove( mesh );
+
+			il--;
+
+		}
+		else {
+
+			i++;
+
+		}
+
+	}
+
+};
+
+THREE.LightningStorm.prototype.getNextLightningTime = function ( currentTime ) {
+
+	return currentTime + THREE.Math.lerp( this.stormParams.lightningMinPeriod, this.stormParams.lightningMaxPeriod, Math.random() ) / ( this.stormParams.maxLightnings + 1 );
+
+};
+
+THREE.LightningStorm.prototype.copy = function ( source ) {
+	
+	Object3D.prototype.copy.call( this, source );
+
+	this.stormParams.size = source.stormParams.size;
+	this.stormParams.minHeight = source.stormParams.minHeight;
+	this.stormParams.maxHeight = source.stormParams.maxHeight;
+	this.stormParams.maxSlope = source.stormParams.maxSlope;
+
+	this.stormParams.maxLightnings = source.stormParams.maxLightnings;
+
+	this.stormParams.lightningMinPeriod = source.stormParams.lightningMinPeriod;
+	this.stormParams.lightningMaxPeriod = source.stormParams.lightningMaxPeriod;
+
+	this.stormParams.lightningMinDuration = source.stormParams.lightningMinDuration;
+	this.stormParams.lightningMaxDuration = source.stormParams.lightningMaxDuration;
+
+	this.lightningParameters = THREE.LightningStrike.copyParameters( {}, source.lightningParameters );
+
+	this.lightningMaterial = source.stormParams.lightningMaterial;
+
+	this.onLightningDown = source.onLightningDown;
+
+	return this;
+
+};
+
+THREE.LightningStrike.prototype.clone = function () {
+
+	return new this.constructor( this.stormParams ).copy( this );
+
+};

部分文件因为文件数量过多而无法显示