Mr.doob 4 years ago
parent
commit
57e4416cec
100 changed files with 4521 additions and 4073 deletions
  1. 199 1035
      build/three.js
  2. 0 1
      build/three.min.js
  3. 241 152
      build/three.module.js
  4. 5 4
      docs/api/ar/audio/Audio.html
  5. 4 3
      docs/api/en/audio/Audio.html
  6. 6 0
      docs/api/en/core/InterleavedBufferAttribute.html
  7. 6 0
      docs/api/en/materials/Material.html
  8. 1 1
      docs/api/en/materials/MeshStandardMaterial.html
  9. 9 0
      docs/api/en/math/MathUtils.html
  10. 1 1
      docs/api/en/math/Plane.html
  11. 3 38
      docs/api/en/math/Quaternion.html
  12. 14 0
      docs/api/en/math/Sphere.html
  13. 0 15
      docs/api/en/renderers/WebGLRenderer.html
  14. 4 1
      docs/api/en/renderers/webgl/WebGLProgram.html
  15. 1 1
      docs/api/en/scenes/Scene.html
  16. 28 8
      docs/api/en/textures/Texture.html
  17. 5 5
      docs/api/ko/audio/Audio.html
  18. 8 7
      docs/api/zh/audio/Audio.html
  19. 6 0
      docs/api/zh/core/InterleavedBufferAttribute.html
  20. 6 0
      docs/api/zh/materials/Material.html
  21. 1 1
      docs/api/zh/materials/MeshStandardMaterial.html
  22. 1 1
      docs/api/zh/math/Box3.html
  23. 9 0
      docs/api/zh/math/MathUtils.html
  24. 1 1
      docs/api/zh/math/Plane.html
  25. 3 38
      docs/api/zh/math/Quaternion.html
  26. 14 0
      docs/api/zh/math/Sphere.html
  27. 0 15
      docs/api/zh/renderers/WebGLRenderer.html
  28. 4 1
      docs/api/zh/renderers/webgl/WebGLProgram.html
  29. 1 1
      docs/api/zh/scenes/Scene.html
  30. 32 11
      docs/api/zh/textures/Texture.html
  31. 6 1
      docs/examples/en/animations/CCDIKSolver.html
  32. 2 0
      docs/examples/en/animations/MMDAnimationHelper.html
  33. 5 6
      docs/examples/en/controls/OrbitControls.html
  34. 1 1
      docs/examples/en/controls/TrackballControls.html
  35. 0 4
      docs/examples/en/helpers/RectAreaLightHelper.html
  36. 11 1
      docs/examples/en/loaders/SVGLoader.html
  37. 5 5
      docs/examples/ko/controls/OrbitControls.html
  38. 1 1
      docs/examples/ko/controls/TrackballControls.html
  39. 5 0
      docs/examples/zh/animations/CCDIKSolver.html
  40. 2 0
      docs/examples/zh/animations/MMDAnimationHelper.html
  41. 5 5
      docs/examples/zh/controls/OrbitControls.html
  42. 2 2
      docs/examples/zh/controls/TrackballControls.html
  43. 0 4
      docs/examples/zh/helpers/RectAreaLightHelper.html
  44. 11 1
      docs/examples/zh/loaders/SVGLoader.html
  45. 2 1
      docs/index.html
  46. 30 1
      docs/list.json
  47. 1 1
      docs/manual/ar/introduction/FAQ.html
  48. 1 1
      docs/manual/en/introduction/FAQ.html
  49. 1 1
      docs/manual/en/introduction/How-to-dispose-of-objects.html
  50. 232 0
      docs/manual/ja/buildTools/Testing-with-NPM.html
  51. 116 0
      docs/manual/ja/introduction/Animation-system.html
  52. 125 0
      docs/manual/ja/introduction/Browser-support.html
  53. 162 0
      docs/manual/ja/introduction/Creating-a-scene.html
  54. 108 0
      docs/manual/ja/introduction/Creating-text.html
  55. 70 0
      docs/manual/ja/introduction/Drawing-lines.html
  56. 59 0
      docs/manual/ja/introduction/FAQ.html
  57. 76 0
      docs/manual/ja/introduction/How-to-create-VR-content.html
  58. 130 0
      docs/manual/ja/introduction/How-to-dispose-of-objects.html
  59. 149 0
      docs/manual/ja/introduction/How-to-run-things-locally.html
  60. 263 0
      docs/manual/ja/introduction/How-to-update-things.html
  61. 115 0
      docs/manual/ja/introduction/How-to-use-post-processing.html
  62. 162 0
      docs/manual/ja/introduction/Installation.html
  63. 96 0
      docs/manual/ja/introduction/Libraries-and-Plugins.html
  64. 156 0
      docs/manual/ja/introduction/Loading-3D-models.html
  65. 86 0
      docs/manual/ja/introduction/Matrix-transformations.html
  66. 40 0
      docs/manual/ja/introduction/Typescript-setup.html
  67. 183 0
      docs/manual/ja/introduction/Useful-links.html
  68. 33 0
      docs/manual/ja/introduction/WebGL-compatibility-check.html
  69. 1 1
      docs/manual/ko/introduction/FAQ.html
  70. 1 1
      docs/manual/zh/introduction/FAQ.html
  71. 18 6
      editor/js/Loader.js
  72. 4 2
      editor/js/Menubar.View.js
  73. 6 6
      editor/js/Sidebar.Material.js
  74. 9 7
      editor/js/Sidebar.Project.Video.js
  75. 29 5
      editor/js/Strings.js
  76. 18 23
      editor/js/Viewport.js
  77. 5 2
      editor/sw.js
  78. 3 2
      examples/files.json
  79. 98 84
      examples/js/animation/CCDIKSolver.js
  80. 234 41
      examples/js/animation/MMDAnimationHelper.js
  81. 6 0
      examples/js/controls/DeviceOrientationControls.js
  82. 9 0
      examples/js/controls/DragControls.js
  83. 0 2
      examples/js/controls/FirstPersonControls.js
  84. 0 2
      examples/js/controls/FlyControls.js
  85. 2 4
      examples/js/controls/OrbitControls.js
  86. 4 9
      examples/js/controls/TrackballControls.js
  87. 56 2
      examples/js/lines/LineMaterial.js
  88. 72 3
      examples/js/lines/LineSegments2.js
  89. 2 2
      examples/js/lines/Wireframe.js
  90. 0 2285
      examples/js/loaders/AssimpLoader.js
  91. 52 4
      examples/js/loaders/MMDLoader.js
  92. 464 16
      examples/js/loaders/SVGLoader.js
  93. 13 42
      examples/js/loaders/TGALoader.js
  94. 1 1
      examples/js/misc/ConvexObjectBreaker.js
  95. 0 18
      examples/js/objects/Water.js
  96. 6 1
      examples/js/postprocessing/EffectComposer.js
  97. 1 0
      examples/js/postprocessing/OutlinePass.js
  98. 11 1
      examples/js/renderers/CSS2DRenderer.js
  99. 97 83
      examples/jsm/animation/CCDIKSolver.js
  100. 234 41
      examples/jsm/animation/MMDAnimationHelper.js

File diff suppressed because it is too large
+ 199 - 1035
build/three.js


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


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


+ 5 - 4
docs/api/ar/audio/Audio.html

@@ -65,7 +65,8 @@
 		<p>تعديل درجة الصوت ، مقاسة بالسنت. +/- 100 نصف نغمة. +/- 1200 هو *octave*. الافتراضي هو *0*.</p>
 
 		<h3>[property:Array filters]</h3>
-		<p>يمثل مجموعة من [link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNodes]. يمكن استخدامه لتطبيق مجموعة متنوعة من المرشحات ذات الترتيب المنخفض لإنشاء مؤثرات صوتية أكثر تعقيدًا. يتم ضبط المرشحات عبر [page:Audio.setFilter] أو [page:Audio.setFilters].</p>
+		<p>Represents an array of [link:https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNodes]. Can be used to apply a variety of low-order filters to create more complex sound effects.
+			In most cases, the array contains instances of [link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNodes]. Filters are set via [page:Audio.setFilter] or [page:Audio.setFilters].</p>
 
 		<h3>[property:GainNode gain]</h3>
 		<p>[link:https://developer.mozilla.org/en-US/docs/Web/API/GainNode GainNode] تم إنشاؤه باستخدام [link:https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createGain AudioContext.createGain]().</p>
@@ -163,13 +164,13 @@
 
 		<h3>[method:Audio setFilter]( filter )</h3>
 		<p>
-		يطبق [link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNode] واحدًا على الصوت.
+		Applies a single filter node to the audio.
 		</p>
 
 		<h3>[method:Audio setFilters]( [param:Array value] )</h3>
 		<p>
-		value - جداول (صفائف) المرشحات.<br />
-		يطبق جدول (مصفوفة) من [link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNodes] على الصوت.
+		value - arrays of filters.<br />
+		Applies an array of filter nodes to the audio.
 		</p>
 
 		<h3>[method:Audio setLoop]( [param:Boolean value] )</h3>

+ 4 - 3
docs/api/en/audio/Audio.html

@@ -65,7 +65,8 @@
 		<p>Modify pitch, measured in cents. +/- 100 is a semitone. +/- 1200 is an octave. Default is *0*.</p>
 
 		<h3>[property:Array filters]</h3>
-		<p>Represents an array of [link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNodes]. Can be used to apply a variety of low-order filters to create more complex sound effects. Filters are set via [page:Audio.setFilter] or [page:Audio.setFilters].</p>
+		<p>Represents an array of [link:https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNodes]. Can be used to apply a variety of low-order filters to create more complex sound effects.
+			In most cases, the array contains instances of [link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNodes]. Filters are set via [page:Audio.setFilter] or [page:Audio.setFilters].</p>
 
 		<h3>[property:GainNode gain]</h3>
 		<p>A [link:https://developer.mozilla.org/en-US/docs/Web/API/GainNode GainNode] created
@@ -169,13 +170,13 @@
 
 		<h3>[method:Audio setFilter]( filter )</h3>
 		<p>
-		Applies a single [link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNode] to the audio.
+		Applies a single filter node to the audio.
 		</p>
 
 		<h3>[method:Audio setFilters]( [param:Array value] )</h3>
 		<p>
 		value - arrays of filters.<br />
-		Applies an array of [link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNodes] to the audio.
+		Applies an array of filter nodes to the audio.
 		</p>
 
 		<h3>[method:Audio setLoop]( [param:Boolean value] )</h3>

+ 6 - 0
docs/api/en/core/InterleavedBufferAttribute.html

@@ -69,6 +69,12 @@
 		<h3>[method:this applyMatrix4]( [param:Matrix4 m] )</h3>
 		<p>Applies matrix [page:Matrix4 m] to every Vector3 element of this InterleavedBufferAttribute.</p>
 
+		<h3>[method:this applyNormalMatrix]( [param:Matrix3 m] )</h3>
+		<p>Applies normal matrix [page:Matrix3 m] to every Vector3 element of this InterleavedBufferAttribute.</p>
+
+		<h3>[method:this transformDirection]( [param:Matrix4 m] )</h3>
+		<p>Applies matrix [page:Matrix4 m] to every Vector3 element of this InterleavedBufferAttribute, interpreting the elements as a direction vectors.</p>
+
 		<h3>[method:Number getX]( [param:Integer index] ) </h3>
 		<p>Returns the x component of the item at the given index.</p>
 

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

@@ -36,6 +36,12 @@
 		Default is *0*.
 		</p>
 
+		<h3>[property:Float alphaToCoverage]</h3>
+		<p>
+		Enables alpha to coverage. Can only be used with MSAA-enabled contexts (meaning when the renderer was created with *antialias* parameter set to *true*).
+		Default is *false*.
+		</p>
+
 		<h3>[property:Integer blendDst]</h3>
 		<p>
 		Blending destination. Default is [page:CustomBlendingEquation OneMinusSrcAlphaFactor].

+ 1 - 1
docs/api/en/materials/MeshStandardMaterial.html

@@ -49,7 +49,7 @@
 		</p>
 		<p>
 			Technical details of the approach used in three.js (and most other PBR systems) can be found is this
-			[link:https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf paper from Disney] (pdf),
+			[link:https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf paper from Disney] (pdf),
 			by Brent Burley.
 		</p>
 

+ 9 - 0
docs/api/en/math/MathUtils.html

@@ -42,6 +42,15 @@
 		<h3>[method:Boolean isPowerOfTwo]( [param:Number n] )</h3>
 		<p>Return *true* if [page:Number n] is a power of 2.</p>
 
+		<h3>[method:Float inverseLerp]( [param:Float x], [param:Float y], [param:Float value] )</h3>
+		<p>
+		[page:Float x] - Start point.<br />
+		[page:Float y] - End point.<br />
+		[page:Float value] - A value between start and end.<br><br />
+
+		Returns the percentage in the closed interval [0, 1] of the given value between the start and end point.
+		</p>
+
 		<h3>[method:Float lerp]( [param:Float x], [param:Float y], [param:Float t] )</h3>
 		<p>
 		[page:Float x] - Start point. <br />

+ 1 - 1
docs/api/en/math/Plane.html

@@ -79,7 +79,7 @@
 		[page:Line3 line] - the [page:Line3] to check for intersection.<br />
 		[page:Vector3 target] — the result will be copied into this Vector3.<br /><br />
 
-		Returns the intersection point of the passed line and the plane. Returns undefined
+		Returns the intersection point of the passed line and the plane. Returns null
 		 if the line does not intersect. Returns the line's starting point if the line is
 		 coplanar with the plane.
 		</p>

+ 3 - 38
docs/api/en/math/Quaternion.html

@@ -163,6 +163,9 @@
 			</code>
 		</p>
 
+		<h3>[method:this slerpQuaternions]( [param:Quaternion qa], [param:Quaternion qb], [param:Float t] )</h3>
+		<p>Performs a spherical linear interpolation between the given quaternions and stores the result in this quaternion.</p>
+
 		<h3>[method:Quaternion set]( [param:Float x], [param:Float y], [param:Float z], [param:Float w] )</h3>
 		<p>Sets [page:.x x], [page:.y y], [page:.z z], [page:.w w] properties of this quaternion.</p>
 
@@ -211,44 +214,6 @@
 
 		<h2>Static Methods</h2>
 
-		<p>
-			Static methods (as opposed to instance methods) are designed to be called directly from the class,
-			rather than from a specific instance. So to use the static version of, call it like so:
-			<code>
-THREE.Quaternion.slerp( qStart, qEnd, qTarget, t );
-			</code>
-			By contrast, to call the 'normal' or instanced slerp method, you would do the following:
-			<code>
-//instantiate a quaternion with default values
-const q = new THREE.Quaternion();
-
-//call the instanced slerp method
-q.slerp( qb, t )
-			</code>
-
-		</p>
-
-		<h3>[method:Quaternion slerp]( [param:Quaternion qStart], [param:Quaternion qEnd], [param:Quaternion qTarget], [param:Float t] )</h3>
-		<p>
-			[page:Quaternion qStart] - The starting quaternion (where [page:Float t] is 0)<br />
-			[page:Quaternion qEnd] - The ending quaternion (where [page:Float t] is 1)<br />
-			[page:Quaternion qTarget] - The target quaternion that gets set with the result<br />
-			[page:Float t] - interpolation factor in the closed interval [0, 1].<br /><br />
-
-			Unlike the normal method, the static version of slerp sets a target quaternion to the result of the slerp operation.
-			<code>
-			// Code setup
-			const startQuaternion = new THREE.Quaternion().set( 0, 0, 0, 1 ).normalize();
-			const endQuaternion = new THREE.Quaternion().set( 1, 1, 1, 1 ).normalize();
-			let t = 0;
-
-			// Update a mesh's rotation in the loop
-			t = ( t + 0.01 ) % 1; // constant angular momentum
-			THREE.Quaternion.slerp( startQuaternion, endQuaternion, mesh.quaternion, t );
-			</code>
-		</p>
-
-
 		<h3>[method:null slerpFlat]( [param:Array dst], [param:Integer dstOffset], [param:Array src0], [param:Integer srcOffset0], [param:Array src1], [param:Integer srcOffset1], [param:Float t] )</h3>
 		<p>
 		[page:Array dst] - The output array.<br />

+ 14 - 0
docs/api/en/math/Sphere.html

@@ -72,6 +72,13 @@
 		the distance will be negative.
 		</p>
 
+		<h3>[method:this expandByPoint]( [param:Vector3 point] )</h3>
+		<p>
+		[page:Vector3 point] - [page:Vector3] that should be included in the sphere.<br /><br />
+
+		Expands the boundaries of this sphere to include [page:Vector3 point].
+		</p>
+
 		<h3>[method:Boolean isEmpty]()</h3>
 		<p>
 		Checks to see if the sphere is empty (the radius set to a negative number).</br>
@@ -138,6 +145,13 @@
 		Translate the sphere's center by the provided offset [page:Vector3].
 		</p>
 
+		<h3>[method:this union]( [param:Sphere sphere] )</h3>
+		<p>
+		[page:Sphere sphere] - Bounding sphere that will be unioned with this sphere.<br /><br />
+
+		Expands this sphere to enclose both the original sphere and the given sphere.
+		</p>
+
 		<h2>Source</h2>
 
 		<p>

+ 0 - 15
docs/api/en/renderers/WebGLRenderer.html

@@ -205,18 +205,6 @@
 		<h3>[property:Boolean localClippingEnabled]</h3>
 		<p>Defines whether the renderer respects object-level clipping planes. Default is *false*.</p>
 
-		<h3>[property:Integer maxMorphTargets]</h3>
-		<p>
-		Default is 8. The maximum number of MorphTargets allowed in a shader.
-			Keep in mind that the standard materials only allow 8 MorphTargets.
-		</p>
-
-		<h3>[property:Integer maxMorphNormals]</h3>
-		<p>
-		Default is 4. The maximum number of MorphNormals allowed in a shader.
-			Keep in mind that the standard materials only allow 4 MorphNormals.
-		</p>
-
 		<h3>[property:Boolean physicallyCorrectLights]</h3>
 		<p>
 		Whether to use physically correct lighting mode. Default is *false*.
@@ -444,9 +432,6 @@
 		<h3>[method:null setClearColor]( [param:Color color], [param:Float alpha] )</h3>
 		<p>Sets the clear color and opacity.</p>
 
-		<h3>[method:null setFramebuffer]( [param:WebGLFramebuffer value] )</h3>
-		<p>Sets the given WebGLFramebuffer. This method can only be used if no render target is set via [page:WebGLRenderer.setRenderTarget .setRenderTarget]().</p>
-
 		<h3>[method:null setPixelRatio]( [param:number value] )</h3>
 		<p>Sets device pixel ratio. This is usually used for HiDPI device to prevent bluring output canvas.</p>
 

+ 4 - 1
docs/api/en/renderers/webgl/WebGLProgram.html

@@ -55,7 +55,10 @@
 		<h3>Vertex shader (conditional):</h3>
 		<div>
 		<code>
-		#ifdef USE_COLOR
+		#if defined( USE_COLOR_ALPHA )
+			// vertex color attribute with alpha
+			attribute vec4 color;
+		#elif defined( USE_COLOR )
 			// vertex color attribute
 			attribute vec3 color;
 		#endif

+ 1 - 1
docs/api/en/scenes/Scene.html

@@ -33,7 +33,7 @@
 		<h3>[property:Object background]</h3>
 		<p>
 		If not null, sets the background used when rendering the scene, and is always rendered first.
-		Can be set to a [page:Color] which sets the clear color, a [page:Texture] covering the canvas, a cubemap as a [page:CubeTexture] or [page:WebGLCubeRenderTarget] or an equirectangular as a [page:Texture] . Default is null.
+		Can be set to a [page:Color] which sets the clear color, a [page:Texture] covering the canvas, a cubemap as a [page:CubeTexture] or an equirectangular as a [page:Texture] . Default is null.
 		</p>
 
 		<h3>[property:Texture environment]</h3>

+ 28 - 8
docs/api/en/textures/Texture.html

@@ -139,10 +139,33 @@
 		<h3>[property:Vector2 offset]</h3>
 		<p>
 		How much a single repetition of the texture is offset from the beginning, in each direction U and V.
-		Typical range is *0.0* to *1.0*.  _Note:_ The offset property is a convenience modifier and only affects
-		the Texture's application to the first set of UVs on a model.  If the Texture is used as a map requiring
-		additional UV sets (e.g. the aoMap or lightMap of most stock materials), those UVs must be manually
-		assigned to achieve the desired offset.
+		Typical range is *0.0* to *1.0*.
+		</p>
+		<p>
+			The below texture types share the *first* uv channel in the engine. The offset (and repeat) setting is evaluated according to
+			the following priorities and then shared by those textures:
+			<ol>
+				<li>color map</li>
+				<li>specular map</li>
+				<li>displacement map</li>
+				<li>normal map</li>
+				<li>bump map</li>
+				<li>roughness map</li>
+				<li>metalness map</li>
+				<li>alpha map</li>
+				<li>emissive map</li>
+				<li>clearcoat map</li>
+				<li>clearcoat normal map</li>
+				<li>clearcoat roughnessMap map</li>
+			</ol>
+		</p>
+		<p>
+			The below texture types share the *second* uv channel in the engine. The offset (and repeat) setting is evaluated according to
+			the following priorities and then shared by those textures:
+			<ol>
+				<li>ao map</li>
+				<li>light map</li>
+			</ol>
 		</p>
 
 		<h3>[property:Vector2 repeat]</h3>
@@ -150,10 +173,7 @@
 		How many times the texture is repeated across the surface, in each direction U and V.  If repeat is set
 		greater than 1 in either direction, the corresponding Wrap parameter should also be set to
 		[page:Textures THREE.RepeatWrapping] or [page:Textures THREE.MirroredRepeatWrapping] to achieve the desired
-		tiling effect.  _Note:_ The repeat property is a convenience modifier and only affects
-		the Texture's application to the first set of UVs on a model.  If the Texture is used as a map requiring
-		additional UV sets (e.g. the aoMap or lightMap of most stock materials), those UVs must be manually
-		assigned to achieve the desired repetiton.
+		tiling effect. Setting different repeat values for textures is restricted in the same way like [page:.offset].
 		</p>
 
 		<h3>[property:number rotation]</h3>

+ 5 - 5
docs/api/ko/audio/Audio.html

@@ -65,8 +65,8 @@
 		<p>피치를 조정하며 100 단위로 조절합니다. +/- 100 은 세미톤 조절. +/- 1200 은 옥타브 조절. 기본값은 *0*입니다.</p>
 
 		<h3>[property:Array filters]</h3>
-		<p>[link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNodes] 배열입니다. 
-			다양한 저차 필터를 적용하여 보다 복잡한 사운드 효과를 만들 수 있습니다. 필터는 [page.Audio.setFilter] 또는 [page:Audio.setFilters]로 설정합니다.</p>
+		<p>Represents an array of [link:https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNodes]. Can be used to apply a variety of low-order filters to create more complex sound effects.
+			In most cases, the array contains instances of [link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNodes]. Filters are set via [page:Audio.setFilter] or [page:Audio.setFilters].</p>
 
 		<h3>[property:GainNode gain]</h3>
 		<p> [link:https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createGain AudioContext.createGain]()를 사용해 만들어진 [link:https://developer.mozilla.org/en-US/docs/Web/API/GainNode GainNode].</p>
@@ -167,13 +167,13 @@
 
 		<h3>[method:Audio setFilter]( filter )</h3>
 		<p>
-		오디오에 새 [link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNode]를 적용합니다.
+		Applies a single filter node to the audio.
 		</p>
 
 		<h3>[method:Audio setFilters]( [param:Array value] )</h3>
 		<p>
-		필터 배열들의 값<br />
-		오디오에 [link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNodes] 배열을 적용합니다.
+		value - arrays of filters.<br />
+		Applies an array of filter nodes to the audio.
 		</p>
 
 		<h3>[method:Audio setLoop]( [param:Boolean value] )</h3>

+ 8 - 7
docs/api/zh/audio/Audio.html

@@ -65,7 +65,8 @@
 		<p>修改音高,以音分为单位。 +/- 100为一个半音, +/- 1200为一个八度。默认值为0。</p>
 
 		<h3>[property:Array filters]</h3>
-		<p>表示[link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNodes]的数组. 可以使用多种不同的低阶filters去创建复杂的音效. filters可以通过 [page:Audio.setFilter] 或者 [page:Audio.setFilters]设置.</p>
+		<p>Represents an array of [link:https://developer.mozilla.org/en-US/docs/Web/API/AudioNode AudioNodes]. Can be used to apply a variety of low-order filters to create more complex sound effects.
+			In most cases, the array contains instances of [link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNodes]. Filters are set via [page:Audio.setFilter] or [page:Audio.setFilters].</p>
 
 		<h3>[property:GainNode gain]</h3>
 		<p>使用[link:https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createGain AudioContext.createGain]()创建的[link:https://developer.mozilla.org/en-US/docs/Web/API/GainNode GainNode].</p>
@@ -74,10 +75,10 @@
 		<p>是否可以使用 [page:Audio.play play](),
 			[page:Audio.pause pause]()等方法控制播放. 默认为 *true*.</p>
 
-		<h3>[property:Boolean isPlaying]</h3>	
-		<p>是否正在播放</p>	
+		<h3>[property:Boolean isPlaying]</h3>
+		<p>是否正在播放</p>
 
-		<h3>[property:AudioListener listener]</h3>	
+		<h3>[property:AudioListener listener]</h3>
 		<p>A reference to the listener object of this audio.</p>
 
 		<h3>[property:Number playbackRate]</h3>
@@ -165,13 +166,13 @@
 
 		<h3>[method:Audio setFilter]( filter )</h3>
 		<p>
-		设置一个[link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNode]给Audio.
+		Applies a single filter node to the audio.
 		</p>
 
 		<h3>[method:Audio setFilters]( [param:Array value] )</h3>
 		<p>
-		value--filters数组.<br />
-		应用[link:https://developer.mozilla.org/en-US/docs/Web/API/BiquadFilterNode BiquadFilterNodes]数组给Audio.
+		value - arrays of filters.<br />
+		Applies an array of filter nodes to the audio.
 		</p>
 
 		<h3>[method:Audio setLoop]( [param:Boolean value] )</h3>

+ 6 - 0
docs/api/zh/core/InterleavedBufferAttribute.html

@@ -68,6 +68,12 @@
 		<h3>[method:this applyMatrix4]( [param:Matrix4 m] )</h3>
 		<p>Applies matrix [page:Matrix4 m] to every Vector3 element of this InterleavedBufferAttribute.</p>
 
+		<h3>[method:this applyNormalMatrix]( [param:Matrix3 m] )</h3>
+		<p>Applies normal matrix [page:Matrix3 m] to every Vector3 element of this InterleavedBufferAttribute.</p>
+
+		<h3>[method:this transformDirection]( [param:Matrix4 m] )</h3>
+		<p>Applies matrix [page:Matrix4 m] to every Vector3 element of this InterleavedBufferAttribute, interpreting the elements as a direction vectors.</p>
+
 		<h3>[method:Number getX]( [param:Integer index] ) </h3>
 		<p>返回给定索引矢量的第一个元素 (X 值)。</p>
 

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

@@ -28,6 +28,12 @@
 <p>设置运行alphaTest时要使用的alpha值。如果不透明度低于此值,则不会渲染材质。默认值为*0*。
 </p>
 
+<h3>[property:Float alphaToCoverage]</h3>
+<p>
+Enables alpha to coverage. Can only be used with MSAA-enabled contexts (meaning when the renderer was created with *antialias* parameter set to *true*).
+Default is *false*.
+</p>
+
 <h3>[property:Integer blendDst]</h3>
 <p> 混合目标。默认值为[page:CustomBlendingEquation OneMinusSrcAlphaFactor]。
 	目标因子所有可能的取值请参阅[page:CustomBlendingEquation constants]。

+ 1 - 1
docs/api/zh/materials/MeshStandardMaterial.html

@@ -37,7 +37,7 @@
 			</ul>
 		</p>
 		<p>在 three.js(以及其他大多数PBR系统)中使用方法的技术细节,
-			可以在Brent Burley撰写的[link:https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf paper from Disney] (pdf)
+			可以在Brent Burley撰写的[link:https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf paper from Disney] (pdf)
 			中查看。
 		</p>
 

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

@@ -10,7 +10,7 @@
 		<h1>[name]</h1>
 
 		<p class="desc">
-			表示维空间中的一个轴对齐包围盒(axis-aligned bounding box,AABB)。
+			表示维空间中的一个轴对齐包围盒(axis-aligned bounding box,AABB)。
 		</p>
 
 		<h2>代码示例</h2>

+ 9 - 0
docs/api/zh/math/MathUtils.html

@@ -40,6 +40,15 @@
 		<h3>[method:Boolean isPowerOfTwo]( [param:Number n] )</h3>
 		<p>如果 [page:Number n] 是2的幂,返回true。</p>
 
+		<h3>[method:Float inverseLerp]( [param:Float x], [param:Float y], [param:Float value] )</h3>
+		<p>
+		[page:Float x] - Start point.<br />
+		[page:Float y] - End point.<br />
+		[page:Float value] - A value between start and end.<br><br />
+
+		Returns the percentage in the closed interval [0, 1] of the given value between the start and end point.
+		</p>
+
 		<h3>[method:Float lerp]( [param:Float x], [param:Float y], [param:Float t] )</h3>
 		<p>
 		[page:Float x] - 起始点。 <br />

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

@@ -75,7 +75,7 @@
 		[page:Line3 line] - 检测是否相交的三维几何线段 [page:Line3]。<br />
 		[page:Vector3 target] — 结果将会写入该向量中。<br /><br />
 
-		返回给定线段和平面的交点。如果不相交则返回undefined。如果线与平面共面,则返回该线段的起始点。
+		返回给定线段和平面的交点。如果不相交则返回null。如果线与平面共面,则返回该线段的起始点。
 		</p>
 
 		<h3>[method:Boolean intersectsBox]( [param:Box3 box] )</h3>

+ 3 - 38
docs/api/zh/math/Quaternion.html

@@ -159,6 +159,9 @@
 			</code>
 		</p>
 
+		<h3>[method:this slerpQuaternions]( [param:Quaternion qa], [param:Quaternion qb], [param:Float t] )</h3>
+		<p>Performs a spherical linear interpolation between the given quaternions and stores the result in this quaternion.</p>
+
 		<h3>[method:Quaternion set]( [param:Float x], [param:Float y], [param:Float z], [param:Float w] )</h3>
 		<p>设置该四元数的 [page:.x x]、[page:.y y]、[page:.z z]和[page:.w w]属性。</p>
 
@@ -205,44 +208,6 @@
 
 		<h2>静态方法</h2>
 
-		<p>
-			静态方法(相对于实例方法)被设计用来直接从类进行调用,而非从特定的实例上进行调用。
-			要使用静态版本,需要按照如下方式来调用:
-			<code>
-THREE.Quaternion.slerp( qStart, qEnd, qTarget, t );
-			</code>
-			作为对比,要调用“正常”或实例的 slerp 方法,则进行如下操作:
-			<code>
-//instantiate a quaternion with default values
-const q = new THREE.Quaternion();
-
-//call the instanced slerp method
-q.slerp( qb, t )
-			</code>
-
-		</p>
-
-		<h3>[method:Quaternion slerp]( [param:Quaternion qStart], [param:Quaternion qEnd], [param:Quaternion qTarget], [param:Float t] )</h3>
-		<p>
-			[page:Quaternion qStart] - The starting quaternion (where [page:Float t] is 0)<br />
-			[page:Quaternion qEnd] - The ending quaternion (where [page:Float t] is 1)<br />
-			[page:Quaternion qTarget] - The target quaternion that gets set with the result<br />
-			[page:Float t] - interpolation factor in the closed interval [0, 1].<br /><br />
-
-			Unlike the normal method, the static version of slerp sets a target quaternion to the result of the slerp operation.
-			<code>
-			// Code setup
-			const startQuaternion = new THREE.Quaternion().set( 0, 0, 0, 1 ).normalize();
-			const endQuaternion = new THREE.Quaternion().set( 1, 1, 1, 1 ).normalize();
-			let t = 0;
-
-			// Update a mesh's rotation in the loop
-			t = ( t + 0.01 ) % 1; // constant angular momentum
-			THREE.Quaternion.slerp( startQuaternion, endQuaternion, mesh.quaternion, t );
-			</code>
-		</p>
-
-
 		<h3>[method:null slerpFlat]( [param:Array dst], [param:Integer dstOffset], [param:Array src0], [param:Integer srcOffset0], [param:Array src1], [param:Integer srcOffset1], [param:Float t] )</h3>
 		<p>
 		[page:Array dst] - The output array.<br />

+ 14 - 0
docs/api/zh/math/Sphere.html

@@ -69,6 +69,13 @@
 		若这个点,则距离将为负值。
 		</p>
 
+		<h3>[method:this expandByPoint]( [param:Vector3 point] )</h3>
+		<p>
+		[page:Vector3 point] - [page:Vector3] that should be included in the sphere.<br /><br />
+
+		Expands the boundaries of this sphere to include [page:Vector3 point].
+		</p>
+
 		<h3>[method:Boolean isEmpty]()</h3>
 		<p>
 		检查球是否为空(the radius set to a negative number).
@@ -134,6 +141,13 @@
 		使用所给定[page:Vector3] offset(偏移量)平移球心。
 		</p>
 
+		<h3>[method:this union]( [param:Sphere sphere] )</h3>
+		<p>
+		[page:Sphere sphere] - Bounding sphere that will be unioned with this sphere.<br /><br />
+
+		Expands this sphere to enclose both the original sphere and the given sphere.
+		</p>
+
 		<h2>源代码</h2>
 
 		<p>

+ 0 - 15
docs/api/zh/renderers/WebGLRenderer.html

@@ -184,18 +184,6 @@
 		<h3>[property:Boolean localClippingEnabled]</h3>
 		<p>定义渲染器是否考虑对象级剪切平面。 默认为*false*.</p>
 
-		<h3>[property:Integer maxMorphTargets]</h3>
-		<p>
-		默认是8。 一个着色器中允许的最大MorphTargets数。
-		切记标准材质只允许8个MorphTargets。
-		</p>
-
-		<h3>[property:Integer maxMorphNormals]</h3>
-		<p>
-		默认是4。 色器中允许的最大MorphNormal数。
-		切记标准材质只允许4个MorphNormal。
-		</p>
-
 		<h3>[property:Boolean physicallyCorrectLights]</h3>
 		<p>
 		是否使用物理上正确的光照模式。 默认是*false*。
@@ -398,9 +386,6 @@
 		<h3>[method:null setClearColor]( [param:Color color], [param:Float alpha] )</h3>
 		<p>设置颜色及其透明度</p>
 
-		<h3>[method:null setFramebuffer]( [param:WebGLFramebuffer value] )</h3>
-		<p>Sets the given WebGLFramebuffer. This method can only be used if no render target is set via [page:WebGLRenderer.setRenderTarget .setRenderTarget]().</p>
-
 		<h3>[method:null setPixelRatio]( [param:number value] )</h3>
 		<p>设置设备像素比。通常用于避免HiDPI设备上绘图模糊</p>
 

+ 4 - 1
docs/api/zh/renderers/webgl/WebGLProgram.html

@@ -55,7 +55,10 @@
 		<h3>顶点着色器(有条件的):</h3>
 		<div>
 		<code>
-		#ifdef USE_COLOR
+		#if defined( USE_COLOR_ALPHA )
+			// vertex color attribute with alpha
+			attribute vec4 color;
+		#elif defined( USE_COLOR )
 			// vertex color attribute
 			attribute vec3 color;
 		#endif

+ 1 - 1
docs/api/zh/scenes/Scene.html

@@ -35,7 +35,7 @@
 		<p>
 		若不为空,在渲染场景的时候将设置背景,且背景总是首先被渲染的。
 		可以设置一个用于的“clear”的[page:Color](颜色)、一个覆盖canvas的[page:Texture](纹理),
-		或是 a cubemap as a [page:CubeTexture] or [page:WebGLCubeRenderTarget] or an equirectangular as a [page:Texture]。默认值为null。
+		或是 a cubemap as a [page:CubeTexture] or an equirectangular as a [page:Texture]。默认值为null。
 		</p>
 
 		<h3>[property:Texture environment]</h3>

+ 32 - 11
docs/api/zh/textures/Texture.html

@@ -137,21 +137,42 @@
 
 		<h3>[property:Vector2 offset]</h3>
 		<p>
-		纹理在单次重复时,从一开始将分别在U、V方向上偏移多少。
-		这个值的范围通常在*0.0*之间*1.0*。
-		请注意:这一属性是一个非常方便的修改器,仅仅影响纹理对模型上第一组UV的应用。
-		如果该纹理被用于需要额外的UV集的贴图(例如一些成品材质中的aoMap或lightMap),
-		这些UV必须被手动调整来实现所期望的偏移。
+		How much a single repetition of the texture is offset from the beginning, in each direction U and V.
+		Typical range is *0.0* to *1.0*.
+		</p>
+		<p>
+			The below texture types share the *first* uv channel in the engine. The offset (and repeat) setting is evaluated according to
+			the following priorities and then shared by those textures:
+			<ol>
+				<li>color map</li>
+				<li>specular map</li>
+				<li>displacement map</li>
+				<li>normal map</li>
+				<li>bump map</li>
+				<li>roughness map</li>
+				<li>metalness map</li>
+				<li>alpha map</li>
+				<li>emissive map</li>
+				<li>clearcoat map</li>
+				<li>clearcoat normal map</li>
+				<li>clearcoat roughnessMap map</li>
+			</ol>
+		</p>
+		<p>
+			The below texture types share the *second* uv channel in the engine. The offset (and repeat) setting is evaluated according to
+			the following priorities and then shared by those textures:
+			<ol>
+				<li>ao map</li>
+				<li>light map</li>
+			</ol>
 		</p>
 
 		<h3>[property:Vector2 repeat]</h3>
 		<p>
-		纹理将在表面上,分别在U、V方向重复多少次。如果这个值在任意方向上设置为大于1,
-		则对应的Wrap参数应当也被设为[page:Textures THREE.RepeatWrapping]或[page:Textures THREE.MirroredRepeatWrapping],
-		以实现所期望的平铺效果。
-		请注意:这一属性是一个非常方便的修改器,仅仅影响纹理对模型上第一组UV的应用。
-		如果该纹理被用于需要额外的UV集的贴图(例如一些成品材质中的aoMap或lightMap),
-		这些UV必须被手动调整来实现所期望的重复。
+		How many times the texture is repeated across the surface, in each direction U and V.  If repeat is set
+		greater than 1 in either direction, the corresponding Wrap parameter should also be set to
+		[page:Textures THREE.RepeatWrapping] or [page:Textures THREE.MirroredRepeatWrapping] to achieve the desired
+		tiling effect. Setting different repeat values for textures is restricted in the same way like [page:.offset].
 		</p>
 
 		<h3>[property:number rotation]</h3>

+ 6 - 1
docs/examples/en/animations/CCDIKSolver.html

@@ -92,7 +92,12 @@
 
 		<h3>[method:CCDIKSolver update]()</h3>
 		<p>
-		Update bones quaternion by solving CCD algorithm.
+		Update IK bones quaternion by solving CCD algorithm.
+		</p>
+
+		<h3>[method:CCDIKSolver updateOne]( [param:Object ikParam] )</h3>
+		<p>
+		Update an IK bone quaternion by solving CCD algorithm.
 		</p>
 
 		<h2>Source</h2>

+ 2 - 0
docs/examples/en/animations/MMDAnimationHelper.html

@@ -77,6 +77,8 @@
 			<li> [page:Boolean sync] - Whether animation durations of added objects are synched. Default is true.</li>
 			<li> [page:Number afterglow] - Default is 0.0.</li>
 			<li> [page:Boolean resetPhysicsOnLoop] - Default is true.</li>
+			<li> [page:Boolean pmxAnimation] - If it is set to true, the helper follows the complex and costly PMX animation system.
+			Try this option only if your PMX model animation doesn't work well. Default is false.</li>
 		</ul>
 		</p>
 		<p>

+ 5 - 6
docs/examples/en/controls/OrbitControls.html

@@ -143,13 +143,12 @@
 			This object contains references to the keycodes for controlling camera panning. Default is the 4 arrow keys.
 			<code>
 controls.keys = {
-	LEFT: 37, //left arrow
-	UP: 38, // up arrow
-	RIGHT: 39, // right arrow
-	BOTTOM: 40 // down arrow
+	LEFT: 'ArrowLeft', //left arrow
+	UP: 'ArrowUp', // up arrow
+	RIGHT: 'ArrowRight', // right arrow
+	BOTTOM: 'ArrowDown' // down arrow
 }
-			 </code> See [link:https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode this page] for a full
-			list of keycodes.
+			 </code> See [link:https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code KeyboardEvent.code] for a full list of keycodes.
 		</p>
 
 		<h3>[property:Float maxAzimuthAngle]</h3>

+ 1 - 1
docs/examples/en/controls/TrackballControls.html

@@ -80,7 +80,7 @@
 				<li>When the second defined key is pressed, all mouse interactions (left, middle, right) performs zooming.</li>
 				<li>When the third defined key is pressed, all mouse interactions (left, middle, right) performs panning.</li>
 			</ul>
-			Default is *65, 83, 68* which represents A, S, D.
+			Default is *KeyA, KeyS, KeyD* which represents A, S, D.
 		</p>
 
 		<h3>[property:Number maxDistance]</h3>

+ 0 - 4
docs/examples/en/helpers/RectAreaLightHelper.html

@@ -53,10 +53,6 @@
 		<h3>[method:null dispose]()</h3>
 		<p>Dispose of the rectAreaLightHelper.</p>
 
-		<h3>[method:null update]()</h3>
-		<p>Updates the helper to match the position and direction of the [page:.light].</p>
-
-
 		<h2>Source</h2>
 
 		<p>

+ 11 - 1
docs/examples/en/loaders/SVGLoader.html

@@ -41,7 +41,7 @@
 						depthWrite: false
 					} );
 
-					const shapes = path.toShapes( true );
+					const shapes = SVGLoader.createShapes( path );
 
 					for ( let j = 0; j < shapes.length; j ++ ) {
 
@@ -104,6 +104,16 @@
 		Begin loading from url and call onLoad with the response content.
 		</p>
 
+		<h2>Static Methods</h2>
+
+		<h3>[method:Array createShapes]( [param:ShapePath shape] )</h3>
+		<p>
+		[page:ShapePath shape] — A ShapePath from the array of [page:ShapePath], given as argument in the onLoad function for the load function of [page:SVGLoader].<br />
+		</p>
+		<p>
+		Returns one or more [page:Shape] objects created from the [param:ShapePath shape] provided as an argument in this function.
+		</p>
+
 		<h2>Source</h2>
 
 		<p>

+ 5 - 5
docs/examples/ko/controls/OrbitControls.html

@@ -138,13 +138,13 @@
 			해당 객체는 카메라 패닝을 제어하기위한 키 코드에 대한 참조를 포함합니다. 기본값은 4 개의 화살표 키입니다.
 			<code>
 controls.keys = {
-	LEFT: 37, // 왼쪽 화살표
-	UP: 38, // 위쪽 화살표
-	RIGHT: 39, // 오른쪽 화살표
-	BOTTOM: 40 // 아래쪽 화살표
+	LEFT: 'ArrowLeft', // 왼쪽 화살표
+	UP: 'ArrowUp', // 위쪽 화살표
+	RIGHT: 'ArrowRight', // 오른쪽 화살표
+	BOTTOM: 'ArrowDown' // 아래쪽 화살표
 }
 			 </code>
-			 전체 키코드 목록은 [link:https://developer.mozilla.org/ko/docs/Web/API/KeyboardEvent/keyCode this page] 를 참조하세요.
+			 전체 키코드 목록은 [link:https://developer.mozilla.org/ko/docs/Web/API/KeyboardEvent/code KeyboardEvent.code] 를 참조하세요.
 		</p>
 
 		<h3>[property:Float maxAzimuthAngle]</h3>

+ 1 - 1
docs/examples/ko/controls/TrackballControls.html

@@ -79,7 +79,7 @@
 				<li>두 번째로 정의 된 키를 누르면 모든 마우스 상호 작용 (왼쪽, 가운데, 오른쪽)이 확대 / 축소를 수행합니다.</li>
 				<li>세 번째로 정의 된 키를 누르면 모든 마우스 상호 작용 (왼쪽, 가운데, 오른쪽)이 패닝을 수행합니다.</li>
 			</ul>
-			기본값은 A, S, D를 나타내는 * 65, 83, 68 *입니다.
+			기본값은 A, S, D를 나타내는 *KeyA, KeyS, KeyD* 입니다.
 		</p>
 
 		<h3>[property:Number maxDistance]</h3>

+ 5 - 0
docs/examples/zh/animations/CCDIKSolver.html

@@ -95,6 +95,11 @@
 		Update bones quaternion by solving CCD algorithm.
 		</p>
 
+		<h3>[method:CCDIKSolver updateOne]( [param:Object ikParam] )</h3>
+		<p>
+		Update an IK bone quaternion by solving CCD algorithm.
+		</p>
+
 		<h2>Source</h2>
 
 		<p>

+ 2 - 0
docs/examples/zh/animations/MMDAnimationHelper.html

@@ -77,6 +77,8 @@
 			<li> [page:Boolean sync] - Whether animation durations of added objects are synched. Default is true.</li>
 			<li> [page:Number afterglow] - Default is 0.0.</li>
 			<li> [page:Boolean resetPhysicsOnLoop] - Default is true.</li>
+			<li> [page:Boolean pmxAnimation] - If it is set to true, the helper follows the complex and costly PMX animation system.
+			Try this option only if your PMX model animation doesn't work well. Default is false.</li>
 		</ul>
 		</p>
 		<p>

+ 5 - 5
docs/examples/zh/controls/OrbitControls.html

@@ -141,12 +141,12 @@
 			这一对象包含了用于控制相机平移的按键代码的引用。默认值为4个箭头(方向)键。
 			<code>
 controls.keys = {
-	LEFT: 37, //left arrow
-	UP: 38, // up arrow
-	RIGHT: 39, // right arrow
-	BOTTOM: 40 // down arrow
+	LEFT: 'ArrowLeft', //left arrow
+	UP: 'ArrowUp', // up arrow
+	RIGHT: 'ArrowRight', // right arrow
+	BOTTOM: 'ArrowDown' // down arrow
 }
-			 </code>请参阅[link:https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode this page]来查看所有按键的代码列表。
+			 </code> 请参阅[link:https://developer.mozilla.org/zh-CN/docs/Web/API/KeyboardEvent/code KeyboardEvent.code]来查看所有按键的代码列表。
 		</p>
 
 		<h3>[property:Float maxAzimuthAngle]</h3>

+ 2 - 2
docs/examples/zh/controls/TrackballControls.html

@@ -77,9 +77,9 @@
 			<ul>
 				<li>当定义的第一个按键按下后,所有的鼠标交互(左/中/右键)表现为环绕。</li>
 				<li>当定义的第二个按键按下后,所有的鼠标交互(左/中/右键)表现为缩放。</li>
-				<li>当定义的第个按键按下后,所有的鼠标交互(左/中/右键)表现为平移。</li>
+				<li>当定义的第个按键按下后,所有的鼠标交互(左/中/右键)表现为平移。</li>
 			</ul>
-			默认为*65, 83, 68*,分别表示A, S, D。
+			默认为*KeyA, KeyS, KeyD*,分别表示A, S, D。
 		</p>
 
 		<h3>[property:Number maxDistance]</h3>

+ 0 - 4
docs/examples/zh/helpers/RectAreaLightHelper.html

@@ -53,10 +53,6 @@
 		<h3>[method:null dispose]()</h3>
 		<p>销毁该区域光源辅助对象.</p>
 
-		<h3>[method:null update]()</h3>
-		<p>更新辅助对象,与 [page:.light] 属性的位置和方向保持一致.</p>
-
-
 		<h2>源码</h2>
 
 		<p>

+ 11 - 1
docs/examples/zh/loaders/SVGLoader.html

@@ -41,7 +41,7 @@
 						depthWrite: false
 					} );
 
-					const shapes = path.toShapes( true );
+					const shapes = SVGLoader.createShapes( path );
 
 					for ( let j = 0; j < shapes.length; j ++ ) {
 
@@ -104,6 +104,16 @@
 		Begin loading from url and call onLoad with the response content.
 		</p>
 
+		<h2>Static Methods</h2>
+
+		<h3>[method:Array createShapes]( [param:ShapePath shape] )</h3>
+		<p>
+		[page:ShapePath shape] — A ShapePath from the array of [page:ShapePath], given as argument in the onLoad function for the load function of [page:SVGLoader].<br />
+		</p>
+		<p>
+		Returns one or more [page:Shape] objects created from the [param:ShapePath shape] provided as an argument in this function.
+		</p>
+
 		<h2>Source</h2>
 
 		<p>

+ 2 - 1
docs/index.html

@@ -48,6 +48,7 @@
 						<option value="ar">ar</option>
 						<option value="ko">한국어</option>
 						<option value="zh">中文</option>
+						<option value="ja">日本語</option>
 					</select>
 				</div>
 				<div id="content"></div>
@@ -95,7 +96,7 @@
 
 			if ( /^(api|manual|examples)/.test( hash ) ) {
 
-				const hashLanguage = /^(api|manual|examples)\/(en|ar|ko|zh)\//.exec( hash );
+				const hashLanguage = /^(api|manual|examples)\/(en|ar|ko|zh|ja)\//.exec( hash );
 
 				if ( hashLanguage === null ) {
 

+ 30 - 1
docs/list.json

@@ -1043,6 +1043,35 @@
 
 		}
 
-	}
+	},
+
+    "ja": {
+        "マニュアル": {
+            "はじめてみましょう": {
+                "シーンの作成": "manual/ja/introduction/Creating-a-scene",
+                "インストールの方法": "manual/ja/introduction/Installation",
+                "サポートしているブラウザ": "manual/ja/introduction/Browser-support",
+                "WebGLの互換性の確認": "manual/ja/introduction/WebGL-compatibility-check",
+                "localで実行する方法": "manual/ja/introduction/How-to-run-things-locally",
+                "線を引く": "manual/ja/introduction/Drawing-lines",
+                "テキストを作成する": "manual/ja/introduction/Creating-text",
+                "3Dモデルをロードする": "manual/ja/introduction/Loading-3D-models",
+                "ライブラリとプラグイン": "manual/ja/introduction/Libraries-and-Plugins",
+                "FAQ": "manual/ja/introduction/FAQ",
+                "役にたつリンク集": "manual/ja/introduction/Useful-links"
+            },
+            "次の段階": {
+                "更新の仕方": "manual/ja/introduction/How-to-update-things",
+                "オブジェクトを廃棄する方法": "manual/ja/introduction/How-to-dispose-of-objects",
+                "VRコンテンツの作り方": "manual/ja/introduction/How-to-create-VR-content",
+                "post-processingの使い方": "manual/ja/introduction/How-to-use-post-processing",
+                "行列の変換": "manual/ja/introduction/Matrix-transformations",
+                "アニメーションシステム": "manual/ja/introduction/Animation-system"
+            },
+            "ビルドツール": {
+                "NPMでテストを実行する": "manual/ja/buildTools/Testing-with-NPM"
+            }
+        }
+    }
 
 }

+ 1 - 1
docs/manual/ar/introduction/FAQ.html

@@ -27,7 +27,7 @@
 
 				<p>[link:https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html Safari: Using the Viewport]</p>
 
-				<p>[link:https://developer.mozilla.org/en/Mobile/Viewport_meta_tag MDN: Using the viewport meta tag]</p>
+				<p>[link:https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag MDN: Using the viewport meta tag]</p>
 		</div>
 
 		<h2>كيف يمكن الحفاظ على مقياس المشهد عند تغيير الحجم؟</h2>

+ 1 - 1
docs/manual/en/introduction/FAQ.html

@@ -27,7 +27,7 @@
 
 				<p>[link:https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html Safari: Using the Viewport]</p>
 
-				<p>[link:https://developer.mozilla.org/en/Mobile/Viewport_meta_tag MDN: Using the viewport meta tag]</p>
+				<p>[link:https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag MDN: Using the viewport meta tag]</p>
 		</div>
 
 		<h2>How can scene scale be preserved on resize?</h2>

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

@@ -66,7 +66,7 @@
 	<p>
 		This question was asked many times by the community so it's important to clarify this matter. Fact is that *three.js* does not know the lifetime or scope
 		of user-created entities like geometries or materials. This is the responsibility of the application. For example even if a material is currently not used for rendering,
-		it might base necessary for the next frame. So if the application decides that a certain object can be deleted, it has to	notify the engine via calling the respective
+		it might be necessary for the next frame. So if the application decides that a certain object can be deleted, it has to	notify the engine via calling the respective
 		*dispose()* method.
 	</p>
 

+ 232 - 0
docs/manual/ja/buildTools/Testing-with-NPM.html

@@ -0,0 +1,232 @@
+<!DOCTYPE html>
+<html lang="ja">
+
+<head>
+    <meta charset="utf-8">
+    <base href="../../../" />
+    <script src="page.js"></script>
+    <link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+    <h1>[name]</h1>
+
+    <p class="desc">
+        この記事ではhtree.jsを[link:https://nodejs.org/en/ node.js]環境で実行する方法について説明します。 node環境で実行すると、自動テストを実行できるようになります。 テストはコマンドラインから実行可能で、[link:https://travis-ci.org/ Travis]のような自動のCIツールからも実行できます。
+    </p>
+
+    <h2>The short version(概略)</h2>
+
+    <p>
+        npmとnodeについて詳しい方は以下のコマンドを実行し
+        <code>
+				$ npm install three --save-dev
+			</code> それから以下のコードをテストに追加してください
+        <code>
+			const THREE = require('three');
+		</code>
+    </p>
+
+    <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>
+    <div>
+        <ol>
+            <li>
+                [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
+$ npm config set registry http://registry.npmjs.org/
+					</code>
+            </li>
+
+            <li>
+                新しいプロジェクトのディレクトリを作成します。
+                <code>
+						 $ mkdir test-example; cd test-example
+					</code>
+            </li>
+
+            <li>
+                npmに新しいプロジェクトfileを作成させます。
+                <code>
+					 $ npm init
+					</code> すべてのプロンプトでEnterを押すと全てデフォルトの設定になります。 こうすることでpackage.jsonが作成されます。
+            </li><br />
+
+            <li>
+                以下のようにしてテスト機能を起動してみてください
+                <code>
+$ npm test
+					</code> おそらくですが、これは失敗します。 package.jsonの中の、テスト用のスクリプトの定義はこのようになっています。
+                <code>
+						"test": "echo \"Error: no test specified\" && exit 1"
+					</code>
+            </li>
+
+        </ol>
+    </div>
+
+    <h2>Add mocha(mochaの追加)</h2>
+    <div>
+        [link:https://mochajs.org/ mocha]を使用していきます。
+
+        <ol>
+            <li>
+                以下のようにしてmochaをインストールします。
+                <code>
+$ npm install mocha --save-dev
+					</code> node_modulesディレクトリが作られていて、依存関係がそこに示されていることが分かるかと思います。 また、package.jsonが更新されていることも分かるでしょう。 devDependencies プロパティは、--save-dev の使用により追加・更新されます。
+            </li><br />
+
+            <li>
+                テストでmochaを使うためにpackage.jsonを編集してください。 これはtestが呼ばれた時に、mochaを実行して詳細をどこに報告するかを決めるためです。 デフォルトでは、testディレクトリにあるものはなんでも実行されます。(もしtestディレクトリがない場合npm ERRが発生する可能性があります。その場合はmkdir testを実行し、ディレクトリを作成してください)
+                <code>
+						"test": "mocha --reporter list"
+					</code>
+            </li>
+
+            <li>
+                以下のコマンドでテストをもう一度実行してみてください
+                <code>
+						$ npm test
+					</code> 今度はうまくいくはずです。0 passing (1ms)などと報告されるでしょう。
+            </li>
+
+        </ol>
+    </div>
+
+    <h2>three.jsを追加する</h2>
+    <div>
+        <ol>
+            <li>
+                three.jsを依存ファイルに加えましょう。
+                <code>
+$ npm install three --save-dev
+					</code>
+                <ul>
+                    <li>
+                        もし違うバージョンのthreeが必要な場合は次のコマンドを使ってください。
+                        <code>
+								$ npm show three versions
+							</code> こうすると使用可能なバージョンが分かります。npmに使用したいバージョンを伝えましょう。
+                        <code>
+ $ npm install [email protected] --save
+							</code> (この例では0.84.0をインストールしています)。--saveは、これをdevの依存関係ではなく、このプロジェクトの依存関係にします。詳しくは、ドキュメント([link:https://www.npmjs.org/doc/json.html here])をご覧ください。
+                    </li>
+                </ul>
+            </li>
+
+            <li>
+                Mochaはtestディレクトリの中でテストを探します。それではtestディレクトリを作成しましょう。
+                <code>
+					$ mkdir test
+					</code>
+            </li>
+
+            <li>
+                最終的には、実際に実行するJSのテストが必要です。 three.jsのオブジェクトが利用可能で動いていることを確かめるための簡単なテストを追加してみましょう。 以下のコードが書かれたtest/verify-three.jsを作成します。
+
+
+                <code>
+const THREE = require('three');
+const assert = require('assert');
+
+describe('The THREE object', function() {
+  it('should have a defined BasicShadowMap constant', function() {
+    assert.notEqual('undefined', THREE.BasicShadowMap);
+  }),
+
+  it('should be able to construct a Vector3 with default of x=0', function() {
+    const vec3 = new THREE.Vector3();
+    assert.equal(0, vec3.x);
+  })
+})
+</code>
+            </li>
+
+            <li>
+                最後に$npm testでもう一度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
+2 passing (8ms)
+				</code>
+            </li>
+        </ol>
+    </div>
+
+    <h2>自分のコードを追加する</h2>
+    <div>
+        3つのことをやる必要があります。
+
+        <ol>
+            <li>
+                自分のコードに期待される動作についてテストを書き、それをtest/の下に置いてください。 ここ([link:https://github.com/air/encounter/blob/master/test/Physics-test.js Here])に実際のプロジェクトの例を置いておきます。
+            </li>
+
+            <li>
+                nodejsが機能的なコードを見られるようにエクスポートして、requireと組み合わせて使用します。こちら([link:https://github.com/air/encounter/blob/master/js/Physics.js here])をご覧ください。
+            </li>
+
+            <li>
+                上記のサンプルコードでrequire('three')を行なったのと同じ方法で、 テストコードに、あなたが作成したコードをインポートする必要があります。
+            </li>
+        </ol>
+
+        <p>
+            2と3の項目は、コードの管理方法によって異なります。上記のPhysics.jsの例では、exportの部分は最後の方にあります。 module.exportsにオブジェクトを割り当てています。
+        </p>
+        <code>
+//=============================================================================
+// make available in nodejs
+//=============================================================================
+if (typeof exports !== 'undefined')
+{
+  module.exports = Physics;
+}
+			</code>
+    </div>
+
+    <h2>Dealing with dependencies(依存関係に対処する)</h2>
+    <div>
+        <p>
+            もしすでに、require.jsやborwserifyといった賢いツールを使っているようなら、この章は飛ばしてください。
+        </p>
+        <p>
+            three.jsのプロジェクトはブラウザで実行するのが一般的です。そのため、モジュールのロードはブラウザによって行われ、たくさんのscriptタグが実行されます。一つのファイルであれば依存関係の心配をする必要はありません。 しかしながら、nodejsでは他の全てのものと結びつけられているindex.htmlがないので、 明示的にそうする必要があります。
+        </p>
+        <p>
+            他のファイルに依存するモジュールをexportする場合、nodeにそのファイルをロードするように伝えなくてはなりません。 以下に1つのアプローチを示します。
+        </p>
+        <ol>
+            <li>
+                モジュールを始める時に、nodejs環境であるかを確かめます。
+            </li>
+            <li>
+                もしそうであれば、依存関係を明示的に宣言します。
+            </li>
+            <li>
+                もしnodejs環境でないならおそらくブラウザ環境ですので、特に他のことはしなくても良いです。
+            </li>
+        </ol>
+        Physics.jsからのサンプルコードを示しておきます。
+        <code>
+//=============================================================================
+// setup for server-side testing
+//=============================================================================
+if (typeof require === 'function') // test for nodejs environment
+{
+  const THREE = require('three');
+  const MY3 = require('./MY3.js');
+}
+			</code>
+    </div>
+
+</body>
+
+</html>

+ 116 - 0
docs/manual/ja/introduction/Animation-system.html

@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<html lang="ja">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../" />
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<h2>概要</h2>
+
+		<p class="desc">
+			three.jsのアニメーションシステムの中では、モデルの様々なプロパティをアニメーション化できます。
+			例えば、装飾を行なったモデル([page:SkinnedMesh skinned and rigged model])の骨格や、[page:Geometry.morphTargets morphTargets]、異なるマテリアルの要素(色、不透明度、有無)、可視性、変形などを操作できます。
+			アニメーションの要素は、フェードインやフェードアウト、クロスフェード、重ね合わせが可能です。
+			同一のオブジェクトであっても異なるものであっても、異なるアニメーションの比重やタイムスケールは独立して変更出来ます。また、同じオブジェクトでも、異なるオブジェクトでもアニメーションは同期出来ます。<br /><br />
+
+			これらを一つのシステムで達成するために、three.jsのアニメーションシステムは2015に完全に変更されました([link:https://github.com/mrdoob/three.js/issues/6881 link])。古い情報に気をつけてください!three.jsのアニメーションシステムは現在はUnityやUnreal Engine 4と似た設計になっています。このページではメインの要素と、それがどうやって動くのかを簡単に説明します。
+
+		</p>
+
+		<h3>Animation Clips</h3>
+
+		<p class="desc">
+			アニメーション付きの3Dオブジェクトをインポートすることに成功した場合(そのオブジェクトが骨格なのか、モーフターゲットなのか、はたまた両方なのかには関係なく)、レスポンスフィールドのうちの一つは"animations"という配列で、そのモデルの[page:AnimationClip AnimationClips]を含んでいるはずです(下記の利用可能なローダーを参照)。
+			アニメーション付きの3Dオブジェクトをインポートすることに成功する状況というのは、例えばBlenderから[link:https://github.com/KhronosGroup/glTF-Blender-IO glTF Blender exporter]でオブジェクトをエクスポートして、そのオブジェクトを[page:GLTFLoader]を使って、three.jsに読みこむ、といったことが挙げられます。<br /><br />
+
+			
+			*AnimationClip*は普通、オブジェクトの特定の動作のデータを持っています。
+			例えば、メッシュの場合、1つめのAnimationClipはウォークサイクルのためのもの、2つ目のAnimationClipはジャンプ用の、3つ目はサイドステップ用という風に動作のデータをAnimationClipに持たせています。
+
+		</p>
+
+		<h3>Keyframe Tracks</h3>
+
+		<p class="desc">
+
+			こういった*AnimationClip*の中では、アニメーションの要素のデータは別の[page:KeyframeTrack]に保存されています。キャラクターオブジェクトが骨格を持っていると仮定すると、あるキートラックフレームは腕の下の方の骨の、位置の時間変化のデータを保存し、別のキートラックは同じ骨の回転成分の動きのデータを保存し、また別のキートラックは他の骨の位置や回転、スケールの変化といったデータを保存します。AnimationClipは、このようなたくさんのトラックで構成できることがわかります。
+
+			モデルが[page:Geometry.morphTargets morph targets]を持っていると仮定すると(例えば、友好的な顔から怒った顔にモーフィングするような場合)、それぞれのトラックは特定のモーフィングターゲットの[page:Mesh.morphTargetInfluences influence]がclipのパフォーマンス中にどうやって変化するかについての情報を持っています。
+
+		</p>
+
+		<h3>Animation Mixer</h3>
+
+		<p class="desc">
+
+			保存されたデータは、アニメーションのベースを形成するだけで、実際のアニメーションの再生は[page:AnimationMixer]によってコントロールされます。AnimationMixerはアニメーションのプレイヤーであるだけでなく、本物のミキサーコンソールのようなハードウェアのシミレーションでもあります。これによって、複数のアニメーションを同時にコントロールして、ブレンドしたり、マージしたり出来ます。
+
+		</p>
+
+		<h3>Animation Actions</h3>
+
+		<p class="desc">
+
+			[page:AnimationAction AnimationActions]によってコントールできるので、*AnimationMixer*自体の(一般的な)メソッドやプロパティは少ないです。*AnimationAction*を設定することで、あるミキサー上での*AnimationClip*の再生や、一時停止、停止のタイミングであったり、clipをリピートする頻度やリピートの有無、フェードや時間変化の有無、クロスフェードやシンクロなどの補助的なことを設定することが出来ます。
+
+		</p>
+
+		<h3>Animation Object Groups</h3>
+
+		<p class="desc">
+
+			オブジェクトのグループに、アニメーションの状態を受け取らせたい場合は、[page:AnimationObjectGroup]が使えます。
+
+		</p>
+
+		<h3>サポートされているフォーマットとloader</h3>
+
+		<p class="desc">
+			全てのモデル形式がアニメーションを含んでいるわけではないことに注意してください(OBJは特に含まれていません)。
+			またthree.jsのloaderのうちのいくつかしか[page:AnimationClip AnimationClip]シーケンスをサポートしていないことにも注意してください。このアニメーションのタイプをサポートしているものがいくつかあります。
+		</p>
+
+			<ul>
+				<li>[page:ObjectLoader THREE.ObjectLoader]</li>
+				<li>THREE.BVHLoader</li>
+				<li>THREE.ColladaLoader</li>
+				<li>THREE.FBXLoader</li>
+				<li>[page:GLTFLoader THREE.GLTFLoader]</li>
+				<li>THREE.MMDLoader</li>
+			</ul>
+
+		<p class="desc">
+			3ds maxとMayaは今のところ、複数のアニメーション(同じタイムラインにないもの)を一つのファイルに直接エクスポートすることは出来ません
+		</p>
+
+		<h2>Example</h2>
+
+		<code>
+		let mesh;
+
+		// Create an AnimationMixer, and get the list of AnimationClip instances
+		const mixer = new THREE.AnimationMixer( mesh );
+		const clips = mesh.animations;
+
+		// Update the mixer on each frame
+		function update () {
+			mixer.update( deltaSeconds );
+		}
+
+		// Play a specific animation
+		const clip = THREE.AnimationClip.findByName( clips, 'dance' );
+		const action = mixer.clipAction( clip );
+		action.play();
+
+		// Play all animations
+		clips.forEach( function ( clip ) {
+			mixer.clipAction( clip ).play();
+		} );
+		</code>
+
+	</body>
+</html>

+ 125 - 0
docs/manual/ja/introduction/Browser-support.html

@@ -0,0 +1,125 @@
+<!DOCTYPE html>
+<html lang="ja">
+<head>
+	<meta charset="utf-8">
+	<base href="../../../" />
+	<script src="page.js"></script>
+	<link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+<body>
+	<h1>[name]</h1>
+
+	<h2>概要</h2>
+	<div>
+		<p>
+			モダンなブラウザ上であれば、Three.jsはWebGLを使ってsceneを描画出来ます。古いブラウザ(特にInternet Explore 10以下)では、他の[link:https://github.com/mrdoob/three.js/tree/master/examples/jsm/renderers renderers] (CSS2DRenderer, CSS3DRenderer, SVGRenderer)に後方互換する必要があるでしょう。さらに、特に [link:https://github.com/mrdoob/three.js/tree/master/examples /examples] フォルダのファイルを使用している場合は、いくつかのpolyfillを含める必要がある可能性があります。
+		</p>
+		<p>
+			注意事項: もし古いブラウザをサポートする必要がないなら、WebGLRenderer以外を使うことはおすすめしません。というのも、他のrendererは遅い上に、サポートしている機能が少ないからです。
+		</p>
+	</div>
+
+	<h2>WebGLをサポートしているブラウザ</h2>
+	<div>
+		<p>
+			Google Chrome 9以上、Firefox 4以上、Opera 15以上、Safari 5.1以上、Internet Explore 11以上、もしくはMicrosoft Edge。
+			どのブラウザがWebGLをサポートしているのかは[link:https://caniuse.com/#feat=webgl Can I use WebGL]を確認してください。
+		</p>
+	</div>
+
+	<h2>three.jsで使用されるJavaScriptの機能とWeb APIs</h2>
+	<div>
+		<p>
+			three.jsで使われる機能の中には追加のpolyfillsが必要になるものがあります。
+		</p>
+		<table>
+			<thead>
+				<tr>
+					<th>機能</th>
+					<th>スコープ</th>
+					<th>モジュール</th>
+				</tr>
+			</thead>
+			<tbody>
+				<tr>
+					<td>Typed Arrays</td>
+					<td>Source</td>
+					<td>BufferAttribute, BufferGeometry, etc.</td>
+				</tr>
+				<tr>
+					<td>Web Audio API</td>
+					<td>Source</td>
+					<td>Audio, AudioContext, AudioListener, etc.</td>
+				</tr>
+				<tr>
+					<td>WebXR Device API</td>
+					<td>Source</td>
+					<td>WebXRManager</td>
+				</tr>
+				<tr>
+					<td>Blob</td>
+					<td>Source</td>
+					<td>FileLoader, etc.</td>
+				</tr>
+				<tr>
+					<td>Promise</td>
+					<td>Examples</td>
+					<td>GLTFLoader, DRACOLoader, BasisTextureLoader, GLTFExporter, VRButton, ARButton, etc.</td>
+				</tr>
+				<tr>
+					<td>Fetch</td>
+					<td>Examples</td>
+					<td>ImageBitmapLoader, etc.</td>
+				</tr>
+				<tr>
+					<td>File API</td>
+					<td>Examples</td>
+					<td>GLTFExporter, etc.</td>
+				</tr>
+				<tr>
+					<td>URL API</td>
+					<td>Examples</td>
+					<td>GLTFLoader, etc.</td>
+				</tr>
+				<tr>
+					<td>Pointer Lock API</td>
+					<td>Examples</td>
+					<td>PointerLockControls</td>
+				</tr>
+			</tbody>
+		</table>
+	</div>
+
+	<h2>Polyfills</h2>
+	<div>
+		<p>
+			要件に応じてポリフィルをインポートするだけです。例えば、IE9の場合は少なくとも以下の機能を追加する必要があります。
+		</p>
+		<ul>
+			<li>Typed Arrays</li>
+			<li>Blob</li>
+		</ul>
+	</div>
+
+	<h3>おすすめのpolyfills</h3>
+	<div>
+		<ul>
+			<li>
+				[link:https://github.com/zloirock/core-js core-js]
+			</li>
+			<li>
+				[link:https://github.com/inexorabletash/polyfill/blob/master/typedarray.js typedarray.js]
+			</li>
+			<li>
+				[link:https://github.com/stefanpenner/es6-promise/ ES6-Promise]
+			</li>
+			<li>
+				[link:https://github.com/eligrey/Blob.js Blob.js]
+			</li>
+			<li>
+				[link:https://github.com/github/fetch fetch]
+			</li>
+		</ul>
+	</div>
+</body>
+</html>

+ 162 - 0
docs/manual/ja/introduction/Creating-a-scene.html

@@ -0,0 +1,162 @@
+<!DOCTYPE html>
+<html lang="ja">
+	<head>
+		<meta charset="utf-8">
+		<base href="../../../" />
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<p>このセクションでは、three.jsを簡単に紹介します。まず、回転するキューブを描画することから始めます。困った時には、ページの下にあるサンプルコードを参考にしてみてください。</p>
+
+		<h2>始める前に</h2>
+
+		<p>three.jsを使う前に、表示するための場所が必要です。以下のHTMLをPCのファイルに保存して、そのHTMLを保存したディレクトリにjs/ディレクトリを作成し[link:https://threejs.org/build/three.js three.js]のコピーを保存しておいてください。その後、保存したHTMLをブラウザで開いてください。</p>
+
+		<code>
+		&lt;!DOCTYPE html&gt;
+		&lt;html&gt;
+			&lt;head&gt;
+				&lt;meta charset="utf-8"&gt;
+				&lt;title&gt;My first three.js app&lt;/title&gt;
+				&lt;style&gt;
+					body { margin: 0; }
+				&lt;/style&gt;
+			&lt;/head&gt;
+			&lt;body&gt;
+				&lt;script src="js/three.js"&gt;&lt;/script&gt;
+				&lt;script&gt;
+					// Our Javascript will go here.
+				&lt;/script&gt;
+			&lt;/body&gt;
+		&lt;/html&gt;
+		</code>
+
+		<p>これで完了です。下のコードは全て空の&lt;script&gt;タグに挿入されます。</p>
+
+		<h2>シーンの作成</h2>
+
+		<p>実際にthree.jsで何かものを表示できるようにするには、scene、camera、rendererの3つが必要です。</p>
+
+		<code>
+		const scene = new THREE.Scene();
+		const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
+
+		const renderer = new THREE.WebGLRenderer();
+		renderer.setSize( window.innerWidth, window.innerHeight );
+		document.body.appendChild( renderer.domElement );
+		</code>
+
+		<p>この時点でscene、camera、rendererの設定が完了したことになります。</p>
+
+		<p>three.jsにはcameraには種類がありますが、今回は<strong>PerspectiveCamera</strong>を使ってみましょう。</p>
+
+		<p>最初の属性は、<strong>field of view</strong>です。FOV(field of view)は、任意の瞬間にディスプレイ上で見られるシーンの範囲で、単位は度数です。</p>
+
+		<p>2つ目は<strong>アスペクト比</strong>です。アスペクト比は要素の幅を高さで割ったもので、描画する際には、アスペクト比を使うことが多いと思います。そうしないと、ワイドスクリーンのテレビで古い映画を再生したときと同じようになってしまいます。</p>
+
+		<p>次の2つの属性は、<strong>near</strong>と<strong>far</strong>です。この二つの値を設定することで、<strong>far</strong>の値よりもカメラから離れたオブジェクトや<strong>near</strong>の値よりも近いオブジェクトはレンダリングされなくなります。今回はこのことを気にする必要はありませんが、より良いパフォーマンスを得るために、アプリで変更するということがあるかもしれません。</p>
+
+		<p>次はrendererです。ここでmagicが起きます。ここで使用しているWebGLRendererの他にも、three.jsにはいくつかの機能があり、古いブラウザを使用しているユーザーや、何らかの理由でWebGLをサポートしていないユーザーのための後方互換として使用されています。</p>
+
+		<p>rendererのインスタンスを作成することに加えて、アプリを描画するサイズを設定する必要があります。アプリで塗りつぶしたい領域の幅と高さを使用することをお勧めします(この場合、ブラウザウィンドウの幅と高さ)。パフォーマンスを重視するアプリの場合、<strong>setSize</strong>に<strong>window.innerWidth/2</strong>や<strong>window.innerHeight/2</strong>のような小さな値を与えることもできます。こうすることでアプリは半分のサイズでレンダリングされます。</p>
+
+		<p>アプリのサイズを維持しつつ、より低い解像度でレンダリングしたい場合は、<strong>updateStyle</strong> (3番目の引数)としてfalseを指定して <strong>setSize</strong> を呼び出すことで行うことができます。例えば、<strong>setSize(window.innerWidth/2, window.innerHeight/2, false)</strong>は、&lt;canvas&gt;の幅と高さが100%の場合、アプリを半分の解像度でレンダリングします。</p>
+
+		<p>最後に、HTMLドキュメントに <strong>renderer</strong> 要素を追加します。これは、rendererがシーンを表示するために使用する &lt;canvas&gt; 要素です。</p>
+
+		<p><em>"それはそれとして、冒頭で言っていたキューブはどこにあるの?"</em> いますぐ追加しましょう。</p>
+
+		<code>
+		const geometry = new THREE.BoxGeometry();
+		const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
+		const cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+
+		camera.position.z = 5;
+		</code>
+
+		<p>キューブを作成するには、<strong>BoxGeometry</strong>が必要です。これは、キューブのすべての点 (<strong>頂点</strong>) および塗りつぶし(<strong>面</strong>)を含むオブジェクトです。これについては、今後さらに詳しく説明していきます。</p>
+
+		<p>形状を表すジオメトリに加えて、色をつけるためのマテリアルが必要です。Three.jsにはいくつかのマテリアルが付属していますが、ここでは<strong>MeshBasicMaterial</strong>だけを使うことにします。すべてのマテリアルは、それらに適用されるプロパティのオブジェクトを取ります。物事を非常にシンプルに保つために、<strong>0x00ff00</strong>のcolor属性を与えるだけにします。これは、CSSやPhotoshopで色が動作するのと同じ方法で動作します(<strong>hex colors</strong>)。</p>
+
+		<p>3番目に必要なのは、<strong>メッシュ</strong>です。メッシュとは、ジオメトリを受け取り、それにマテリアルを適用するオブジェクトのことで、シーンに挿入して自由に動作させることができます。</p>
+
+		<p>デフォルトでは、<strong>scene.add()</strong> を呼び出すと、追加したものが座標 <strong>(0,0,0)</strong> に追加されます。これにより、カメラとキューブの両方が互いに内側になってしまいます。これを回避するために、カメラを少しずらします。</p>
+
+		<h2>sceneのレンダリング</h2>
+
+		<p>先ほど作成したHTMLファイルに上のコードをコピーしても何も表示されません。これは、実際にはまだ何も描画していないからです。そのためには、<strong>レンダリングまたはアニメーションループ</strong>と呼ばれるものが必要です。</p>
+
+		<code>
+		function animate() {
+			requestAnimationFrame( animate );
+			renderer.render( scene, camera );
+		}
+		animate();
+		</code>
+
+		<p>このコードでは、画面が更新されるたびにrendererがシーンを描画するループを作成しています(一般的な画面では、これは1秒間に60回を意味します)。ブラウザでゲームを書くのが初めての方は、<em>「なぜ setIntervalでやらないのか」</em>と言うかもしれません。おそらく最も重要なのは、ユーザーが別のブラウザタブに移動するときに一時停止し、貴重な処理能力とバッテリー寿命を無駄にしないことです。</p>
+
+		<h2>キューブのアニメーション</h2>
+
+		<p>始める前に作成したファイルに上記のコードをすべて挿入すると、緑色のボックスが表示されるはずです。これを回転させて少し面白くしてみましょう。</p>
+
+		<p><strong>animate</strong> 関数の中で<strong>renderer.render</strong> を呼び出している箇所のすぐ上に以下のコードを追加します。</p>
+
+		<code>
+		cube.rotation.x += 0.01;
+		cube.rotation.y += 0.01;
+		</code>
+
+		<p>これはフレームごとに実行され(通常は1秒間に60回)、キューブに素敵な回転アニメーションを与えます。基本的に、アプリの実行中に移動または変更したいものはすべて、アニメーションループを通過する必要があります。もちろん、そこから他の関数を呼び出すこともできます。</p>
+
+		<h2>成果</h2>
+		<p>おめでとうございます。これで初めてのthree.jsアプリが完成しました。簡単なことですが、誰でもはじめは初心者です。</p>
+
+		<p>今回使用したコードは[link:https://jsfiddle.net/mkba0ecu/ live example]にあり編集可能です。紹介したコードがどうやって動作するかをより理解するために、それを使って遊んでみてください。</p>
+
+		<code>
+		&lt;!DOCTYPE html&gt;
+		&lt;html&gt;
+			&lt;head&gt;
+				&lt;title&gt;My first three.js app&lt;/title&gt;
+				&lt;style&gt;
+					body { margin: 0; }
+				&lt;/style&gt;
+			&lt;/head&gt;
+			&lt;body&gt;
+				&lt;script src="js/three.js"&gt;&lt;/script&gt;
+				&lt;script&gt;
+					const scene = new THREE.Scene();
+					const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
+
+					const renderer = new THREE.WebGLRenderer();
+					renderer.setSize( window.innerWidth, window.innerHeight );
+					document.body.appendChild( renderer.domElement );
+
+					const geometry = new THREE.BoxGeometry();
+					const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
+					const cube = new THREE.Mesh( geometry, material );
+					scene.add( cube );
+
+					camera.position.z = 5;
+
+					const animate = function () {
+						requestAnimationFrame( animate );
+
+						cube.rotation.x += 0.01;
+						cube.rotation.y += 0.01;
+
+						renderer.render( scene, camera );
+					};
+
+					animate();
+				&lt;/script&gt;
+			&lt;/body&gt;
+		&lt;/html&gt;
+		</code>
+	</body>
+</html>

+ 108 - 0
docs/manual/ja/introduction/Creating-text.html

@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<html lang="ja">
+	<head>
+		<meta charset="utf-8">
+		<base href="../../../" />
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+		<div>
+			<p>
+				three.jsアプリケーションを作る上でテキストを使う必要がある場合がしばしばあります。それを実現する方法はいくつかあります。
+			</p>
+		</div>
+
+		<h2>1. DOM + CSS</h2>
+		<div>
+			<p>
+				HTMLを使用することは、一般的にテキストを追加する最も簡単で早い方法です。これは、three.jsにテキストを追加する際に主に使用されている方法です。
+			</p>
+			<p>以下のようにすることでコンテンツを追加できます。</p>
+			<code>&lt;div id="info"&gt;Description&lt;/div&gt;</code>
+
+			<p>
+				そして、three.jsをフルスクリーンで使用する場合は、CSSを使ってz-indexの絶対的な位置を他の要素よりも上にしておきましょう。
+			</p>
+
+			<code>
+#info {
+	position: absolute;
+	top: 10px;
+	width: 100%;
+	text-align: center;
+	z-index: 100;
+	display:block;
+}
+			</code>
+
+		</div>
+
+
+
+		<h2>2.テキストをcanvasに書いて、[page:Texture]として使用する</h2>
+		<div>
+			<p>three.jsのsceneで平面上にテキストを簡単に描きたい場合は、この方法を使用します。</p>
+		</div>
+
+
+		<h2>3.お気に入りの3Dアプリケーションでモデルを作成し、three.jsに書き出す</h2>
+		<div>
+			<p>他の3Dアプリケーションを使用して、three.jsにインポートしたい場合にこの方法を使用します。</p>
+		</div>
+
+
+
+		<h2>4. Procedural Text Geometry</h2>
+		<div>
+			<p>
+				純粋なTHREE.jsで作業したい場合や、手続き的に動的な3Dのテキストジオメトリを作成したい場合、メッシュで実現することが出来ます。そのメッシュのジオメトリはTHREE.TextGeometryインスタンスを使います。
+			</p>
+			<p>
+				<code>new THREE.TextGeometry( text, parameters );</code>
+			</p>
+			<p>
+				しかし、これを機能させるためには、TextGeometryのfontパラメータにTHREE.Fontのインスタンスを設定する必要があります。
+
+				これをどのように行うかについては [page:TextGeometry] ページを参照してください。また、受け入れ可能な各パラメータの説明、THREE.js ディストリビューションに付属する JSON フォントの一覧も参照してください。
+			</p>
+
+			<h3>Examples</h3>
+
+			<p>
+				[example:webgl_geometry_text WebGL / geometry / text]<br />
+				[example:webgl_shadowmap WebGL / shadowmap]
+			</p>
+
+			<p>
+				Typefaceがダウンしている場合や、そこにないフォントを使いたい場合は、以下のリンク先のチュートリアル(blender用のPythonスクリプトでテキストをThree.jsのJSON形式に書き出す)を参考にしてください。
+				[link:http://www.jaanga.com/2012/03/blender-to-threejs-create-3d-text-with.html]
+			</p>
+
+		</div>
+
+
+
+		<h2>5. Bitmap Fonts</h2>
+		<div>
+			<p>
+				BMFonts(ビットマップフォント)では、グリフを1つのBufferGeometryにバッチ処理することができます。BMFont レンダリングは、ワードラッピング、文字間隔、カーニング、標準的な導関数を持つ符号付き距離フィールド、マルチチャンネル符号付き距離フィールド、マルチテクスチャフォントなどをサポートしています。[link:https://github.com/Jam3/three-bmfont-text three-bmfont-text]を参照してください。
+			</p>
+			<p>
+				[link:https://github.com/etiennepinchon/aframe-fonts A-Frame Fonts]のようなプロジェクトではストックフォントが利用できますが、任意の .TTF フォントから独自のフォントを作成し、プロジェクトに必要な文字のみを含めるように最適化することもできます。
+			</p>
+			<p>
+				役に立つツール
+			</p>
+			<ul>
+				<li>[link:http://msdf-bmfont.donmccurdy.com/ msdf-bmfont-web] <i>(web-based)</i></li>
+				<li>[link:https://github.com/soimy/msdf-bmfont-xml msdf-bmfont-xml] <i>(commandline)</i></li>
+				<li>[link:https://github.com/libgdx/libgdx/wiki/Hiero hiero] <i>(desktop app)</i></li>
+			</ul>
+		</div>
+
+
+
+	</body>
+</html>

+ 70 - 0
docs/manual/ja/introduction/Drawing-lines.html

@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html lang="ja">
+	<head>
+		<meta charset="utf-8">
+		<base href="../../../" />
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+		<div>
+			<p>
+				ワイヤーフレームの[page:Mesh]ではなく、線や円が描きたいとします。
+				そのためには、[page:WebGLRenderer renderer]と[page:Scene scene]そしてcameraを設定する必要があります。(詳しくはシーンを作成するページを参照)
+			</p>
+
+			<p>これがその場合に使用するコードです。</p>
+			<code>
+const renderer = new THREE.WebGLRenderer();
+renderer.setSize( window.innerWidth, window.innerHeight );
+document.body.appendChild( renderer.domElement );
+
+const camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 500 );
+camera.position.set( 0, 0, 100 );
+camera.lookAt( 0, 0, 0 );
+
+const scene = new THREE.Scene();
+			</code>
+			<p>
+				次にやるべきことはマテリアルを定義することです。線を描くには、[page:LineBasicMaterial]か [page:LineDashedMaterial]を使う必要があります。
+			</p>
+			<code>
+//create a blue LineBasicMaterial
+const material = new THREE.LineBasicMaterial( { color: 0x0000ff } );
+			</code>
+
+			<p>
+				マテリアルの次は、複数の頂点を持つジオメトリを定義する必要があります。
+			</p>
+
+			<code>
+const points = [];
+points.push( new THREE.Vector3( - 10, 0, 0 ) );
+points.push( new THREE.Vector3( 0, 10, 0 ) );
+points.push( new THREE.Vector3( 10, 0, 0 ) );
+
+const geometry = new THREE.BufferGeometry().setFromPoints( points );
+			</code>
+
+			<p>
+				線は連続する頂点の組の間に引かれますが、最初の点と最後の点の間には引かれないことに注意してください(線は閉じません)
+			</p>
+
+			<p>
+				ここで、2つの線とマテリアルが1つがあるので、これを組み合わせて一つの線にすることができます。
+			</p>
+			<code>
+const line = new THREE.Line( geometry, material );
+			</code>
+			<p>あとはシーンに追加して[page:WebGLRenderer.render render]を呼び出すだけです。</p>
+
+			<code>
+scene.add( line );
+renderer.render( scene, camera );
+			</code>
+
+			<p>2本の青い線で出来た上向きの矢印が表示されているはずです</p>
+		</div>
+	</body>
+</html>

+ 59 - 0
docs/manual/ja/introduction/FAQ.html

@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html lang="ja">
+
+<head>
+    <meta charset="utf-8">
+    <base href="../../../" />
+    <script src="page.js"></script>
+    <link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+    <h1>[name]</h1>
+
+    <h2>
+        3Dモデルの形式はどれががおすすめでしょうか?
+    </h2>
+    <div>
+        <p>
+            アセットをimportしたり、exportしたりするのにおすすめなのは、glTF(GL Transmission Format)です。 その理由としてはglTFはランタイムでのアセットの配信に焦点を合わせているので、コンパクトに変換でき、ロードが早いからです。
+        </p>
+        <p>
+            three.jsはFBX、Collada、OBJなどの他の多くの一般的なフォーマットにも対応したローダーを提供しています。 それでも、プロジェクトでは常に最初にglTF ベースのワークフローの作成を試してください。詳細については、[link:#manual/introduction/Loading-3D-models Loading-3D-models]を参照してください。
+
+        </p>
+    </div>
+
+    <h2>なぜmetaタグのviewpointがexampleに入っているのですか?</h2>
+    <div>
+        <code>&lt;meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"&gt;</code>
+
+        <p>
+            これらのタグは、モバイルブラウザのビューポートのサイズとスケールを制御します(ページの内容が表示されているビューポートとは異なるサイズでレンダリングされる場合があります)。
+
+        </p>
+
+        <p>[link:https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html Safari: Using the Viewport]</p>
+
+        <p>[link:https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag MDN: Using the viewport meta tag]</p>
+    </div>
+
+    <h2>
+        リサイズをしたときに、シーンのスケールを保存しておくにはどうしたらよいですか?
+    </h2>
+    <p>
+        カメラからの距離に関係なく、ウィンドウのサイズを変更しても、すべてのオブジェクトが同じサイズで表示されるようにしたいです。この問題を解くための重要な方程式は、ある距離での可視高さの計算式です。
+
+        <code>
+visible_height = 2 * Math.tan( ( Math.PI / 180 ) * camera.fov / 2 ) * distance_from_camera;
+			</code> ウィンドウの高さを一定の割合で増加させると、すべての距離で同じ割合で表示される高さが増加することになります。これは、カメラの位置を変えてもできません。 その代わりに、カメラの視野を変更する必要があります。 具体例は[link:http://jsfiddle.net/Q4Jpu/ sample]を参照してください。
+    </p>
+
+    <h2>オブジェクトの一部が非表示になる原因はなんですか?</h2>
+    <p>
+        これはface cullingが原因かもしれません。Faceにはどちらの面かを決める向きがあります。 そして、cullingは通常の状況では裏面を削除します。 これが問題となって非表示になっているかどうかを確認するには、 マテリアルの面をTHREE.DoubleSideに変更してください。
+        <code>material.side = THREE.DoubleSide</code>
+    </p>
+</body>
+
+</html>

+ 76 - 0
docs/manual/ja/introduction/How-to-create-VR-content.html

@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html lang="ja">
+
+<head>
+	<meta charset="utf-8">
+	<base href="../../../" />
+	<script src="page.js"></script>
+	<link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+	<h1>[name]</h1>
+
+	<p>
+		このガイドでは、three.jsを使って作成したWebベースのVRアプリケーションの基本的なコンポーネントの概要を説明しています。
+	</p>
+
+	<h2>Workflow</h2>
+
+	<p>
+		はじめに、プロジェクトに[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/webxr/VRButton.js VRButton.js]を追加する必要があります。
+	</p>
+
+	<code>
+import { VRButton } from 'three/examples/jsm/webxr/VRButton.js';
+	</code>
+
+	<p>
+		*VRButton.createButton()* は2つの重要なことを行います。VR互換性であることを表すボタンを作成し、ユーザーがボタンをアクティブにするとVRセッションを開始します。この機能を追加するためには、次のコードをアプリに追加するだけで良いです。
+	</p>
+
+	<code>
+document.body.appendChild( VRButton.createButton( renderer ) );
+	</code>
+
+	<p>
+		次に *WebGLRenderer* インスタンスのXRレンダリングを有効にしてください。
+	</p>
+
+	<code>
+renderer.xr.enabled = true;
+	</code>
+
+	<p>
+		最後にアニメーションループを調整する必要があります。というのも、よく知られた *window.requestAnimationFrame()* 関数を使えないからです。VRプロジェクトのためには、[page:WebGLRenderer.setAnimationLoop setAnimationLoop]を使います。最低限必要なコードは以下のようになります。
+	</p>
+
+	<code>
+renderer.setAnimationLoop( function () {
+
+	renderer.render( scene, camera );
+
+} );
+	</code>
+
+	<h2>Next Steps</h2>
+
+	<p>
+		このワークフローを実際に見るために、公式のWebVRの例を見てみましょう。<br /><br />
+
+		[example:webxr_vr_ballshooter WebXR / VR / ballshooter]<br />
+		[example:webxr_vr_cubes WebXR / VR / cubes]<br />
+		[example:webxr_vr_dragging WebXR / VR / dragging]<br />
+		[example:webxr_vr_lorenzattractor WebXR / VR / lorenzattractor]<br />
+		[example:webxr_vr_paint WebXR / VR / paint]<br />
+		[example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]<br />
+		[example:webxr_vr_panorama WebXR / VR / panorama]<br />
+		[example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]<br />
+		[example:webxr_vr_sandbox WebXR / VR / sandbox]<br />
+		[example:webxr_vr_sculpt WebXR / VR / sculpt]<br />
+		[example:webxr_vr_video WebXR / VR / video]
+	</p>
+
+</body>
+
+</html>

+ 130 - 0
docs/manual/ja/introduction/How-to-dispose-of-objects.html

@@ -0,0 +1,130 @@
+<!DOCTYPE html>
+<html lang="ja">
+
+<head>
+	<meta charset="utf-8">
+	<base href="../../../" />
+	<script src="page.js"></script>
+	<link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+	<h1>[name]</h1>
+
+	<p>
+		アプリケーションのパフォーマンスを向上させ、メモリリークを回避するための重要なこととして、
+		未使用のライブラリエンティティの廃棄が挙げられます。
+		three.js型のインスタンスを作成すると、決まった量のメモリが割り当てられます。
+		しかし、*three.js*はジオメトリやマテリアルのような特定のオブジェクトのために、レンダリングに必要なバッファやshaderといったWebGL関連のエンティティを作成します。これらのオブジェクトは自動的に解放されるわけではありません。
+		その代わり、アプリケーションはこのようなリソースを解放するために特別なAPIを使用する必要があります。
+		このガイドでは、このAPIがどのように使用されるのか、また、このコンテキストではどのようなオブジェクトが関連しているのかについて簡単に説明します。
+	</p>
+
+	<h2>Geometries</h2>
+
+	<p>
+		ジオメトリは普通は、属性の集合として定義された頂点の情報を表します。
+		*three.js*は、内部にはそれぞれの属性に対して、[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLBuffer WebGLBuffer]型のオブジェクトを作成します。
+		これらのentityは[page:BufferGeometry.dispose]()が呼ばれた時にのみ削除されます。
+		もしアプリケーションの中で、あるジオメトリが使われなくなった場合は、関連したリソースを開放するためにこの方法を実行してください。
+	</p>
+
+	<h2>Materials</h2>
+
+	<p>
+		マテリアルは、オブジェクトをどのように描画するかを定義します。
+		*three.js*はマテリアルの定義情報をレンダリング用のシェーダプログラムを構築するために使います。
+		シェーダプログラムは対応するマテリアルを捨てることでのみ、削除することができます。
+		パフォーマンスのために、*three.js*は可能であればすでに存在するシェーダプログラムを再利用しようとします。
+		そのため、シェーダプログラムは、関連したマテリアルがすべて廃棄された場合のみ削除されます。
+		[page:Material.dispose]()を実行することで、マテリアルの削除を指示できます。
+	</p>
+
+	<h2>Textures</h2>
+
+	<p>
+		マテリアルの廃棄をしても、テクスチャには影響がありません。
+		一つのテクスチャが複数のマテリアルに同時に使用されることがあるので、
+		テクスチャとマテリアルは別々に制御されています。
+		テクスチャのインスタンスを作成すると、three.jsは内部に[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture]を作成します。
+		バッファと同様に、このオブジェクトは[page:Texture.dispose]()を呼ぶことでしか削除できません。
+	</p>
+
+	<h2>Render Targets</h2>
+
+	<p>
+		[page:WebGLRenderTarget]型のオブジェクトは、描画先をカスタム出来るように、
+		[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture]インスタンスだけでなく、[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLFramebuffer WebGLFramebuffer]と
+		[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderbuffer WebGLRenderbuffer]も確保します。
+		これらのオブジェクトは[page:WebGLRenderTarget.dispose]()を実行することで、解放されます。
+	</p>
+
+	<h2>Miscellaneous</h2>
+
+	<p>
+		exampleディレクトリには、コントロールや後処理用のパスクラスといったクラスがあります。
+		これらのクラスは内部のイベントリスナーや描画対象を取り除くための*dispose()*メソッドを提供します。
+		一般的には、APIやクラスのドキュメントで*dispose()*があるかどうか探すのがおすすめです。
+		*dispose()*メソッドが存在するなら、片付けの際に使うとよいでしょう。
+	</p>
+
+	<h2>FAQ</h2>
+
+	<h3>なぜthree.jsは自動的にオブジェクトを処分できないのですか?</h3>
+
+	<p>
+		この質問はコミュニティで何度も訊かれた質問なので、この問題についてはきちんと解説します。
+		実のところ、*three.js*はライフタイムや、ユーザが作成したジオメトリやマテリアルのようなエンティティのスコープの情報をもっていません。これはアプリケーション側に責任があります。例えば、マテリアルが今のところレンダリングのために使用されていなくとも、次のフレームでは必要になるかもしれません。そのため、アプリケーションが特定のオブジェクトを削除しても良いと判断した場合、対応する*dispose()*メソッドを呼ぶことで描画エンジンに対してそのことを知らせなくてはなりません。
+	</p>
+
+	<h3>シーンからmeshを取り除くとそのジオメトリとマテリアルも削除されますか?</h3>
+
+	<p>
+		いいえ。ジオメトリとマテリアルは*dispose()*で明示的に削除する必要があります。
+		メッシュのような3Dオブジェクト間でジオメトリとマテリアルは共有できることを覚えておいてください。
+	</p>
+
+	<h3>*three.js*でキャッシュされたオブジェクトの量について情報を知ることができますか?</h3>
+
+	<p>
+		はい。グラフィックボードのメモリとレンダリングプロセスの一連の統計情報で
+		レンダラの特別なプロパティである[page:WebGLRenderer.info]を評価することができます。
+		また、ほかにはテクスチャやジオメトリ、シェーダプログラムがどれくらい内部に保存されているかを知ることができます。
+		もし、アプリケーションにパフォーマンス上の問題があることに気づいた場合、簡単にメモリリークを見つけるために
+		このプロパティを調べてみることをおすすめします。
+	</p>
+
+	<h3>画像がまだロードされていない時に、テクスチャの*dispose()*を呼び出すとどうなりますか?</h3>
+
+	<p>
+		テクスチャの内部リソースは、イメージが完全に読み込まれた場合にのみ割り当てられます。
+		画像が読み込まれる前にテクスチャを破棄しても何も起こりません。
+		リソースが割り当てられていないので、クリーンアップの必要もありません。
+	</p>
+
+	<h3>dispose()を呼び出した後に、対象のオブジェクトを使用すると何が起きますか?</h3>
+
+	<p>
+		削除された内部のリソースは、エンジンによって再び作成されます。
+		そのため、ランタイムエラーは発生しませんが、シェーダプログラムのコンパイルが必要な場合には特に
+		現在のフレームでのパフォーマンスの低下が発生するかもしれません。
+
+	</p>
+
+	<h3>*three.js*のオブジェクトをどのように管理するべきでしょうか?いつオブジェクトを削除するべきでしょうか?</h3>
+
+	<p>
+		この問いに対する明確で一般的な答えはありません。いつ*dispose()*を呼ぶのが正しいのかは、ユースケースに大きく依存します。常にオブジェクトを削除する必要があるわけではないことは強調しておきます。そのよい例として、複数のレベルで構成されているゲームがあります。こういったアプリの場合、オブジェクトを削除するのに適しているのはレベルを切り替えるときです。
+		そうすることで、古いシーンを通じてオブジェクトに対して処理を適用し、古いマテリアルやジオメトリ、テクスチャを削除できます。前の章で言及したように、まだ使用中のオブジェクトを削除してもランタイムエラーは発生しません。最悪でも1フレーム分のパフォーマンス低下が発生するだけです。
+	</p>
+
+	<h2>Examples that demonstrate the usage of dispose()</h2>
+
+	<p>
+		[example:webgl_test_memory WebGL / test / memory]<br />
+		[example:webgl_test_memory2 WebGL / test / memory2]<br />
+	</p>
+
+</body>
+
+</html>

+ 149 - 0
docs/manual/ja/introduction/How-to-run-things-locally.html

@@ -0,0 +1,149 @@
+<!DOCTYPE html>
+<html lang="ja">
+
+<head>
+    <meta charset="utf-8">
+    <base href="../../../" />
+    <script src="page.js"></script>
+    <link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+    <h1>[name]</h1>
+    <p>
+        テクスチャを呼び出さずに、ジオメトリを使うだけならウェブページをファイルシステムからそのまま動かすことができます。ファイルマネージャのHTMLファイルをダブルクリックすると、ブラウザで動作するはずです。(ブラウザのアドレスバーには<em>file:///yourFile.html</em>と表示されているでしょう)
+    </p>
+
+    <h2>外部のファイルからコンテンツを読み込む</h2>
+    <div>
+        <p>
+            外部ファイルからテクスチャやモジュールを読み込む場合、ブラウザのセキュリティ制限によって、ファイルシステムからの読み込みは失敗します。
+        </p>
+
+        <p>これを解決するには2つの方法があります。</p>
+
+        <ol>
+            <li>
+                ブラウザのローカルファイルに対するセキュリティ設定を変更することです。これによって、<code>file:///yourFile.html</code>といったローカルのファイルにアクセスできるようになります。
+            </li>
+            <li>
+                もうひとつは、ローカルのサーバからファイルを起動することです。こうすることで、<code>http://localhost/yourFile.html</code>にアクセスできるようになります。
+            </li>
+        </ol>
+
+        <p>
+            1つ目の方法を使う場合、いつも使用しているブラウザを使用すると、自ら脆弱性を露呈させかねないことに注意してください。念のため、ローカル開発専用のブラウザプロファイル/ショートカットを分けて作成しておいた方が良いかもしれません。それぞれのオプションを順番に紹介します。
+        </p>
+    </div>
+
+
+    <h2>ローカルでサーバを動かす</h2>
+    <div>
+        <p>
+            ほとんどのプログラム言語は組み込みの簡単なHTTPサーバが使えます。こういった組み込みのサーバは、ApacheやNginxなどの本番用に使用されるサーバと比べると機能が少ないですが、three.jsを試してみるには十分な機能があります
+        </p>
+
+        <h3>コードエディタのプラグイン</h3>
+        <div>
+            <p>コードエディタの中には、オンデマンドでシンプルなサーバを起動するプラグインがありものがあります</p>
+            <ul>
+                <li>Visual Studio Codeの[link:https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer Live Server]</li>
+                <li>Atomの[link:https://atom.io/packages/atom-live-server Live Server]</li>
+            </ul>
+        </div>
+
+        <h3>Servez</h3>
+        <div>
+            <p>
+                [link:https://greggman.github.io/servez Servez]はGUI で操作できるシンプルなサーバです。
+            </p>
+        </div>
+
+        <h3>Node.js http-server</h3>
+        <div>
+            <p>Node.jsにはシンプルなHTTPサーバーパッケージがあります。インストールするには以下のコマンドを実行してください。</p>
+            <code>npm install http-server -g</code>
+
+            <p>ローカル環境で実行するには以下のようにしてください</p>
+            <code>http-server . -p 8000</code>
+        </div>
+
+        <h3>Python server</h3>
+        <div>
+            <p>
+                [link:http://python.org/ Python]がインストールされている場合、作業ディレクトリで以下のようにコマンドライン実行すれば、サーバを動かすことができます。
+            </p>
+            <code>
+//Python 2.x
+python -m SimpleHTTPServer
+
+//Python 3.x
+python -m http.server
+				</code>
+
+            <p>
+                このようにすることで、ローカルホストのカレントディレクトリから8000番ポートでファイルが提供されます。提供されるファイルを見るためには、ブラウザのアドレスバーに以下のように入力してください。
+            </p>
+
+            <code>http://localhost:8000/</code>
+        </div>
+
+        <h3>Ruby server</h3>
+        <div>
+            <p>Rubyがインストールされている環境の場合、代わりに以下のコマンドを実行することでサーバを動かすことができます。</p>
+            <code>
+ruby -r webrick -e "s = WEBrick::HTTPServer.new(:Port => 8000, :DocumentRoot => Dir.pwd); trap('INT') { s.shutdown }; s.start"
+				</code>
+        </div>
+
+        <h3>PHP server</h3>
+        <div>
+            <p>PHPにも組み込みのwebサーバがあるので、phpの5.4.0で以下のように実行してみてください</p>
+            <code>php -S localhost:8000</code>
+        </div>
+
+        <h3>Lighttpd</h3>
+        <div>
+            <p>
+                Lighttpd は非常に軽量な汎用ウェブサーバです。ここではOSXにHomeBrewでインストールする方法を説明します。ここで説明した他のサーバとは異なり、lighttpd は本格的な本番環境に対応したサーバです。
+            </p>
+
+            <ol>
+                <li>
+                    homebrewでLighttpdをインストールする
+                    <code>brew install lighttpd</code>
+                </li>
+                <li>
+                    ウェブサーバを動作させたいディレクトリにlighttpd.confという設定ファイルを作成します。 設定ファイルのサンプルはこちらにあります。: [link:http://redmine.lighttpd.net/projects/lighttpd/wiki/TutorialConfiguration TutorialConfiguration]
+                </li>
+                <li>
+                    設定ファイルでserver.document-rootを提供したいファイルが置いてあるディレクトリに変更してください
+                </li>
+                <li>
+                    Lighttpdは以下のコマンドで実行できます。
+                    <code>lighttpd -f lighttpd.conf</code>
+                </li>
+                <li>
+                    http://localhost:3000/ に移動すると、選択したディレクトリから静的ファイルを提供します。
+                </li>
+            </ol>
+        </div>
+        <h3>IIS</h3>
+        <div>
+            <p>
+                WebサーバにMicrosoft IISを使用している場合ロードする前に.fbx拡張子に関するMIMEタイプの設定を追加してください。
+            </p>
+            <code>File name extension: fbx        MIME Type: text/plain</code>
+            <p>
+                デフォルトではIISは.fbxや.objのファイルをダウンロードするのをブロックします。そのため、IISがそういったファイル(.fbxなど)をダウンロードできるように設定を変更する必要があります。
+
+            </p>
+        </div>
+        <p>
+            他のシンプルな方法はStack Overflowで議論されています: [link:http://stackoverflow.com/q/12905426/24874 Simple way]
+        </p>
+    </div>
+
+</body>
+
+</html>

+ 263 - 0
docs/manual/ja/introduction/How-to-update-things.html

@@ -0,0 +1,263 @@
+<!DOCTYPE html>
+<html lang="ja">
+
+<head>
+    <meta charset="utf-8">
+    <base href="../../../" />
+    <script src="page.js"></script>
+    <link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+    <h1>[name]</h1>
+    <div>
+        <p>
+            下記のコードのようにシーンに追加されたオブジェクトはデフォルトで自動的にマトリクスを更新します。
+        </p>
+        <code>
+const object = new THREE.Object3D();
+scene.add( object );
+			</code> もしくは、シーンに親オブジェクトが追加されると子オブジェクトも自動的に更新されます。
+        <code>
+const object1 = new THREE.Object3D();
+const object2 = new THREE.Object3D();
+
+object1.add( object2 );
+scene.add( object1 ); //object1 and object2 will automatically update their matrices
+			</code>
+    </div>
+
+    <p>
+        しかしながら、オブジェクトが静的なものであると分かっている場合は、自動更新を無効にして必要な時だけ、更新することが出来ます。
+    </p>
+
+    <code>
+object.matrixAutoUpdate  = false;
+object.updateMatrix();
+		</code>
+
+    <h2>BufferGeometry</h2>
+    <div>
+        <p>
+            BufferGeometriesは、情報(頂点の位置、面のインデックス、法線、色、UV、カスタム属性など)をバッファ、 つまり[link:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays Typed_arrays](型付の配列)に保存します。 このため、標準的なジオメトリよりも一般的に高速ですが、その反面、作業がやや難しくなっています。
+        </p>
+        <p>
+            BufferGeometriesの更新についてバッファのサイズを変更することができないということは理解しておく必要があります。(これは非常にコストがかかり、基本的には新しいジオメトリを作成するのと同じです)。しかし、バッファの内容を更新することはできます。
+
+        </p>
+        <p>
+            つまり、BufferGeometry の属性(例えば頂点の数など)が増加することがわかっている場合、 新たに作成される可能性のある頂点を保持するのに十分な大きさのバッファを事前に確保しておく必要があります。 もちろん、これはBufferGeometryの最大サイズが存在することになります。
+        </p>
+        <p>
+            ここでは、レンダリング時に拡張される線の例を使用します。 バッファに500頂点分のスペースを確保しますが、[page:BufferGeometry.drawRange]を使って最初は2つだけ描画します。
+        </p>
+        <code>
+const MAX_POINTS = 500;
+
+// geometry
+const geometry = new THREE.BufferGeometry();
+
+// attributes
+const positions = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point
+geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
+
+// draw range
+const drawCount = 2; // draw the first 2 points, only
+geometry.setDrawRange( 0, drawCount );
+
+// material
+const material = new THREE.LineBasicMaterial( { color: 0xff0000 } );
+
+// line
+const line = new THREE.Line( geometry,  material );
+scene.add( line );
+			</code>
+        <p>
+            次に以下のようにして、線上にランダムに点を追加してみましょう。
+        </p>
+        <code>
+const positions = line.geometry.attributes.position.array;
+
+let x, y, z, index;
+x = y = z = index = 0;
+
+for ( let i = 0, l = MAX_POINTS; i < l; i ++ ) {
+
+    positions[ index ++ ] = x;
+    positions[ index ++ ] = y;
+    positions[ index ++ ] = z;
+
+    x += ( Math.random() - 0.5 ) * 30;
+    y += ( Math.random() - 0.5 ) * 30;
+    z += ( Math.random() - 0.5 ) * 30;
+
+}
+			</code>
+        <p>
+            もし、最初の描画以降に<em>点の数</em>を変更したい場合は、以下のようにしてください。
+        </p>
+        <code>
+line.geometry.setDrawRange( 0, newValue );
+			</code>
+        <p>
+            最初の描画以降に位置データの値を変更したい場合は、needsUpdateをtrueにセットする必要があります。
+        </p>
+        <code>
+line.geometry.attributes.position.needsUpdate = true; // required after the first render
+			</code>
+
+        <p>
+            最初の描画以降に位置データの値を変更した場合は、frustum cullingやヘルパーといったエンジンの他の機能がちゃんと機能するようにboundingボリュームを再計算する必要があるかもしれません。
+        </p>
+        <code>
+line.geometry.computeBoundingBox();
+line.geometry.computeBoundingSphere();
+			</code>
+
+        <p>
+            [link:http://jsfiddle.net/w67tzfhx/ Here is a fiddle] showing an animated line which you can adapt to your use case. ここ([link:http://jsfiddle.net/w67tzfhx/ link])では、あなたのユースケースに合わせることができるアニメーションを表示しています。
+        </p>
+
+        <h3>Examples</h3>
+
+        <p>
+            [example:webgl_custom_attributes WebGL / custom / attributes]<br /> [example:webgl_buffergeometry_custom_attributes_particles WebGL / buffergeometry / custom / attributes / particles]
+        </p>
+
+    </div>
+
+    <h2>Geometry</h2>
+    <div>
+        <p>
+            下記に示してあるフラグはさまざまなジオメトリの要素の更新をコントロールします。 更新にはコストがかかるので、更新が必要な要素のみを、更新するように設定してください。 バッファが変化すると、自動的にこれらのフラグはflaseにリセットされます。 バッファを更新し続けたいのであれば、このフラグをtrueに設定し続ける必要があります。 これは[page:Geometry]にのみ適用されて、[page:BufferGeometry]には適用されないことに注意してください。
+        </p>
+        <code>
+const geometry = new THREE.Geometry();
+geometry.verticesNeedUpdate = true;
+geometry.elementsNeedUpdate = true;
+geometry.morphTargetsNeedUpdate = true;
+geometry.uvsNeedUpdate = true;
+geometry.normalsNeedUpdate = true;
+geometry.colorsNeedUpdate = true;
+geometry.tangentsNeedUpdate = true;
+			</code>
+
+        <p>
+            [link:https://github.com/mrdoob/three.js/releases/tag/r66 r66]以前のバージョンでは、メッシュは<em>dynamic</em>フラグを有効にする必要があります。これは内部で型付き配列を保持するために必要になります。
+        </p>
+
+        <code>
+// removed after r66
+geometry.dynamic = true;
+			</code>
+
+    </div>
+
+    <h2>Materials</h2>
+    <div>
+        <p>
+            ユニフォームの値(例えば、色やテクスチャや透明度)は自由に変更することが出来ます。 これらの値はフレームごとにシェーダに送られます。
+        </p>
+
+        <p>
+            GLstateに関連したパラメータ(depthTest, blending, polygonOffsetなど)もいつでも変更出来ます。
+        </p>
+
+        <p>
+            以下に示すパラメータはランタイム(マテリアルが一度描画された後)には簡単に変更ができません。
+        </p>
+        <ul>
+            <li>ユニフォームの種類や数</li>
+            <li>以下の要素の有無
+                <ul>
+                    <li>texture</li>
+                    <li>fog</li>
+                    <li>vertex colors</li>
+                    <li>skinning</li>
+                    <li>morphing</li>
+                    <li>shadow map</li>
+                    <li>alpha test</li>
+                </ul>
+            </li>
+        </ul>
+
+        <p>
+            これらの値を変更するのには新しいシェーダプログラムが必要です、そのためには以下のように設定してください。
+        </p>
+        <code>material.needsUpdate = true</code>
+
+        <p>
+            こうすることで、プログラムはとても遅くなり、フレームレートが不安定になるかもしれないことを覚えておいてください。(特にWindowsでは、シェーダのコンパイルがOpenGLよりもDirectXの方が遅いので、より顕著に現れる可能性があります)。
+        </p>
+
+        <p>
+            より滑らかな体験を提供するために、明るさ0の光や、白紙のテクスチャ、密度0の霧といった"ダミー"の値を使うことで、これらの変化をある程度模倣することができます。
+        </p>
+
+        <p>
+            ジオメトリチャンクに使用するマテリアルは自由に変更できますが、オブジェクトをチャンクに分割する方法は変更できません。オブジェクトをどのようにチャンクに分割するからは、表面のマテリアルによって決まります。
+        </p>
+
+        <h3>
+            ランタイムに異なるマテリアルの設定が必要な場合
+        </h3>
+        <p>
+            マテリアル/チャンクの数が少ない場合は、あらかじめオブジェクトを分割しておくことができます(例:人間の場合は髪/顔/胴体/上着/ズボン、車の場合はフロント/サイド/トップ/ガラス/タイヤ/内装)。
+
+
+        </p>
+
+        <p>
+            数が多い場合(例えば、人の顔はそれぞれ違っている可能性があります)は、顔ごとに異なる外観にするために属性/テクスチャを使用するなど、別の解決策を検討してください。
+        </p>
+
+        <h3>Examples</h3>
+        <p>
+            [example:webgl_materials_car WebGL / materials / car]<br /> [example:webgl_postprocessing_dof WebGL / webgl_postprocessing / dof]
+        </p>
+    </div>
+
+
+    <h2>Textures</h2>
+    <div>
+        <p>
+            画像やcanvas、ビデオやデータのテクスチャが変化する場合は、以下のフラグを有効にする必要があります。
+        </p>
+        <code>
+				texture.needsUpdate = true;
+			</code>
+        <p>描画の対象が自動的に更新されます。</p>
+
+        <h3>Examples</h3>
+        <p>
+            [example:webgl_materials_video WebGL / materials / video]<br /> [example:webgl_rtt WebGL / rtt]
+        </p>
+
+    </div>
+
+
+    <h2>Cameras</h2>
+    <div>
+        <p>カメラの位置とターゲットは自動的に更新されます。以下の要素を変更する必要がある場合、projection matrixを再計算する必要があります。</p>
+        <ul>
+            <li>
+                fov
+            </li>
+            <li>
+                aspect
+            </li>
+            <li>
+                near
+            </li>
+            <li>
+                far
+            </li>
+        </ul>
+        <code>
+camera.aspect = window.innerWidth / window.innerHeight;
+camera.updateProjectionMatrix();
+			</code>
+    </div>
+</body>
+
+</html>

+ 115 - 0
docs/manual/ja/introduction/How-to-use-post-processing.html

@@ -0,0 +1,115 @@
+<!DOCTYPE html>
+<html lang="ja">
+
+<head>
+	<meta charset="utf-8">
+	<base href="../../../" />
+	<script src="page.js"></script>
+	<link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+	<h1>How to use post-processing(後処理の使い方)</h1>
+
+	<p>
+		three.jsアプリケーションの多くは3Dオブジェクトをスクリーンに直接描画します。
+		しかしながら時々、一つ以上のエフェクト(被写界深度、Bloom、フィルムグレイン、様々なアンチエイリアス効果など)を適用したい場合があります。こういったエフェクトを実装するためにpost-processingは広く使用されています。
+		まず、シーンはビデオカードメモリのバッファを表す描画対象に対して描画されます。
+		次に、最終的なスクリーンへのレンダリングの前に、1つ以上のpost-processingで画像バッファにフィルタとエフェクトを適用します。
+	</p>
+	<p>
+		こういったワークフローを実装するために、three.jsは[page:EffectComposer]で完全なpost-processingを提供しています。
+	</p>
+
+	<h2>Workflow</h2>
+
+	<p>
+		プロセスの一段階目はexampleディレクトリから必要なファイルを全てimportすることです。
+		このガイドではthree.jsの[link:https://www.npmjs.com/package/three npm package](npmの公式のパッケージ)を使っていると想定しています。
+		このガイドのデモでは下に示したファイルが必要です。
+	</p>
+
+	<code>
+		import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
+		import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
+		import { GlitchPass } from 'three/examples/jsm/postprocessing/GlitchPass.js';
+		</code>
+
+	<p>
+		全てのファイルのimportが成功したのちに、[page:WebGLRenderer]のインスタンスを渡すことでcomposerを作成します。
+	</p>
+
+	<code>
+		const composer = new EffectComposer( renderer );
+		</code>
+
+	<p>
+		composerを使うときにはアプリケーションのアニメーションループを変更する必要があります。
+		[page:WebGLRenderer]のrenderメソッドを呼ぶ代わりに[page:EffectComposer]のそれぞれの対応するものを使います。
+	</p>
+
+	<code>
+		function animate() {
+
+			requestAnimationFrame( animate );
+
+			composer.render();
+
+		}
+		</code>
+
+	<p>
+		composerが準備できたので、post-processingパスのチェーンを設定できるようになりました。
+		これらのパスはアプリケーションの最終的なビジュアルを出力することに責任を持ちます。
+		これらのパスは追加/挿入の順番で処理されます。今回示している例では、*RenderPass*インスタンスがはじめに実行され、
+		それから*GlitchPass*インスタンスが実行されます。チェーンの中で最後の有効なpassが自動的に画面に描画されます。
+		passの設定は以下のように行います。
+	</p>
+
+	<code>
+		const renderPass = new RenderPass( scene, camera );
+		composer.addPass( renderPass );
+
+		const glitchPass = new GlitchPass();
+		composer.addPass( glitchPass );
+		</code>
+
+	<p>
+		*RenderPass*は普通チェインのはじめにあります。
+		これはレンダリングされたシーンを次のpost-processingの入力とするためです。
+		*GlitchPass*は、これらのイメージをワイルドなglitch effectを適用するために使います。
+		実際に動いているものを見るために、[link:https://threejs.org/examples/webgl_postprocessing_glitch sample]を見てみましょう。
+	</p>
+
+	<h2>Built-in Passes(組み込みのpass)</h2>
+
+	<p>
+		エンジンに元から入っている定義済みの後処理passが使えます。
+		このpassは[link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm/postprocessing postprocessing]ディレクトリに入っていて、広範囲に使用できます。
+	</p>
+
+	<h2>Custom Passes(カスタムpass)</h2>
+
+	<p>
+		独自のpostprocessing shaderを書いて、post-processing passのチェーンの中に組み込みたい場合があります。そういった場合には、*ShaderPass*を利用することが出来ます。
+		ファイルと独自のshaderをインポートしたのちに、以下のコードでpassを設定することができます。
+	</p>
+
+	<code>
+		import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
+		import { LuminosityShader } from 'three/examples/jsm/shaders/LuminosityShader.js';
+
+		// later in your init routine
+
+		const luminosityPass = new ShaderPass( LuminosityShader );
+		composer.addPass( luminosityPass );
+		</code>
+
+	<p>
+		リポジトリには[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/shaders/CopyShader.js CopyShader]と呼ばれるファイルがあり、カスタムshaderを作る上での良いスタートコードです。
+		*CopyShader*はエフェクトを適用せずに、EffectComposerの読み込みバッファの画像内容を書き込みバッファにコピーするだけです。
+	</p>
+
+</body>
+
+</html>

+ 162 - 0
docs/manual/ja/introduction/Installation.html

@@ -0,0 +1,162 @@
+<!DOCTYPE html>
+<html lang="ja">
+
+<head>
+    <meta charset="utf-8">
+    <base href="../../../" />
+    <script src="page.js"></script>
+    <link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+    <h1>[name]</h1>
+
+    <p>
+        [link:https://www.npmjs.com/ npm]を使ってthree.jsとモダンなビルドツールをインストール出来ます。もしくは、静的ホスティングやCDNを使って素早く使い始めることも可能です。ほとんどの人にとっては、npmを使ってインストールするのが良いでしょう。
+    </p>
+
+    <p>
+        どちらの方法を選ぶにしても、一貫して同じバージョンのライブラリからファイルをimportしてください。異なるソースのファイルを混ぜるとコードが重複するかもしれませんし、予想外の方法でアプリケーションが壊れるかもしれません。
+    </p>
+
+    <p>
+        three.jsをインストール方法は、ES modules依存です([link:https://eloquentjavascript.net/10_modules.html#h_hF2FmOVxw7 Eloquent JavaScript: ECMAScript Modules]を参照)。そのおかげで、最新版のプロジェクトのライブラリの必要な部分だけを取り込むことができます。
+    </p>
+
+    <h2>npmでインストールする</h2>
+
+    <p>
+        [link:https://www.npmjs.com/package/three there] npm moduleをインストールするために, プロジェクトのフォルダでターミナルを開いて以下のコードを実行してください。
+    </p>
+
+    <code>
+		npm install --save three
+		</code>
+
+    <p>
+        パッケージがダウンロードされて、インストールされます。これで、three.jsをコードの中で使う準備が完了しました。
+    </p>
+
+    <code>
+		// Option 1: Import the entire three.js core library.
+		import * as THREE from 'three';
+
+		const scene = new THREE.Scene();
+
+
+		// Option 2: Import just the parts you need.
+		import { Scene } from 'three';
+
+		const scene = new Scene();
+		</code>
+
+    <p>
+        npmからインストールする際に、プロジェクトで必要なパッケージを一つのJavaScriptのファイルにまとめるために、ビルドツールを使うことがあるでしょう。ほとんどのモダンなJavaScriptのビルダーでthree.jsは使えますが、最も人気なのは[link:https://webpack.js.org/ webpack]です。
+    </p>
+
+    <p>
+        すべての機能が <em>three</em> モジュールから直接アクセスできるわけではありません(直接アクセスすることを「ベアインポート」とも呼びます)。コントロール、ローダー、エフェクトの前処理など、ライブラリの他の一般的な部分はサプフォルダ[link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm examples/jsm]からインポートしなければなりません。詳細については、以下の<em>Examples</em>を参照してください。
+    </p>
+
+    <p>
+        [link:https://eloquentjavascript.net/20_node.html#h_J6hW/SmL/a Eloquent JavaScript: Installing with npm]でnpm moduleについて詳しく学習する。
+    </p>
+
+    <h2>CDNや静的ホスティングからインストールをする</h2>
+
+    <p>
+        three.jsは、自分の Web サーバーにファイルをアップロードするか、既存の CDN を利用することで、ビルドシステムなしで利用することができます。ライブラリはES moduleに依存しているため、ライブラリを参照するスクリプトは以下のように<em>type="module"</em>を使用する必要があります。
+    </p>
+
+    <code>
+		&lt;script type="module">
+
+		  // Find the latest version by visiting https://unpkg.com/three. The URL will
+		  // redirect to the newest stable release.
+		  import * as THREE from 'https://unpkg.com/three/build/three.module.js';
+
+		  const scene = new THREE.Scene();
+
+		&lt;/script>
+		</code>
+
+    <p>
+        すべての機能が <em>build/three.module.js</em> モジュールからアクセスできるわけではありません。コントロール、ローダー、エフェクトの前処理など、ライブラリの他の一般的な部分は、[link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm examples/jsm] サブフォルダからインポートする必要があります。詳細については、以下の<em>Examples</em>を参照してください。
+    </p>
+
+
+    <h2>Examples</h2>
+
+    <p>
+        three.jsのコアは、3Dエンジンの最も重要なコンポーネントに焦点を当てています。コントロール、ローダー、エフェクトの前処理といった、他の多くの便利なコンポーネントは [link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm examples/jsm] ディレクトリの一部です。これらは「examples」と呼ばれています。その理由としては、ユーザーが既製品を使用でき、リミックスやカスタマイズも可能だからです。これらのコンポーネントは常にコアライブラリと同期していますが、npm上の同様のサードパーティ製パッケージは別の人によってメンテナンスされており、最新ではないかもしれません。
+    </p>
+
+    <p>
+        Examplesはそれだけ別でインストールする必要はありませんが、importは分けて行う必要があります。 three.jsをnpmでインストールしている場合、以下のようにして[page:OrbitControls]コンポーネントを読み込むことができます。
+    </p>
+
+
+    <code>
+		import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
+
+		const controls = new OrbitControls();
+		</code>
+
+    <p>
+        three.jsをCDNを使用してインストールしている場合は、同じCDNを使用して他のコンポートをインストールしてください。
+    </p>
+
+    <code>
+		&lt;script type="module">
+
+		  // Find the latest version by visiting https://unpkg.com/three. The URL will
+		  // redirect to the newest stable release.
+		  import { OrbitControls } from 'https://unpkg.com/three/examples/jsm/controls/OrbitControls.js';
+
+		  const controls = new OrbitControls();
+
+		&lt;/script>
+		</code>
+
+    <p>
+        重要なのは、すべてのファイルで同じバージョンを使用することです。異なるバージョンの異なるExamplesをインポートしたり、three.jsライブラリ自体とは異なるバージョンのExamplesを使用したりしないでください。
+    </p>
+
+    <h2>互換性について</h2>
+
+    <h3>CommonJSでのimport</h3>
+
+    <p>
+        最近のJavaScriptバンドラーはデフォルトでESモジュールをサポートしていますが、古いビルドツールの中にはサポートしていないものもあります。そのような場合は,バンドラーがESモジュールのことがわかるように設定することができます。例えば [link:http://browserify.org/ Browserify]では[link:https://github.com/babel/babelify babelify] プラグインが必要です。
+    </p>
+
+    <h3>Import maps</h3>
+
+    <p>
+        npmからインストールする時と、静的ホスティングやCDN からインストールする時とでは、インポートに使用するパスが異なります。これは、両方のグループのユーザーが、どういったものを使いやすいと感じるかが異なるために起こります。ビルドツールやバンドルを使用している開発者は、相対パスよりも裸のパッケージ指定子(例えば、'three')を好み、<em>examples/</em> フォルダ内のファイルは、この形式に従わない <em>three.module.js</em> への相対参照を使用しています。ビルドツールを使用しない人(高速プロトタイピング、学習、個人的な好みなど)は、同様に、特定のフォルダ構造を必要とし、グローバルな<em>three.*</em>名前空間よりも厳密な相対インポートを嫌うかもしれません。
+    </p>
+
+    <p>
+        [link:https://github.com/WICG/import-maps import maps] が広く利用できるようになったら、これらの相対パスを削除して、npm パッケージ名の 'three' への裸のパッケージ指定子に置き換えたいと考えています。これにより、ビルドツールが期待するnpmパッケージとより密接にマッチし、ファイルをインポートする際に両グループのユーザが全く同じコードを書くことができるようになります。ビルドツールを避けたいユーザーのために、シンプルなJSONマッピングですべてのインポートをCDNや静的ファイルフォルダに向けることができます。試しに、私たちの
+        [link:https://glitch.com/edit/#!/three-import-map?path=index.html import map example] で示されているように、import mapsのPolyfillを使って、今日はよりシンプルなインポートを使ってみることができます。
+    </p>
+
+    <h3>Node.js</h3>
+
+    <p>
+        以下の2つの理由からnode.jsでthree.jsを使用するのは難しくなりがちです。
+    </p>
+
+    <p>
+        まず、three.jsはWeb用に作られているので、Node.jsには必ずしも存在しないブラウザやDOM APIに依存します。これらの問題のいくつかは、[link:https://github.com/stackgl/headless-gl headless-gl] のような補正ツールを使用したり、[page:TextureLoader] のようなコンポーネントをカスタムの代替品で置き換えることで解決できます。他の DOM APIは、それらを使用するコードと深く絡み合っている可能性があり、回避するのが難しくなります。Node.js
+        のサポートを改善するためのシンプルで保守性の高いプルリクエストを歓迎しますが、まず問題を開いて改善点を議論することをお勧めします。
+    </p>
+
+    <p>
+        第二に、Node.jsによるESモジュールのサポートは...複雑です。Node.js v12の時点では、three.jsのコアライブラリは<em>require('three')</em>でCommonJSモジュールとしてインポートすることができます。しかし、<em>examples/jsm</em>にあるほとんどのサンプルコンポーネントはインポートできません。Node.jsの将来のバージョンで解決されるかもしれませんが、それまでの間は、[link:https://github.com/standard-things/esm
+        esm]のような回避策を使用して、Node.jsアプリケーションがESモジュールを認識できるようにする必要があるでしょう。
+    </p>
+
+</body>
+
+</html>

+ 96 - 0
docs/manual/ja/introduction/Libraries-and-Plugins.html

@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html lang="ja">
+
+<head>
+    <meta charset="utf-8" />
+    <base href="../../../" />
+    <script src="page.js"></script>
+    <link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+    <h1>[name]</h1>
+
+    <p class="desc">
+        外部で開発された互換性のあるthree.jsのライブラリやプラグインをここでリストアップしています。 このリストと関連したパッケージはコミュニティによってメンテナンスされており、最新である保証はありません。 もしこのリストを更新したい場合はPullRequestを送ってください!
+    </p>
+
+    <h3>Physics(物理)</h3>
+
+    <ul>
+        <li>[link:https://github.com/lo-th/Oimo.js/ Oimo.js]</li>
+        <li>[link:https://enable3d.io/ enable3d]</li>
+        <li>[link:https://github.com/kripken/ammo.js/ ammo.js]</li>
+        <li>[link:https://github.com/pmndrs/cannon-es cannon-es]</li>
+    </ul>
+
+    <h3>Postprocessing(後処理)</h3>
+
+    <p>
+        [link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm/postprocessing official three.js postprocessing effects]に加えて、外部のライブラリを通して、追加のエフェクトやフレームワークのサポートが利用可能です。
+
+
+    </p>
+
+    <ul>
+        <li>[link:https://github.com/vanruesc/postprocessing postprocessing]</li>
+    </ul>
+
+    <h3>Intersection and Raycasting Performance</h3>
+
+    <ul>
+        <li>[link:https://github.com/gkjohnson/three-mesh-bvh three-mesh-bvh]</li>
+    </ul>
+
+    <h3>File Formats(ファイル形式)</h3>
+
+    <p>
+        [link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm/loaders official three.js loaders]に加えて、外部のライブラリを通して、追加のフォーマットのサポートが利用できます。
+    </p>
+
+    <ul>
+        <li>[link:https://github.com/gkjohnson/urdf-loaders/tree/master/javascript urdf-loader]</li>
+        <li>[link:https://github.com/NASA-AMMOS/3DTilesRendererJS 3d-tiles-renderer-js]</li>
+        <li>[link:https://github.com/kaisalmen/WWOBJLoader WebWorker OBJLoader]</li>
+        <li>[link:https://github.com/agviegas/IFC.js IFC.js]</li>
+    </ul>
+
+    <h3>3D Text and Layout</h3>
+
+    <ul>
+        <li>[link:https://github.com/protectwise/troika/tree/master/packages/troika-three-text troika-three-text]</li>
+        <li>[link:https://github.com/felixmariotto/three-mesh-ui three-mesh-ui]</li>
+    </ul>
+
+    <h3>Particle Systems</h3>
+
+    <ul>
+        <li>[link:https://github.com/creativelifeform/three-nebula three-nebula]</li>
+    </ul>
+
+
+    <h3>Inverse Kinematics</h3>
+
+    <ul>
+        <li>[link:https://github.com/jsantell/THREE.IK THREE.IK]</li>
+        <li>[link:https://github.com/lo-th/fullik fullik]</li>
+    </ul>
+
+    <h3>Game AI</h3>
+
+    <ul>
+        <li>[link:https://mugen87.github.io/yuka/ yuka]</li>
+        <li>[link:https://github.com/donmccurdy/three-pathfinding three-pathfinding]</li>
+    </ul>
+
+    <h3>Wrappers and Frameworks</h3>
+
+    <ul>
+        <li>[link:https://aframe.io/ A-Frame]</li>
+        <li>[link:https://github.com/pmndrs/react-three-fiber react-three-fiber]</li>
+        <li>[link:https://github.com/ecsyjs/ecsy-three ECSY]</li>
+    </ul>
+
+</body>
+
+</html>

+ 156 - 0
docs/manual/ja/introduction/Loading-3D-models.html

@@ -0,0 +1,156 @@
+<!DOCTYPE html>
+<html lang="ja">
+
+<head>
+	<meta charset="utf-8">
+	<base href="../../../" />
+	<script src="page.js"></script>
+	<link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+	<h1>[name]</h1>
+
+	<p>
+		3Dモデルはたくさんのファイル形式で利用可能で、それぞれに目的があり、複雑さも様々です。
+		<a href="https://github.com/mrdoob/three.js/tree/dev/examples/jsm/loaders" target="_blank" rel="noopener">
+			three.jsは様々なloaderを提供しています</a>
+		が、適切な形式とワークフローを選択することで、パフォーマンスを改善することができます。
+		うまく動作させるのが難しいフォーマットや、リアルタイムでの体験に適さないフォーマットもあり、
+		中にはまったくサポートされていないフォーマットもあります。
+	</p>
+
+	<p>
+		このガイドでは、ほとんどのユーザにおすすめのワークフローと、予期しないことが発生したときに何を試してみればよいかを紹介します。
+	</p>
+
+	<h2>始める前に</h2>
+
+	<p>
+		もしthree.jsをローカルサーバで動かすのが初めてなら、
+		[link:#manual/introduction/How-to-run-things-locally how to run things locally]を見てみてください。
+		3Dモデルを表示する際の多くの一般的なエラーはファイルを正しく配置することで防ぐことができます。
+	</p>
+
+	<h2>おすすめのワークフロー</h2>
+
+	<p>
+		可能なら、glTF(GL Transmission Format)を使うことをおすすめします。
+		glTFは<small>.GLB</small> と <small>.GLTF</small>の両方のフォーマットについてサポートしています。
+		glTFはランタイムアセットの配信に注力しているので、変換時にはコンパクトでロードも早いです。
+		機能としては、メッシュやマテリアル、テクスチャ、スキン、スケルトン、morphターゲット、アニメーション、ライト、カメラがあります。
+	</p>
+
+	<p>
+		公開されているglTFファイルは<a href="https://sketchfab.com/models?features=downloadable&sort_by=-likeCount&type=models" target="_blank" rel="noopener">Sketchfab</a>のようなサイトで利用可能です。
+		また様々なツールでglTF形式でexportすることが出来ます。
+	</p>
+
+	<ul>
+		<li><a href="https://www.blender.org/" target="_blank" rel="noopener">Blender</a> by the Blender Foundation</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><a href="https://labs.maxon.net/?p=3360" target="_blank" rel="noopener">Cinema 4D</a> by MAXON</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>&hellip;and <a href="http://github.khronos.org/glTF-Project-Explorer/" target="_blank" rel="noopener">many
+				more</a></li>
+	</ul>
+
+	<p>
+		glTFをサポートしていないツールが使いたい場合は、ツールの作者にglTFのエクスポートを依頼するか、
+		<a href="https://github.com/KhronosGroup/glTF/issues/1051" target="_blank" rel="noopener">the glTF roadmap
+			thread</a>に投稿することを検討してください。
+	</p>
+
+	<p>
+		glTFが選択肢にない場合は、FBX,OBJ,COLLADAといった一般的な形式も利用可能です。
+		これらは定期的にメンテナンスされています。
+	</p>
+
+	<h2>Loading</h2>
+
+	<p>
+		ごく一部のローダ(例えば、[page:ObjectLoader])はデフォルトでthree.jsに入っています。
+		ほかのものは、ユーザがそれぞれ自分のアプリに加える必要があります。
+
+	</p>
+
+	<code>
+		import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
+	</code>
+
+	<p>
+		ローダをimportした時点で、シーンにモデルを追加できるようになります。
+		文法はローダによって異なります。異なるフォーマットを使う場合は、そのローダのドキュメントやサンプルを確認してください。glTFの場合、グローバルスクリプトでは以下のように使用します。
+	</p>
+
+	<code>
+		const loader = new GLTFLoader();
+
+		loader.load( 'path/to/model.glb', function ( gltf ) {
+
+			scene.add( gltf.scene );
+
+		}, undefined, function ( error ) {
+
+			console.error( error );
+
+		} );
+	</code>
+
+	<p>
+		より詳細な機能について知りたい場合は[page:GLTFLoader GLTFLoader documentation]を見てください。
+	</p>
+
+	<h2>Troubleshooting</h2>
+
+	<p>
+		何時間もかけて傑作をモデリングしたのに、webpageに読み込むと、なんと!😭
+		歪んでいたり、色がおかしかったり、表示されなかったりすることがあります。
+		そういったときにはトラブルシューティングを始めましょう。
+	</p>
+
+	<ol>
+		<li>
+			JavaScriptコンソールでエラーが発生していないか確認し、<em>.load()</em> を呼び出す際に<em>onError</em>コールバックを使用して結果をログに記録していることを確認してください
+
+		</li>
+		<li>
+			モデルを別のアプリケーションで見てみてください。
+			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>でドラックアンドドロップでviewerが利用できます。
+			一つ以上のアプリケーションでモデルが正しく表示された場合、<a href="https://github.com/mrdoob/three.js/issues/new" target="_blank" rel="noopener">three.jsにバグを報告</a>してください。
+			モデルがどのアプリケーションでも表示できない場合、モデルを作成する際に使ったアプリにバグを報告することを強くお勧めします。
+		</li>
+		<li>
+			モデルを1000倍にスケールアップしたり、スケールダウンしたりしてみてください。
+			多くのモデルはスケールが異なります。大きなモデルだと、カメラがモデルの中に入ってしまって見えなくなっていることがあります。
+		</li>
+		<li>
+			光源を追加して配置してみてください。暗闇の中にモデルが隠れている可能性があります。
+		</li>
+		<li>
+			ネットワークタブで失敗しているテクスチャのリクエスト(例えば、<em>C:\\Path\To\Model\texture.jpg</em>)を探してみてください。見つかったら代わりに <em>images/texture.jpg</em>
+			のようなモデルへの相対パスを使ってください。
+			これはテキストエディタでモデルファイルを編集する必要があるかもしれません。
+		</li>
+	</ol>
+
+	<h2>助けを求める(Asking for help)</h2>
+
+	<p>
+		上記のトラブルシューティングのプロセスを一通りやってもまだ動かない場合、正しいやり方で助けを求めることが
+		早期の解決につながります。<a href="https://discourse.threejs.org/" target="_blank" rel="noopener">three.js forum</a>に質問を投稿して、可能であれば自分のモデル(もしくは同じ問題を持つよりシンプルなモデル)を利用可能な形式で添付してください。他の人が問題を迅速に再現できるように、十分な情報を含めてください。
+	</p>
+
+</body>
+
+</html>

+ 86 - 0
docs/manual/ja/introduction/Matrix-transformations.html

@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<html lang="ja">
+
+<head>
+	<meta charset="utf-8">
+	<base href="../../../" />
+	<script src="page.js"></script>
+	<link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+	<h1>[name]</h1>
+
+	<p>
+		Three.jsは行列(*matrices*)を使って3次元変換(位置の変換、回転、スケーリング)をエンコードします。
+		すべての[page:Object3D]インスタンスは、そのオブジェクトの位置や回転、スケールを保存した行列([page:Object3D.matrix
+		matrix])を持っています。このページではオブジェクトの3次元変換をどうやって行うかを説明しています。
+
+	</p>
+
+	<h2>Convenience properties and *matrixAutoUpdate*(便利なプロパティとmatrixAutoUpdate)</h2>
+
+	<p>
+		オブジェクトの変換を更新するには二つの方法があります。
+	</p>
+	<ol>
+		<li>
+			オブジェクトの*position*や*quaternion*(四元数)や<strong>スケールのプロパティ</strong>を変更することで、three.jsに
+			オブジェクトの行列を再計算させます。
+			<code>
+object.position.copy( start_position );
+object.quaternion.copy( quaternion );
+				</code>
+			デフォルトでは、*matrixAutoUpdate*のプロパティはtrueで、行列は自動的に再計算されます。
+			オブジェクトが静的な場合や、再計算するタイミングを制御したい場合は、このプロパティをfalseに設定することでパフォーマンスが改善する可能性があります。
+
+			<code>
+object.matrixAutoUpdate = false;
+				</code>
+			プロパティを変更した後には、行列を手動で更新してください。
+			<code>
+object.updateMatrix();
+				</code>
+		</li>
+		<li>
+			オブジェクトの行列を直接修正する方法です。
+			[page:Matrix4]クラスには行列を変更するための様々なメソッドがあります。
+			<code>
+object.matrix.setRotationFromQuaternion( quaternion );
+object.matrix.setPosition( start_position );
+object.matrixAutoUpdate = false;
+				</code>
+			この場合 *matrixAutoUpdate*は*false*に設定<em>しなくてはならない</em>ことに注意してください。
+			また*updateMatrix*を呼ば<em>ない</em>ようにしてください。
+			*updateMatrix*を呼ぶと、行列にマニュアルで加えた変更がなくなり、<strong>位置やスケール</strong>などから行列が再計算されます。
+		</li>
+	</ol>
+
+	<h2>Object and world matrices(オブジェクトとワールド座標系での行列)</h2>
+	<p>
+		オブジェクトの行列([page:Object3D.matrix matrix])は、[page:Object3D.parent parent](親オブジェクト)に対する<em>相対的な</em>変換を保持しています。
+		<em>ワールド座標系での</em>オブジェクトの変換を取得するには、オブジェクトの[page:Object3D.matrixWorld]にアクセスする必要があります。
+
+	</p>
+	<p>
+		親オブジェクトや子オブジェクトの変換が変更された場合は、[page:Object3D.updateMatrixWorld updateMatrixWorld]()を呼び出すことで、子オブジェクトの[page:Object3D.matrixWorld matrixWorld]の更新を要求することができます。
+	</p>
+
+	<h2>Rotation and Quaternion(回転と四元数)</h2>
+	<p>
+		three.jsでは3次元の回線を表すためにオイラー角([page:Euler Euler angles])と4元数([page:Quaternion Quaternions])という2つの方法があります。
+		また、three.jsではこの2つの間の変換メソッドも提供されています。
+		オイラー角はgimbal lockと呼ばれる問題の影響をうけることがあります。
+		gimbal lockが発生すると、特定の設定のときにオブジェクトの回転の自由度が失われます(オブジェクトが特定の軸方向に回転できなくなります)
+		このため、オブジェクトの回転は<em>つねに</em>オブジェクトの4元数([page:Object3D.quaternion quaternion])に保持されます。
+	</p>
+	<p>
+		以前のバージョンのライブラリには*useQuaternion*プロパティがあり、これをfalseに設定すると、
+		オブジェクトの行列([page:Object3D.matrix matrix])がオイラー角から計算されるようになっていました。
+		このやり方は古くなってきたので、代わりに[page:Object3D.setRotationFromEuler setRotationFromEuler]メソッドを使用して、
+		四元数を更新します。
+	</p>
+
+</body>
+
+</html>

+ 40 - 0
docs/manual/ja/introduction/Typescript-setup.html

@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html lang="ja">
+	<head>
+		<meta charset="utf-8">
+		<base href="../../../" />
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<p>
+			three.jsはJavaScriptベースのライブラリですが、[link:https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html 宣言ファイル](*d.ts* ファイル)は公開されているので、TypeScriptプロジェクトで使用することも可能です。
+		</p>
+
+		<p>
+			Typescriptのコンパイラがthree.jsの型を判別するために最小限の設定は必要です。<br>
+			[link:https://www.typescriptlang.org/docs/handbook/module-resolution.html moduleResolution]を *node* に、[link:https://www.typescriptlang.org/docs/handbook/compiler-options.html target]を *es6* 以降に設定する必要があります。
+		</p>
+
+		<code>
+		// Example of minimal `tsconfig.json` file
+		{
+			"compilerOptions": {
+				"target": "es6",
+				"moduleResolution": "node",
+			},
+			"include": [ "./src/**/*.ts" ],
+		}
+		</code>
+
+		<p>
+			注意事項 : 今のところ、この2つのオプションを使わずにthree.jsの型を使うことはできません。
+		</p>
+
+		<p>
+			注意事項 : いくつかの宣言が間違っていたり欠けていたりすることがあります。宣言ファイルの改良に貢献することは、コミュニティにとって非常に有益であり、three.jsの型付けをより正確で良いものにします。
+		</p>
+	</body>
+</html>

+ 183 - 0
docs/manual/ja/introduction/Useful-links.html

@@ -0,0 +1,183 @@
+<!DOCTYPE html>
+<html lang="ja">
+	<head>
+		<meta charset="utf-8">
+		<base href="../../../" />
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<p class="desc">
+			以下は、three.jsを学ぶ際に役立つと思われるリンク集です。<br />
+			ここに追加したいものがあったり、以下のリンクのどれかがもう関連していない、もしくは機能していないと思われる場合は、右下の「編集」ボタンをクリックして、自由に変更してください<br /><br />
+
+			また、three.jsは急速に開発が進んでいるため、これらのリンクの多くには古い情報が含まれていることにも注意してください。
+			期待通りに動作しない場合や、これらのリンクのいずれかに記載されている通りに動作しない場合は、
+			ブラウザコンソールで警告やエラーがないか確認してください。また、関連するドキュメントページもチェックしてください。
+		</p>
+
+		<h2>ヘルプ</h2>
+		<p>
+			Three.jsは公式の[link:https://discourse.threejs.org/ forum]と[link:http://stackoverflow.com/tags/three.js/info Stack Overflow]をヘルプリクエストに利用しています。何か支援が必要な場合は、ここを利用してください。ヘルプリクエストのためにGithubのissueを作成しないでください
+		</p>
+
+		<h2>チュートリアルと学習コース</h2>
+
+		<h3>three.jsを始める</h3>
+		<ul>
+			<li>
+				[link:https://threejsfundamentals.org/threejs/lessons/threejs-fundamentals.html Three.js Fundamentals starting lesson]
+			</li>
+			<li>
+				[link:https://codepen.io/rachsmith/post/beginning-with-3d-webgl-pt-1-the-scene Beginning with 3D WebGL] by [link:https://codepen.io/rachsmith/ Rachel Smith].
+			</li>
+			<li>
+				[link:https://www.august.com.au/blog/animating-scenes-with-webgl-three-js/ Animating scenes with WebGL and three.js]
+			</li>
+		</ul>
+
+		<h3>より先進的な内容の記事やコース</h3>
+		<ul>
+			<li>
+				[link:https://discoverthreejs.com/ Discover three.js]
+			</li>
+			<li>
+				[link:https://threejsfundamentals.org/ Three.js Fundamentals]
+			</li>
+			<li>
+				[link:http://blog.cjgammon.com/ Collection of tutorials] by [link:http://www.cjgammon.com/ CJ Gammon].
+			</li>
+			<li>
+				[link:https://medium.com/soffritti.pierfrancesco/glossy-spheres-in-three-js-bfd2785d4857 Glossy spheres in three.js].
+			</li>
+		 <li>
+			 [link:https://www.udacity.com/course/cs291 Interactive 3D Graphics] - a free course on Udacity that teaches the fundamentals of 3D Graphics,
+			 and uses three.js as its coding tool.
+		 </li>
+		 <li>
+			[Link:https://aerotwist.com/tutorials/ Aerotwist] tutorials by [link:https://github.com/paullewis/ Paul Lewis].
+		 </li>
+			 <li>
+			 [link:http://learningthreejs.com/ Learning Three.js] – a blog with articles dedicated to teaching three.js
+		 </li>
+		 <li>
+			 [link:https://discourse.threejs.org/t/three-js-bookshelf/2468 Three.js Bookshelf] - Looking for more resources about three.js or computer graphics in general?
+			 Check out the selection of literature recommended by the community.
+		 </li>
+		</ul>
+
+		<h2>ニュースとアップデート情報</h2>
+		<ul>
+			<li>
+				[link:https://twitter.com/hashtag/threejs Three.js on Twitter]
+			</li>
+			<li>
+				[link:http://www.reddit.com/r/threejs/ Three.js on reddit]
+			</li>
+			<li>
+				[link:http://www.reddit.com/r/webgl/ WebGL on reddit]
+			</li>
+			<li>
+				[link:http://learningwebgl.com/blog/ Learning WebGL Blog] – The authoritive news source for WebGL.
+			</li>
+		</ul>
+
+		<h2>Examples</h2>
+		<ul>
+			<li>
+				[link:https://github.com/edwinwebb/three-seed/ three-seed] - three.js starter project with ES6 and Webpack
+			</li>
+			<li>
+				[link:http://stemkoski.github.io/Three.js/index.html Professor Stemkoskis Examples] - a collection of beginner friendly
+				examples built using three.js r60.
+			</li>
+			<li>
+				[link:https://threejs.org/examples/ Official three.js examples] - these examples are
+				maintained as part of the three.js repository, and always use the latest version of three.js.
+			</li>
+			<li>
+				[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>
+		</ul>
+
+	 <h2>ツール</h2>
+	 <ul>
+		 <li>
+			[link:http://www.physgl.org/ physgl.org] - JavaScript front-end with wrappers to three.js, to bring WebGL
+ 			graphics to students learning physics and math.
+		 </li>
+		 <li>
+			 [link:https://whs.io/ Whitestorm.js] – Modular three.js framework with AmmoNext physics plugin.
+		 </li>
+
+		<li>
+			[link:http://zz85.github.io/zz85-bookmarklets/threelabs.html Three.js Inspector]
+		</li>
+		<li>
+			[link:http://idflood.github.io/ThreeNodes.js/ ThreeNodes.js].
+		</li>
+		<li>
+			[link:https://marketplace.visualstudio.com/items?itemName=bierner.comment-tagged-templates comment-tagged-templates] - VSCode extension syntax highlighting for tagged template strings, like: glsl.js.
+		</li>
+		<li>
+			[link:https://github.com/MozillaReality/WebXR-emulator-extension WebXR-emulator-extension]
+		</li>
+	 </ul>
+
+	<h2>WebGLのリファレンス</h2>
+	 <ul>
+		 <li>
+			[link:https://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf webgl-reference-card.pdf] - Reference of all WebGL and GLSL keywords, terminology, syntax and definitions.
+		 </li>
+	 </ul>
+
+	 <h2>古いリンク(Old Links)</h2>
+	 <p>
+		以下のリンクは歴史的な理由で残っています。現在でも役に立つと思うかもしれませんが、リンク先の情報は
+		すごく古いバージョンのthree.jsの情報を含んでいる可能性があるので気をつけてください。
+	 </p>
+
+	 <ul>
+		<li>
+			<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.
+		</li>
+		<li>
+			[link:http://fhtr.org/BasicsOfThreeJS/#1 Introduction to Three.js] by [link:http://github.com/kig/ Ilmari Heikkinen] (slideshow).
+		</li>
+		<li>
+			[link:http://www.slideshare.net/yomotsu/webgl-and-threejs WebGL and Three.js] by [link:http://github.com/yomotsu Akihiro Oyamada] (slideshow).
+		</li>
+		<li>
+			[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="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.
+		</li>
+		<li>
+			[link:http://bkcore.com/blog/3d/webgl-three-js-workflow-tips.html Max to Three.js workflow tips and tricks] by [link:https://github.com/BKcore BKcore]
+		</li>
+		<li>
+			[link:http://12devsofxmas.co.uk/2012/01/webgl-and-three-js/ A whirlwind look at Three.js]
+			by [link:http://github.com/nrocy Paul King]
+		</li>
+		<li>
+			[link:http://bkcore.com/blog/3d/webgl-three-js-animated-selective-glow.html Animated selective glow in Three.js]
+			by [link:https://github.com/BKcore BKcore]
+		</li>
+		<li>
+			[link:http://www.natural-science.or.jp/article/20120220155529.php Building A Physics Simulation Environment] - three.js tutorial in Japanese
+		</li>
+	 </ul>
+
+	</body>
+</html>

+ 33 - 0
docs/manual/ja/introduction/WebGL-compatibility-check.html

@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html lang="ja">
+	<head>
+		<meta charset="utf-8">
+		<base href="../../../" />
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+		<p>
+			問題が少なくなってきたとはいえ、端末やブラウザによってはWebGLに対応していない場合があります。以下の方法で、ブラウザがWebGLをサポートしているかどうかを確認し、サポートされていない場合はユーザーにメッセージを表示することができます。
+		</p>
+
+		<p>
+			javascriptのコードに[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/WebGL.js]を付け加えて、何かを描画する前に以下のコードを実行してください。
+		</p>
+
+		<code>
+		if ( WEBGL.isWebGLAvailable() ) {
+
+			// Initiate function or other initializations here
+			animate();
+
+		} else {
+
+			const warning = WEBGL.getWebGLErrorMessage();
+			document.getElementById( 'container' ).appendChild( warning );
+
+		}
+		</code>
+	</body>
+</html>

+ 1 - 1
docs/manual/ko/introduction/FAQ.html

@@ -27,7 +27,7 @@
 
 				<p>[link:https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html Safari: Using the Viewport]</p>
 
-				<p>[link:https://developer.mozilla.org/en/Mobile/Viewport_meta_tag MDN: Using the viewport meta tag]</p>
+				<p>[link:https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag MDN: Using the viewport meta tag]</p>
 		</div>
 
 		<h2>화면 확대 정도가 리사이징 시에 유지될 수 있나요?</h2>

+ 1 - 1
docs/manual/zh/introduction/FAQ.html

@@ -29,7 +29,7 @@
 
 				<p>[link:https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html Safari: Using the Viewport]</p>
 
-				<p>[link:https://developer.mozilla.org/en/Mobile/Viewport_meta_tag MDN: Using the viewport meta tag]</p>
+				<p>[link:https://developer.mozilla.org/en-US/docs/Web/HTML/Viewport_meta_tag MDN: Using the viewport meta tag]</p>
 		</div>
 
 		<h2>如何在窗口调整大小时保持场景比例不变?</h2>

+ 18 - 6
editor/js/Loader.js

@@ -299,11 +299,6 @@ function Loader( editor ) {
 			case 'js':
 			case 'json':
 
-			case '3geo':
-			case '3mat':
-			case '3obj':
-			case '3scn':
-
 				reader.addEventListener( 'load', function ( event ) {
 
 					var contents = event.target.result;
@@ -352,6 +347,23 @@ function Loader( editor ) {
 
 				break;
 
+			case 'ifc':
+
+				reader.addEventListener( 'load', async function ( event ) {
+
+					var { IFCLoader } = await import( '../../examples/jsm/loaders/IFCLoader.js' );
+
+					var loader = new IFCLoader();
+					var scene = await loader.parse( event.target.result );
+
+					scene.name = filename;
+
+					editor.execute( new AddObjectCommand( editor, scene ) );
+
+				}, false );
+				reader.readAsArrayBuffer( file );
+
+				break;
 
 			case 'kmz':
 
@@ -492,7 +504,7 @@ function Loader( editor ) {
 							depthWrite: false
 						} );
 
-						var shapes = path.toShapes( true );
+						var shapes = SVGLoader.createShapes( path );
 
 						for ( var j = 0; j < shapes.length; j ++ ) {
 

+ 4 - 2
editor/js/Menubar.View.js

@@ -2,12 +2,14 @@ import { UIPanel, UIRow } from './libs/ui.js';
 
 function MenubarView( editor ) {
 
+	var strings = editor.strings;
+
 	var container = new UIPanel();
 	container.setClass( 'menu' );
 
 	var title = new UIPanel();
 	title.setClass( 'title' );
-	title.setTextContent( 'View' );
+	title.setTextContent( strings.getKey( 'menubar/view' ) );
 	container.add( title );
 
 	var options = new UIPanel();
@@ -18,7 +20,7 @@ function MenubarView( editor ) {
 
 	var option = new UIRow();
 	option.setClass( 'option' );
-	option.setTextContent( 'Fullscreen' );
+	option.setTextContent( strings.getKey( 'menubar/view/fullscreen' ) );
 	option.onClick( function () {
 
 		if ( document.fullscreenElement === null ) {

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

@@ -1,6 +1,6 @@
 import * as THREE from '../../build/three.module.js';
 
-import { UIPanel, UIRow, UIInput, UIButton, UIColor, UICheckbox, UISelect, UIText, UINumber } from './libs/ui.js';
+import { UIButton, UICheckbox, UIColor, UIInput, UINumber, UIPanel, UIRow, UISelect, UIText } from './libs/ui.js';
 import { UITexture } from './libs/ui.three.js';
 
 import { SetMaterialCommand } from './commands/SetMaterialCommand.js';
@@ -104,7 +104,7 @@ function SidebarMaterial( editor ) {
 	materialProgramRow.add( new UIText( strings.getKey( 'sidebar/material/program' ) ).setWidth( '90px' ) );
 
 	var materialProgramInfo = new UIButton( strings.getKey( 'sidebar/material/info' ) );
-	materialProgramInfo.setMarginLeft( '4px' );
+	materialProgramInfo.setMarginRight( '4px' );
 	materialProgramInfo.onClick( function () {
 
 		signals.editScript.dispatch( currentObject, 'programInfo' );
@@ -113,7 +113,7 @@ function SidebarMaterial( editor ) {
 	materialProgramRow.add( materialProgramInfo );
 
 	var materialProgramVertex = new UIButton( strings.getKey( 'sidebar/material/vertex' ) );
-	materialProgramVertex.setMarginLeft( '4px' );
+	materialProgramVertex.setMarginRight( '4px' );
 	materialProgramVertex.onClick( function () {
 
 		signals.editScript.dispatch( currentObject, 'vertexShader' );
@@ -122,7 +122,7 @@ function SidebarMaterial( editor ) {
 	materialProgramRow.add( materialProgramVertex );
 
 	var materialProgramFragment = new UIButton( strings.getKey( 'sidebar/material/fragment' ) );
-	materialProgramFragment.setMarginLeft( '4px' );
+	materialProgramFragment.setMarginRight( '4px' );
 	materialProgramFragment.onClick( function () {
 
 		signals.editScript.dispatch( currentObject, 'fragmentShader' );
@@ -1273,8 +1273,8 @@ function SidebarMaterial( editor ) {
 			'emissiveMap': materialEmissiveMapRow,
 			'gradientMap': materialGradientMapRow,
 			'side': materialSideRow,
-			'size': materialSize,
-			'sizeAttenuation': materialSizeAttenuation,
+			'size': materialSizeRow,
+			'sizeAttenuation': materialSizeAttenuationRow,
 			'flatShading': materialShadingRow,
 			'blending': materialBlendingRow,
 			'opacity': materialOpacityRow,

+ 9 - 7
editor/js/Sidebar.Project.Video.js

@@ -4,12 +4,14 @@ import { APP } from './libs/app.js';
 
 function SidebarProjectVideo( editor ) {
 
+	var strings = editor.strings;
+
 	var container = new UIPanel();
 	container.setId( 'render' );
 
 	// Video
 
-	container.add( new UIText( 'Video' ).setTextTransform( 'uppercase' ) );
+	container.add( new UIText( strings.getKey( 'sidebar/project/video' ) ).setTextTransform( 'uppercase' ) );
 	container.add( new UIBreak(), new UIBreak() );
 
 	// Resolution
@@ -17,7 +19,7 @@ function SidebarProjectVideo( editor ) {
 	var resolutionRow = new UIRow();
 	container.add( resolutionRow );
 
-	resolutionRow.add( new UIText( 'Resolution' ).setWidth( '90px' ) );
+	resolutionRow.add( new UIText( strings.getKey( 'sidebar/project/resolution' ) ).setWidth( '90px' ) );
 
 	var videoWidth = new UIInteger( 1024 ).setTextAlign( 'center' ).setWidth( '28px' );
 	resolutionRow.add( videoWidth );
@@ -35,7 +37,7 @@ function SidebarProjectVideo( editor ) {
 	// Duration
 
 	var videoDurationRow = new UIRow();
-	videoDurationRow.add( new UIText( 'Duration' ).setWidth( '90px' ) );
+	videoDurationRow.add( new UIText( strings.getKey( 'sidebar/project/duration' ) ).setWidth( '90px' ) );
 
 	var videoDuration = new UIInteger( 10 );
 	videoDurationRow.add( videoDuration );
@@ -51,7 +53,7 @@ function SidebarProjectVideo( editor ) {
 	progress.setWidth( '170px' );
 	container.add( progress );
 
-	const renderButton = new UIButton( 'RENDER' );
+	const renderButton = new UIButton( strings.getKey( 'sidebar/project/render' ) ).setTextTransform( 'uppercase' );
 	renderButton.setWidth( '170px' );
 	renderButton.onClick( async () => {
 
@@ -75,7 +77,7 @@ function SidebarProjectVideo( editor ) {
 
 		ffmpeg.setProgress( ( { ratio } ) => {
 
-			progress.setValue( ratio );
+			progress.setValue( ( ratio * 0.5 ) + 0.5 );
 
 		} );
 
@@ -93,11 +95,11 @@ function SidebarProjectVideo( editor ) {
 			ffmpeg.FS( 'writeFile', `tmp.${num}.png`, await fetchFile( canvas.toDataURL() ) );
 			currentTime += 1 / fps;
 
-			progress.setValue( i / frames );
+			progress.setValue( ( i / frames ) * 0.5 );
 
 		}
 
-		await ffmpeg.run( '-framerate', String( fps ), '-pattern_type', 'glob', '-i', '*.png', '-c:v', 'libx264', '-pix_fmt', 'yuv420p', '-preset', 'slow', '-crf', String( 6 ), 'out.mp4' );
+		await ffmpeg.run( '-framerate', String( fps ), '-pattern_type', 'glob', '-i', '*.png', '-c:v', 'libx264', '-pix_fmt', 'yuv420p', '-preset', 'slow', '-crf', String( 5 ), 'out.mp4' );
 
 		const data = ffmpeg.FS( 'readFile', 'out.mp4' );
 

+ 29 - 5
editor/js/Strings.js

@@ -71,6 +71,9 @@ function Strings( config ) {
 			'menubar/examples/Pong': 'Pong',
 			'menubar/examples/Shaders': 'Shaders',
 
+			'menubar/view': 'View',
+			'menubar/view/fullscreen': 'Fullscreen',
+
 			'menubar/help': 'Help',
 			'menubar/help/source_code': 'Source Code',
 			'menubar/help/icons': 'Icon Pack',
@@ -233,8 +236,8 @@ function Strings( config ) {
 			'sidebar/material/name': 'Name',
 			'sidebar/material/program': 'Program',
 			'sidebar/material/info': 'Info',
-			'sidebar/material/vertex': 'Vertex',
-			'sidebar/material/fragment': 'fragment',
+			'sidebar/material/vertex': 'Vert',
+			'sidebar/material/fragment': 'Frag',
 			'sidebar/material/color': 'Color',
 			'sidebar/material/depthPacking': 'Depth Packing',
 			'sidebar/material/roughness': 'Roughness',
@@ -301,6 +304,11 @@ function Strings( config ) {
 			'sidebar/project/materials': 'Materials',
 			'sidebar/project/Assign': 'Assign',
 
+			'sidebar/project/video': 'Video',
+			'sidebar/project/resolution': 'Resolution',
+			'sidebar/project/duration': 'Duration',
+			'sidebar/project/render': 'Render',
+
 			'sidebar/settings': 'Settings',
 			'sidebar/settings/language': 'Language',
 			'sidebar/settings/exportPrecision': 'Export Precision',
@@ -398,6 +406,9 @@ function Strings( config ) {
 			'menubar/examples/Pong': 'Pong',
 			'menubar/examples/Shaders': 'Shaders',
 
+			'menubar/view': 'View',
+			'menubar/view/fullscreen': 'Fullscreen',
+
 			'menubar/help': 'Aide',
 			'menubar/help/source_code': 'Code Source',
 			'menubar/help/icons': 'Icon Pack',
@@ -628,6 +639,11 @@ function Strings( config ) {
 			'sidebar/project/materials': 'Matériaux',
 			'sidebar/project/Assign': 'Attribuer',
 
+			'sidebar/project/video': 'Video',
+			'sidebar/project/resolution': 'Resolution',
+			'sidebar/project/duration': 'Duration',
+			'sidebar/project/render': 'Render',
+
 			'sidebar/settings': 'Paramètres',
 			'sidebar/settings/language': 'Langue',
 			'sidebar/settings/exportPrecision': 'Précision à l\'exportation',
@@ -682,7 +698,7 @@ function Strings( config ) {
 			'menubar/edit/undo': '撤销 (Ctrl+Z)',
 			'menubar/edit/redo': '重做 (Ctrl+Shift+Z)',
 			'menubar/edit/clear_history': '清空历史记录',
-			'menubar/edit/center': 'Center',
+			'menubar/edit/center': '居中',
 			'menubar/edit/clone': '拷贝',
 			'menubar/edit/delete': '删除 (Del)',
 			'menubar/edit/fixcolormaps': '修复颜色贴图',
@@ -725,6 +741,9 @@ function Strings( config ) {
 			'menubar/examples/Pong': '乒乓球',
 			'menubar/examples/Shaders': '着色器',
 
+			'menubar/view': '视图',
+			'menubar/view/fullscreen': '全屏',
+
 			'menubar/help': '帮助',
 			'menubar/help/source_code': '源码',
 			'menubar/help/icons': '图标组件包',
@@ -939,18 +958,23 @@ function Strings( config ) {
 			'sidebar/project/materials': '材质',
 			'sidebar/project/Assign': '应用',
 
+			'sidebar/project/video': '视频',
+			'sidebar/project/resolution': '分辨率',
+			'sidebar/project/duration': '时长',
+			'sidebar/project/render': '渲染',
+
 			'sidebar/settings': '设置',
 			'sidebar/settings/language': '语言',
 			'sidebar/settings/exportPrecision': '输出精度',
 
-			'sidebar/settings/shortcuts': 'Shortcuts',
+			'sidebar/settings/shortcuts': '快捷键',
 			'sidebar/settings/shortcuts/translate': '移动',
 			'sidebar/settings/shortcuts/rotate': '旋转',
 			'sidebar/settings/shortcuts/scale': '缩放',
 			'sidebar/settings/shortcuts/undo': '撤销',
 			'sidebar/settings/shortcuts/focus': '聚焦',
 
-			'sidebar/settings/viewport': 'Viewport',
+			'sidebar/settings/viewport': '视窗',
 			'sidebar/settings/viewport/grid': '网格',
 			'sidebar/settings/viewport/helpers': '辅助',
 

+ 18 - 23
editor/js/Viewport.js

@@ -43,7 +43,19 @@ function Viewport( editor ) {
 
 	// helpers
 
-	var grid = new THREE.GridHelper( 30, 30, 0x444444, 0x888888 );
+	var grid = new THREE.Group();
+
+	var grid1 = new THREE.GridHelper( 30, 30, 0x888888 );
+	grid1.material.color.setHex( 0x888888 );
+	grid1.material.vertexColors = false;
+	grid.add( grid1 );
+
+	var grid2 = new THREE.GridHelper( 30, 6, 0x222222 );
+	grid2.material.color.setHex( 0x222222 );
+	grid2.material.depthFunc = THREE.AlwaysDepth;
+	grid2.material.vertexColors = false;
+	grid.add( grid2 );
+
 	var viewHelper = new ViewHelper( camera, container );
 	var vr = new VR( editor );
 
@@ -359,14 +371,14 @@ function Viewport( editor ) {
 			mediaQuery.addListener( function ( event ) {
 
 				renderer.setClearColor( event.matches ? 0x333333 : 0xaaaaaa );
-				updateGridColors( grid, event.matches ? [ 0x888888, 0x222222 ] : [ 0x282828, 0x888888 ] );
+				updateGridColors( grid1, grid2, event.matches ? [ 0x222222, 0x888888 ] : [ 0x888888, 0x282828 ] );
 
 				render();
 
 			} );
 
 			renderer.setClearColor( mediaQuery.matches ? 0x333333 : 0xaaaaaa );
-			updateGridColors( grid, mediaQuery.matches ? [ 0x888888, 0x222222 ] : [ 0x282828, 0x888888 ] );
+			updateGridColors( grid1, grid2, mediaQuery.matches ? [ 0x222222, 0x888888 ] : [ 0x888888, 0x282828 ] );
 
 		}
 
@@ -770,27 +782,10 @@ function Viewport( editor ) {
 
 }
 
-function updateGridColors( grid, colors ) {
-
-	const color1 = new THREE.Color( colors[ 0 ] );
-	const color2 = new THREE.Color( colors[ 1 ] );
-
-	const attribute = grid.geometry.attributes.color;
-	const array = attribute.array;
-
-	for ( var i = 0; i < array.length; i += 12 ) {
-
-		const color = ( i % ( 12 * 5 ) === 0 ) ? color1 : color2;
-
-		for ( var j = 0; j < 12; j += 3 ) {
-
-			color.toArray( array, i + j );
-
-		}
-
-	}
+function updateGridColors( grid1, grid2, colors ) {
 
-	attribute.needsUpdate = true;
+	grid1.material.color.setHex( colors[ 0 ] );
+	grid2.material.color.setHex( colors[ 1 ] );
 
 }
 

+ 5 - 2
editor/sw.js

@@ -1,4 +1,4 @@
-// r126.1bis
+const cacheName = 'threejs-editor-r127';
 
 const assets = [
 	'./',
@@ -37,6 +37,9 @@ const assets = [
 	'../examples/jsm/loaders/FBXLoader.js',
 	'../examples/jsm/loaders/GLTFLoader.js',
 	'../examples/jsm/loaders/KMZLoader.js',
+	'../examples/jsm/loaders/IFCLoader.js',
+	'../examples/jsm/loaders/ifc/web-ifc-api.js',
+	'../examples/jsm/loaders/ifc/web-ifc.wasm',
 	'../examples/jsm/loaders/MD2Loader.js',
 	'../examples/jsm/loaders/OBJLoader.js',
 	'../examples/jsm/loaders/MTLLoader.js',
@@ -214,7 +217,7 @@ const assets = [
 
 self.addEventListener( 'install', async function () {
 
-	const cache = await caches.open( 'threejs-editor' );
+	const cache = await caches.open( cacheName );
 
 	assets.forEach( function ( asset ) {
 

+ 3 - 2
examples/files.json

@@ -75,7 +75,6 @@
 		"webgl_loader_3mf",
 		"webgl_loader_3mf_materials",
 		"webgl_loader_amf",
-		"webgl_loader_assimp",
 		"webgl_loader_bvh",
 		"webgl_loader_collada",
 		"webgl_loader_collada_kinematics",
@@ -88,6 +87,7 @@
 		"webgl_loader_gltf_compressed",
 		"webgl_loader_gltf_extensions",
 		"webgl_loader_gltf_variants",
+		"webgl_loader_ifc",
 		"webgl_loader_imagebitmap",
 		"webgl_loader_kmz",
 		"webgl_loader_ldraw",
@@ -262,6 +262,7 @@
 		"webgl_postprocessing_sobel",
 		"webgl_postprocessing_ssao",
 		"webgl_postprocessing_ssr",
+		"webgl_postprocessing_ssrr",
 		"webgl_postprocessing_taa",
 		"webgl_postprocessing_unreal_bloom",
 		"webgl_postprocessing_unreal_bloom_selective"
@@ -298,6 +299,7 @@
 		"webgl_raymarching_reflect",
 		"webgl_shadowmap_csm",
 		"webgl_shadowmap_pcss",
+		"webgl_shadowmap_progressive",
 		"webgl_simple_gi",
 		"webgl_tiled_forward",
 		"webgl_worker_offscreencanvas"
@@ -377,7 +379,6 @@
 		"misc_exporter_ply",
 		"misc_exporter_stl",
 		"misc_exporter_usdz",
-		"misc_legacy",
 		"misc_lookat"
 	],
 	"css2d": [

+ 98 - 84
examples/js/animation/CCDIKSolver.js

@@ -38,12 +38,32 @@ THREE.CCDIKSolver = ( function () {
 		constructor: CCDIKSolver,
 
 		/**
-		 * Update IK bones.
+		 * Update all IK bones.
 		 *
-		 * @return {THREE.CCDIKSolver}
+		 * @return {CCDIKSolver}
 		 */
 		update: function () {
 
+			var iks = this.iks;
+
+			for ( var i = 0, il = iks.length; i < il; i ++ ) {
+
+				this.updateOne( iks[ i ] );
+
+			}
+
+			return this;
+
+		},
+
+		/**
+		 * Update one IK bone
+		 *
+		 * @param {Object} ik parameter
+		 * @return {THREE.CCDIKSolver}
+		 */
+		updateOne: function () {
+
 			var q = new THREE.Quaternion();
 			var targetPos = new THREE.Vector3();
 			var targetVec = new THREE.Vector3();
@@ -55,137 +75,131 @@ THREE.CCDIKSolver = ( function () {
 			var axis = new THREE.Vector3();
 			var vector = new THREE.Vector3();
 
-			return function update() {
+			return function update( ik ) {
 
 				var bones = this.mesh.skeleton.bones;
-				var iks = this.iks;
 
 				// for reference overhead reduction in loop
 				var math = Math;
 
-				for ( var i = 0, il = iks.length; i < il; i ++ ) {
-
-					var ik = iks[ i ];
-					var effector = bones[ ik.effector ];
-					var target = bones[ ik.target ];
-
-					// don't use getWorldPosition() here for the performance
-					// because it calls updateMatrixWorld( true ) inside.
-					targetPos.setFromMatrixPosition( target.matrixWorld );
-
-					var links = ik.links;
-					var iteration = ik.iteration !== undefined ? ik.iteration : 1;
-
-					for ( var j = 0; j < iteration; j ++ ) {
+				var effector = bones[ ik.effector ];
+				var target = bones[ ik.target ];
 
-						var rotated = false;
+				// don't use getWorldPosition() here for the performance
+				// because it calls updateMatrixWorld( true ) inside.
+				targetPos.setFromMatrixPosition( target.matrixWorld );
 
-						for ( var k = 0, kl = links.length; k < kl; k ++ ) {
+				var links = ik.links;
+				var iteration = ik.iteration !== undefined ? ik.iteration : 1;
 
-							var link = bones[ links[ k ].index ];
+				for ( var i = 0; i < iteration; i ++ ) {
 
-							// skip this link and following links.
-							// this skip is used for MMD performance optimization.
-							if ( links[ k ].enabled === false ) break;
+					var rotated = false;
 
-							var limitation = links[ k ].limitation;
-							var rotationMin = links[ k ].rotationMin;
-							var rotationMax = links[ k ].rotationMax;
+					for ( var j = 0, jl = links.length; j < jl; j ++ ) {
 
-							// don't use getWorldPosition/Quaternion() here for the performance
-							// because they call updateMatrixWorld( true ) inside.
-							link.matrixWorld.decompose( linkPos, invLinkQ, linkScale );
-							invLinkQ.invert();
-							effectorPos.setFromMatrixPosition( effector.matrixWorld );
+						var link = bones[ links[ j ].index ];
 
-							// work in link world
-							effectorVec.subVectors( effectorPos, linkPos );
-							effectorVec.applyQuaternion( invLinkQ );
-							effectorVec.normalize();
+						// skip this link and following links.
+						// this skip is used for MMD performance optimization.
+						if ( links[ j ].enabled === false ) break;
 
-							targetVec.subVectors( targetPos, linkPos );
-							targetVec.applyQuaternion( invLinkQ );
-							targetVec.normalize();
+						var limitation = links[ j ].limitation;
+						var rotationMin = links[ j ].rotationMin;
+						var rotationMax = links[ j ].rotationMax;
 
-							var angle = targetVec.dot( effectorVec );
+						// don't use getWorldPosition/Quaternion() here for the performance
+						// because they call updateMatrixWorld( true ) inside.
+						link.matrixWorld.decompose( linkPos, invLinkQ, linkScale );
+						invLinkQ.invert();
+						effectorPos.setFromMatrixPosition( effector.matrixWorld );
 
-							if ( angle > 1.0 ) {
+						// work in link world
+						effectorVec.subVectors( effectorPos, linkPos );
+						effectorVec.applyQuaternion( invLinkQ );
+						effectorVec.normalize();
 
-								angle = 1.0;
+						targetVec.subVectors( targetPos, linkPos );
+						targetVec.applyQuaternion( invLinkQ );
+						targetVec.normalize();
 
-							} else if ( angle < - 1.0 ) {
+						var angle = targetVec.dot( effectorVec );
 
-								angle = - 1.0;
+						if ( angle > 1.0 ) {
 
-							}
+							angle = 1.0;
 
-							angle = math.acos( angle );
+						} else if ( angle < - 1.0 ) {
 
-							// skip if changing angle is too small to prevent vibration of bone
-							// Refer to http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mmd.three.js
-							if ( angle < 1e-5 ) continue;
+							angle = - 1.0;
 
-							if ( ik.minAngle !== undefined && angle < ik.minAngle ) {
+						}
 
-								angle = ik.minAngle;
+						angle = math.acos( angle );
 
-							}
+						// skip if changing angle is too small to prevent vibration of bone
+						// Refer to http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mmd.three.js
+						if ( angle < 1e-5 ) continue;
 
-							if ( ik.maxAngle !== undefined && angle > ik.maxAngle ) {
+						if ( ik.minAngle !== undefined && angle < ik.minAngle ) {
 
-								angle = ik.maxAngle;
+							angle = ik.minAngle;
 
-							}
+						}
 
-							axis.crossVectors( effectorVec, targetVec );
-							axis.normalize();
+						if ( ik.maxAngle !== undefined && angle > ik.maxAngle ) {
 
-							q.setFromAxisAngle( axis, angle );
-							link.quaternion.multiply( q );
+							angle = ik.maxAngle;
 
-							// TODO: re-consider the limitation specification
-							if ( limitation !== undefined ) {
+						}
 
-								var c = link.quaternion.w;
+						axis.crossVectors( effectorVec, targetVec );
+						axis.normalize();
 
-								if ( c > 1.0 ) c = 1.0;
+						q.setFromAxisAngle( axis, angle );
+						link.quaternion.multiply( q );
 
-								var c2 = math.sqrt( 1 - c * c );
-								link.quaternion.set( limitation.x * c2,
-								                     limitation.y * c2,
-								                     limitation.z * c2,
-								                     c );
+						// TODO: re-consider the limitation specification
+						if ( limitation !== undefined ) {
 
-							}
+							var c = link.quaternion.w;
 
-							if ( rotationMin !== undefined ) {
+							if ( c > 1.0 ) c = 1.0;
 
-								link.rotation.setFromVector3(
-									link.rotation
-										.toVector3( vector )
-										.max( rotationMin ) );
+							var c2 = math.sqrt( 1 - c * c );
+							link.quaternion.set( limitation.x * c2,
+							                     limitation.y * c2,
+							                     limitation.z * c2,
+							                     c );
 
-							}
+						}
 
-							if ( rotationMax !== undefined ) {
+						if ( rotationMin !== undefined ) {
 
-								link.rotation.setFromVector3(
-									link.rotation
-										.toVector3( vector )
-										.min( rotationMax ) );
+							link.rotation.setFromVector3(
+								link.rotation
+									.toVector3( vector )
+									.max( rotationMin ) );
 
-							}
+						}
 
-							link.updateMatrixWorld( true );
+						if ( rotationMax !== undefined ) {
 
-							rotated = true;
+							link.rotation.setFromVector3(
+								link.rotation
+									.toVector3( vector )
+									.min( rotationMax ) );
 
 						}
 
-						if ( ! rotated ) break;
+						link.updateMatrixWorld( true );
+
+						rotated = true;
 
 					}
 
+					if ( ! rotated ) break;
+
 				}
 
 				return this;

+ 234 - 41
examples/js/animation/MMDAnimationHelper.js

@@ -40,7 +40,9 @@ THREE.MMDAnimationHelper = ( function () {
 			afterglow: params.afterglow !== undefined
 				? params.afterglow : 0.0,
 			resetPhysicsOnLoop: params.resetPhysicsOnLoop !== undefined
-				? params.resetPhysicsOnLoop : true
+				? params.resetPhysicsOnLoop : true,
+			pmxAnimation: params.pmxAnimation !== undefined
+				? params.pmxAnimation : false
 		};
 
 		this.enabled = {
@@ -217,15 +219,28 @@ THREE.MMDAnimationHelper = ( function () {
 
 			mesh.updateMatrixWorld( true );
 
-			if ( params.ik !== false ) {
+			// PMX animation system special path
+			if ( this.configuration.pmxAnimation &&
+				mesh.geometry.userData.MMD && mesh.geometry.userData.MMD.format === 'pmx' ) {
 
-				this._createCCDIKSolver( mesh ).update( params.saveOriginalBonesBeforeIK ); // this param is experimental
+				var sortedBonesData = this._sortBoneDataArray( mesh.geometry.userData.MMD.bones.slice() );
+				var ikSolver = params.ik !== false ? this._createCCDIKSolver( mesh ) : null;
+				var grantSolver = params.grant !== false ? this.createGrantSolver( mesh ) : null;
+				this._animatePMXMesh( mesh, sortedBonesData, ikSolver, grantSolver );
 
-			}
+			} else {
+
+				if ( params.ik !== false ) {
+
+					this._createCCDIKSolver( mesh ).update();
 
-			if ( params.grant !== false ) {
+				}
+
+				if ( params.grant !== false ) {
 
-				this.createGrantSolver( mesh ).update();
+					this.createGrantSolver( mesh ).update();
+
+				}
 
 			}
 
@@ -515,28 +530,45 @@ THREE.MMDAnimationHelper = ( function () {
 			var physics = objects.physics;
 			var looped = objects.looped;
 
-			// alternate solution to save/restore bones but less performant?
-			//mesh.pose();
-			//this._updatePropertyMixersBuffer( mesh );
-
 			if ( mixer && this.enabled.animation ) {
 
+				// alternate solution to save/restore bones but less performant?
+				//mesh.pose();
+				//this._updatePropertyMixersBuffer( mesh );
+
 				this._restoreBones( mesh );
 
 				mixer.update( delta );
 
 				this._saveBones( mesh );
 
-				if ( ikSolver && this.enabled.ik ) {
+				// PMX animation system special path
+				if ( this.configuration.pmxAnimation &&
+					mesh.geometry.userData.MMD && mesh.geometry.userData.MMD.format === 'pmx' ) {
 
-					mesh.updateMatrixWorld( true );
-					ikSolver.update();
+					if ( ! objects.sortedBonesData ) objects.sortedBonesData = this._sortBoneDataArray( mesh.geometry.userData.MMD.bones.slice() );
 
-				}
+					this._animatePMXMesh(
+						mesh,
+						objects.sortedBonesData,
+						ikSolver && this.enabled.ik ? ikSolver : null,
+						grantSolver && this.enabled.grant ? grantSolver : null
+					);
 
-				if ( grantSolver && this.enabled.grant ) {
+				} else {
 
-					grantSolver.update();
+					if ( ikSolver && this.enabled.ik ) {
+
+						mesh.updateMatrixWorld( true );
+						ikSolver.update();
+
+					}
+
+					if ( grantSolver && this.enabled.grant ) {
+
+						grantSolver.update();
+
+					}
 
 				}
 
@@ -559,6 +591,142 @@ THREE.MMDAnimationHelper = ( function () {
 
 		},
 
+		// Sort bones in order by 1. transformationClass and 2. bone index.
+		// In PMX animation system, bone transformations should be processed
+		// in this order.
+		_sortBoneDataArray: function ( boneDataArray ) {
+
+			return boneDataArray.sort( function ( a, b ) {
+
+				if ( a.transformationClass !== b.transformationClass ) {
+
+					return a.transformationClass - b.transformationClass;
+
+				} else {
+
+					return a.index - b.index;
+
+				}
+
+			} );
+
+		},
+
+		// PMX Animation system is a bit too complex and doesn't great match to
+		// Three.js Animation system. This method attempts to simulate it as much as
+		// possible but doesn't perfectly simulate.
+		// This method is more costly than the regular one so
+		// you are recommended to set constructor parameter "pmxAnimation: true"
+		// only if your PMX model animation doesn't work well.
+		// If you need better method you would be required to write your own.
+		_animatePMXMesh: function () {
+
+			// Keep working quaternions for less GC
+			var quaternions = [];
+			var quaternionIndex = 0;
+
+			function getQuaternion() {
+
+				if ( quaternionIndex >= quaternions.length ) {
+
+					quaternions.push( new THREE.Quaternion() );
+
+				}
+
+				return quaternions[ quaternionIndex ++ ];
+
+			}
+
+			// Save rotation whose grant and IK are already applied
+			// used by grant children
+			var grantResultMap = new Map();
+
+			function updateOne( mesh, boneIndex, ikSolver, grantSolver ) {
+
+				var bones = mesh.skeleton.bones;
+				var bonesData = mesh.geometry.userData.MMD.bones;
+				var boneData = bonesData[ boneIndex ];
+				var bone = bones[ boneIndex ];
+
+				// Return if already updated by being referred as a grant parent.
+				if ( grantResultMap.has( boneIndex ) ) return;
+
+				var quaternion = getQuaternion();
+
+				// Initialize grant result here to prevent infinite loop.
+				// If it's referred before updating with actual result later
+				// result without applyting IK or grant is gotten
+				// but better than composing of infinite loop.
+				grantResultMap.set( boneIndex, quaternion.copy( bone.quaternion ) );
+
+				// @TODO: Support global grant and grant position
+				if ( grantSolver && boneData.grant &&
+					! boneData.grant.isLocal && boneData.grant.affectRotation ) {
+
+					var parentIndex = boneData.grant.parentIndex;
+					var ratio = boneData.grant.ratio;
+
+					if ( ! grantResultMap.has( parentIndex ) ) {
+
+						updateOne( mesh, parentIndex, ikSolver, grantSolver );
+
+					}
+
+					grantSolver.addGrantRotation( bone, grantResultMap.get( parentIndex ), ratio );
+
+				}
+
+				if ( ikSolver && boneData.ik ) {
+
+					// @TODO: Updating world matrices every time solving an IK bone is
+					// costly. Optimize if possible.
+					mesh.updateMatrixWorld( true );
+					ikSolver.updateOne( boneData.ik );
+
+					// No confident, but it seems the grant results with ik links should be updated?
+					var links = boneData.ik.links;
+
+					for ( var i = 0, il = links.length; i < il; i ++ ) {
+
+						var link = links[ i ];
+
+						if ( link.enabled === false ) continue;
+
+						var linkIndex = link.index;
+
+						if ( grantResultMap.has( linkIndex ) ) {
+
+							grantResultMap.set( linkIndex, grantResultMap.get( linkIndex ).copy( bones[ linkIndex ].quaternion ) );
+
+						}
+
+					}
+
+				}
+
+				// Update with the actual result here
+				quaternion.copy( bone.quaternion );
+
+			}
+
+			return function ( mesh, sortedBonesData, ikSolver, grantSolver ) {
+
+				quaternionIndex = 0;
+				grantResultMap.clear();
+
+				for ( var i = 0, il = sortedBonesData.length; i < il; i ++ ) {
+
+					updateOne( mesh, sortedBonesData[ i ].index, ikSolver, grantSolver );
+
+				}
+
+				mesh.updateMatrixWorld( true );
+				return this;
+
+			};
+
+		}(),
+
 		_animateCamera: function ( camera, delta ) {
 
 			var mixer = this.objects.get( camera ).mixer;
@@ -961,6 +1129,10 @@ THREE.MMDAnimationHelper = ( function () {
 	};
 
 	/**
+	 * Solver for Grant (Fuyo in Japanese. I just google translated because
+	 * Fuyo may be MMD specific term and may not be common word in 3D CG terms.)
+	 * Grant propagates a bone's transform to other bones transforms even if
+	 * they are not children.
 	 * @param {THREE.SkinnedMesh} mesh
 	 * @param {Array<Object>} grants
 	 */
@@ -976,54 +1148,75 @@ THREE.MMDAnimationHelper = ( function () {
 		constructor: GrantSolver,
 
 		/**
+		 * Solve all the grant bones
 		 * @return {GrantSolver}
 		 */
 		update: function () {
 
-			var quaternion = new THREE.Quaternion();
+			var grants = this.grants;
 
-			return function () {
+			for ( var i = 0, il = grants.length; i < il; i ++ ) {
 
-				var bones = this.mesh.skeleton.bones;
-				var grants = this.grants;
+				this.updateOne( grants[ i ] );
 
-				for ( var i = 0, il = grants.length; i < il; i ++ ) {
+			}
 
-					var grant = grants[ i ];
-					var bone = bones[ grant.index ];
-					var parentBone = bones[ grant.parentIndex ];
+			return this;
 
-					if ( grant.isLocal ) {
+		},
 
-						// TODO: implement
-						if ( grant.affectPosition ) {
+		/**
+		 * Solve a grant bone
+		 * @param {Object} grant - grant parameter
+		 * @return {GrantSolver}
+		 */
+		updateOne: function ( grant ) {
 
-						}
+			var bones = this.mesh.skeleton.bones;
+			var bone = bones[ grant.index ];
+			var parentBone = bones[ grant.parentIndex ];
 
-						// TODO: implement
-						if ( grant.affectRotation ) {
+			if ( grant.isLocal ) {
 
-						}
+				// TODO: implement
+				if ( grant.affectPosition ) {
 
-					} else {
+				}
 
-						// TODO: implement
-						if ( grant.affectPosition ) {
+				// TODO: implement
+				if ( grant.affectRotation ) {
 
-						}
+				}
 
-						if ( grant.affectRotation ) {
+			} else {
 
-							quaternion.set( 0, 0, 0, 1 );
-							quaternion.slerp( parentBone.quaternion, grant.ratio );
-							bone.quaternion.multiply( quaternion );
+				// TODO: implement
+				if ( grant.affectPosition ) {
 
-						}
+				}
 
-					}
+				if ( grant.affectRotation ) {
+
+					this.addGrantRotation( bone, parentBone.quaternion, grant.ratio );
 
 				}
 
+			}
+
+			return this;
+
+		},
+
+		addGrantRotation: function () {
+
+			var quaternion = new THREE.Quaternion();
+
+			return function ( bone, q, ratio ) {
+
+				quaternion.set( 0, 0, 0, 1 );
+				quaternion.slerp( q, ratio );
+				bone.quaternion.multiply( quaternion );
+
 				return this;
 
 			};

+ 6 - 0
examples/js/controls/DeviceOrientationControls.js

@@ -4,6 +4,12 @@
 
 THREE.DeviceOrientationControls = function ( object ) {
 
+	if ( window.isSecureContext === false ) {
+
+		console.error( 'THREE.DeviceOrientationControls: DeviceOrientationEvent is only available in secure contexts (https)' );
+
+	}
+
 	var scope = this;
 	var changeEvent = { type: 'change' };
 	var EPS = 0.000001;

+ 9 - 0
examples/js/controls/DragControls.js

@@ -105,6 +105,15 @@ THREE.DragControls = function ( _objects, _camera, _domElement ) {
 
 			_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( object.matrixWorld ) );
 
+			if ( _hovered !== object && _hovered !== null) {
+
+				scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
+
+				_domElement.style.cursor = 'auto';
+				_hovered = null;
+
+			}
+			
 			if ( _hovered !== object ) {
 
 				scope.dispatchEvent( { type: 'hoveron', object: object } );

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

@@ -92,7 +92,6 @@ THREE.FirstPersonControls = function ( object, domElement ) {
 		}
 
 		event.preventDefault();
-		event.stopPropagation();
 
 		if ( this.activeLook ) {
 
@@ -112,7 +111,6 @@ THREE.FirstPersonControls = function ( object, domElement ) {
 	this.onMouseUp = function ( event ) {
 
 		event.preventDefault();
-		event.stopPropagation();
 
 		if ( this.activeLook ) {
 

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

@@ -117,7 +117,6 @@ THREE.FlyControls = function ( object, domElement ) {
 		}
 
 		event.preventDefault();
-		event.stopPropagation();
 
 		if ( this.dragToLook ) {
 
@@ -158,7 +157,6 @@ THREE.FlyControls = function ( object, domElement ) {
 	this.mouseup = function ( event ) {
 
 		event.preventDefault();
-		event.stopPropagation();
 
 		if ( this.dragToLook ) {
 

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

@@ -63,7 +63,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 	this.autoRotateSpeed = 2.0; // 30 seconds per orbit when fps is 60
 
 	// The four arrow keys
-	this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
+	this.keys = { LEFT: 'ArrowLeft', UP: 'ArrowUp', RIGHT: 'ArrowRight', BOTTOM: 'ArrowDown' };
 
 	// Mouse buttons
 	this.mouseButtons = { LEFT: THREE.MOUSE.ROTATE, MIDDLE: THREE.MOUSE.DOLLY, RIGHT: THREE.MOUSE.PAN };
@@ -586,7 +586,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 		var needsUpdate = false;
 
-		switch ( event.keyCode ) {
+		switch ( event.code ) {
 
 			case scope.keys.UP:
 				pan( 0, scope.keyPanSpeed );
@@ -989,7 +989,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 		if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return;
 
 		event.preventDefault();
-		event.stopPropagation();
 
 		scope.dispatchEvent( startEvent );
 
@@ -1098,7 +1097,6 @@ THREE.OrbitControls = function ( object, domElement ) {
 		if ( scope.enabled === false ) return;
 
 		event.preventDefault(); // prevent scrolling
-		event.stopPropagation();
 
 		switch ( state ) {
 

+ 4 - 9
examples/js/controls/TrackballControls.js

@@ -29,7 +29,7 @@ THREE.TrackballControls = function ( object, domElement ) {
 	this.minDistance = 0;
 	this.maxDistance = Infinity;
 
-	this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];
+	this.keys = [ 'KeyA' /*A*/, 'KeyS' /*S*/, 'KeyD' /*D*/ ];
 
 	this.mouseButtons = { LEFT: THREE.MOUSE.ROTATE, MIDDLE: THREE.MOUSE.DOLLY, RIGHT: THREE.MOUSE.PAN };
 
@@ -454,15 +454,15 @@ THREE.TrackballControls = function ( object, domElement ) {
 
 			return;
 
-		} else if ( event.keyCode === scope.keys[ STATE.ROTATE ] && ! scope.noRotate ) {
+		} else if ( event.code === scope.keys[ STATE.ROTATE ] && ! scope.noRotate ) {
 
 			_keyState = STATE.ROTATE;
 
-		} else if ( event.keyCode === scope.keys[ STATE.ZOOM ] && ! scope.noZoom ) {
+		} else if ( event.code === scope.keys[ STATE.ZOOM ] && ! scope.noZoom ) {
 
 			_keyState = STATE.ZOOM;
 
-		} else if ( event.keyCode === scope.keys[ STATE.PAN ] && ! scope.noPan ) {
+		} else if ( event.code === scope.keys[ STATE.PAN ] && ! scope.noPan ) {
 
 			_keyState = STATE.PAN;
 
@@ -483,7 +483,6 @@ THREE.TrackballControls = function ( object, domElement ) {
 	function onMouseDown( event ) {
 
 		event.preventDefault();
-		event.stopPropagation();
 
 		if ( _state === STATE.NONE ) {
 
@@ -539,7 +538,6 @@ THREE.TrackballControls = function ( object, domElement ) {
 		if ( scope.enabled === false ) return;
 
 		event.preventDefault();
-		event.stopPropagation();
 
 		var state = ( _keyState !== STATE.NONE ) ? _keyState : _state;
 
@@ -565,7 +563,6 @@ THREE.TrackballControls = function ( object, domElement ) {
 		if ( scope.enabled === false ) return;
 
 		event.preventDefault();
-		event.stopPropagation();
 
 		_state = STATE.NONE;
 
@@ -583,7 +580,6 @@ THREE.TrackballControls = function ( object, domElement ) {
 		if ( scope.noZoom === true ) return;
 
 		event.preventDefault();
-		event.stopPropagation();
 
 		switch ( event.deltaMode ) {
 
@@ -646,7 +642,6 @@ THREE.TrackballControls = function ( object, domElement ) {
 		if ( scope.enabled === false ) return;
 
 		event.preventDefault();
-		event.stopPropagation();
 
 		switch ( event.touches.length ) {
 

+ 56 - 2
examples/js/lines/LineMaterial.js

@@ -213,6 +213,24 @@ THREE.ShaderLib[ 'line' ] = {
 
 			#endif
 
+			float alpha = opacity;
+
+			#ifdef ALPHA_TO_COVERAGE
+
+			// artifacts appear on some hardware if a derivative is taken within a conditional
+			float a = vUv.x;
+			float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0;
+			float len2 = a * a + b * b;
+			float dlen = fwidth( len2 );
+
+			if ( abs( vUv.y ) > 1.0 ) {
+
+				alpha = 1.0 - smoothstep( 1.0 - dlen, 1.0 + dlen, len2 );
+
+			}
+
+			#else
+
 			if ( abs( vUv.y ) > 1.0 ) {
 
 				float a = vUv.x;
@@ -223,12 +241,14 @@ THREE.ShaderLib[ 'line' ] = {
 
 			}
 
-			vec4 diffuseColor = vec4( diffuse, opacity );
+			#endif
+
+			vec4 diffuseColor = vec4( diffuse, alpha );
 
 			#include <logdepthbuf_fragment>
 			#include <color_fragment>
 
-			gl_FragColor = vec4( diffuseColor.rgb, diffuseColor.a );
+			gl_FragColor = vec4( diffuseColor.rgb, alpha );
 
 			#include <tonemapping_fragment>
 			#include <encodings_fragment>
@@ -400,6 +420,40 @@ THREE.LineMaterial = function ( parameters ) {
 
 			}
 
+		},
+
+		alphaToCoverage: {
+
+			enumerable: true,
+
+			get: function () {
+
+				return Boolean( 'ALPHA_TO_COVERAGE' in this.defines );
+
+			},
+
+			set: function ( value ) {
+
+				if ( Boolean( value ) !== Boolean( 'ALPHA_TO_COVERAGE' in this.defines ) ) {
+
+					this.needsUpdate = true;
+
+				}
+
+				if ( value ) {
+
+					this.defines.ALPHA_TO_COVERAGE = '';
+					this.extensions.derivatives = true;
+
+				} else {
+
+					delete this.defines.ALPHA_TO_COVERAGE;
+					this.extensions.derivatives = false;
+
+				}
+
+			}
+
 		}
 
 	} );

+ 72 - 3
examples/js/lines/LineSegments2.js

@@ -26,9 +26,9 @@ THREE.LineSegments2.prototype = Object.assign( Object.create( THREE.Mesh.prototy
 
 			var instanceStart = geometry.attributes.instanceStart;
 			var instanceEnd = geometry.attributes.instanceEnd;
-			var lineDistances = new Float32Array( 2 * instanceStart.data.count );
+			var lineDistances = new Float32Array( 2 * instanceStart.count );
 
-			for ( var i = 0, j = 0, l = instanceStart.data.count; i < l; i ++, j += 2 ) {
+			for ( var i = 0, j = 0, l = instanceStart.count; i < l; i ++, j += 2 ) {
 
 				start.fromBufferAttribute( instanceStart, i );
 				end.fromBufferAttribute( instanceEnd, i );
@@ -60,6 +60,10 @@ THREE.LineSegments2.prototype = Object.assign( Object.create( THREE.Mesh.prototy
 		var line = new THREE.Line3();
 		var closestPoint = new THREE.Vector3();
 
+		var box = new THREE.Box3();
+		var sphere = new THREE.Sphere();
+		var clipToWorldVector = new THREE.Vector4();
+
 		return function raycast( raycaster, intersects ) {
 
 			if ( raycaster.camera === null ) {
@@ -74,6 +78,7 @@ THREE.LineSegments2.prototype = Object.assign( Object.create( THREE.Mesh.prototy
 			var camera = raycaster.camera;
 			var projectionMatrix = camera.projectionMatrix;
 
+			var matrixWorld = this.matrixWorld;
 			var geometry = this.geometry;
 			var material = this.material;
 			var resolution = material.resolution;
@@ -85,6 +90,71 @@ THREE.LineSegments2.prototype = Object.assign( Object.create( THREE.Mesh.prototy
 			// camera forward is negative
 			var near = - camera.near;
 
+			// clip space is [ - 1, 1 ] so multiply by two to get the full
+			// width in clip space
+			var ssMaxWidth = 2.0 * Math.max( lineWidth / resolution.width, lineWidth / resolution.height );
+
+			//
+
+			// check if we intersect the sphere bounds
+			if ( geometry.boundingSphere === null ) {
+
+				geometry.computeBoundingSphere();
+
+			}
+
+			sphere.copy( geometry.boundingSphere ).applyMatrix4( matrixWorld );
+			var distanceToSphere = Math.max( camera.near, sphere.distanceToPoint( ray.origin ) );
+
+			// get the w component to scale the world space line width
+			clipToWorldVector.set( 0, 0, - distanceToSphere, 1.0 ).applyMatrix4( camera.projectionMatrix );
+			clipToWorldVector.multiplyScalar( 1.0 / clipToWorldVector.w );
+			clipToWorldVector.applyMatrix4( camera.projectionMatrixInverse );
+
+			// increase the sphere bounds by the worst case line screen space width
+			var sphereMargin = Math.abs( ssMaxWidth / clipToWorldVector.w ) * 0.5;
+			sphere.radius += sphereMargin;
+
+			if ( raycaster.ray.intersectsSphere( sphere ) === false ) {
+
+				return;
+
+			}
+
+			//
+
+			// check if we intersect the box bounds
+			if ( geometry.boundingBox === null ) {
+
+				geometry.computeBoundingBox();
+
+			}
+
+			box.copy( geometry.boundingBox ).applyMatrix4( matrixWorld );
+			var distanceToBox = Math.max( camera.near, box.distanceToPoint( ray.origin ) );
+
+			// get the w component to scale the world space line width
+			clipToWorldVector.set( 0, 0, - distanceToBox, 1.0 ).applyMatrix4( camera.projectionMatrix );
+			clipToWorldVector.multiplyScalar( 1.0 / clipToWorldVector.w );
+			clipToWorldVector.applyMatrix4( camera.projectionMatrixInverse );
+
+			// increase the sphere bounds by the worst case line screen space width
+			var boxMargin = Math.abs( ssMaxWidth / clipToWorldVector.w ) * 0.5;
+			box.max.x += boxMargin;
+			box.max.y += boxMargin;
+			box.max.z += boxMargin;
+			box.min.x -= boxMargin;
+			box.min.y -= boxMargin;
+			box.min.z -= boxMargin;
+
+			if ( raycaster.ray.intersectsBox( box ) === false ) {
+
+				return;
+
+			}
+
+			//
+
 			// pick a point 1 unit out along the ray to avoid the ray origin
 			// sitting at the camera origin which will cause "w" to be 0 when
 			// applying the projection matrix.
@@ -103,7 +173,6 @@ THREE.LineSegments2.prototype = Object.assign( Object.create( THREE.Mesh.prototy
 
 			ssOrigin3.copy( ssOrigin );
 
-			var matrixWorld = this.matrixWorld;
 			mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld );
 
 			for ( var i = 0, l = instanceStart.count; i < l; i ++ ) {

+ 2 - 2
examples/js/lines/Wireframe.js

@@ -26,9 +26,9 @@ THREE.Wireframe.prototype = Object.assign( Object.create( THREE.Mesh.prototype )
 
 			var instanceStart = geometry.attributes.instanceStart;
 			var instanceEnd = geometry.attributes.instanceEnd;
-			var lineDistances = new Float32Array( 2 * instanceStart.data.count );
+			var lineDistances = new Float32Array( 2 * instanceStart.count );
 
-			for ( var i = 0, j = 0, l = instanceStart.data.count; i < l; i ++, j += 2 ) {
+			for ( var i = 0, j = 0, l = instanceStart.count; i < l; i ++, j += 2 ) {
 
 				start.fromBufferAttribute( instanceStart, i );
 				end.fromBufferAttribute( instanceEnd, i );

+ 0 - 2285
examples/js/loaders/AssimpLoader.js

@@ -1,2285 +0,0 @@
-THREE.AssimpLoader = function ( manager ) {
-
-	THREE.Loader.call( this, manager );
-
-};
-
-THREE.AssimpLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype ), {
-
-	constructor: THREE.AssimpLoader,
-
-	load: function ( url, onLoad, onProgress, onError ) {
-
-		var scope = this;
-
-		var path = ( scope.path === '' ) ? THREE.LoaderUtils.extractUrlBase( url ) : scope.path;
-
-		var loader = new THREE.FileLoader( scope.manager );
-		loader.setPath( scope.path );
-		loader.setResponseType( 'arraybuffer' );
-		loader.setRequestHeader( scope.requestHeader );
-		loader.setWithCredentials( scope.withCredentials );
-
-		loader.load( url, function ( buffer ) {
-
-			try {
-
-				onLoad( scope.parse( buffer, path ) );
-
-			} catch ( e ) {
-
-				if ( onError ) {
-
-					onError( e );
-
-				} else {
-
-					console.error( e );
-
-				}
-
-				scope.manager.itemError( url );
-
-			}
-
-		}, onProgress, onError );
-
-	},
-
-	parse: function ( buffer, path ) {
-
-		var textureLoader = new THREE.TextureLoader( this.manager );
-		textureLoader.setPath( this.resourcePath || path ).setCrossOrigin( this.crossOrigin );
-
-		var Virtulous = {};
-
-		Virtulous.KeyFrame = function ( time, matrix ) {
-
-			this.time = time;
-			this.matrix = matrix.clone();
-			this.position = new THREE.Vector3();
-			this.quaternion = new THREE.Quaternion();
-			this.scale = new THREE.Vector3( 1, 1, 1 );
-			this.matrix.decompose( this.position, this.quaternion, this.scale );
-			this.clone = function () {
-
-				var n = new Virtulous.KeyFrame( this.time, this.matrix );
-				return n;
-
-			};
-
-			this.lerp = function ( nextKey, time ) {
-
-				time -= this.time;
-				var dist = ( nextKey.time - this.time );
-				var l = time / dist;
-				var l2 = 1 - l;
-				var keypos = this.position;
-				var keyrot = this.quaternion;
-				//      var keyscl =  key.parentspaceScl || key.scl;
-				var key2pos = nextKey.position;
-				var key2rot = nextKey.quaternion;
-				//  var key2scl =  key2.parentspaceScl || key2.scl;
-				Virtulous.KeyFrame.tempAniPos.x = keypos.x * l2 + key2pos.x * l;
-				Virtulous.KeyFrame.tempAniPos.y = keypos.y * l2 + key2pos.y * l;
-				Virtulous.KeyFrame.tempAniPos.z = keypos.z * l2 + key2pos.z * l;
-				//     tempAniScale.x = keyscl[0] * l2 + key2scl[0] * l;
-				//     tempAniScale.y = keyscl[1] * l2 + key2scl[1] * l;
-				//     tempAniScale.z = keyscl[2] * l2 + key2scl[2] * l;
-				Virtulous.KeyFrame.tempAniQuat.set( keyrot.x, keyrot.y, keyrot.z, keyrot.w );
-				Virtulous.KeyFrame.tempAniQuat.slerp( key2rot, l );
-				return Virtulous.KeyFrame.tempAniMatrix.compose( Virtulous.KeyFrame.tempAniPos, Virtulous.KeyFrame.tempAniQuat, Virtulous.KeyFrame.tempAniScale );
-
-			};
-
-		};
-
-		Virtulous.KeyFrame.tempAniPos = new THREE.Vector3();
-		Virtulous.KeyFrame.tempAniQuat = new THREE.Quaternion();
-		Virtulous.KeyFrame.tempAniScale = new THREE.Vector3( 1, 1, 1 );
-		Virtulous.KeyFrame.tempAniMatrix = new THREE.Matrix4();
-		Virtulous.KeyFrameTrack = function () {
-
-			this.keys = [];
-			this.target = null;
-			this.time = 0;
-			this.length = 0;
-			this._accelTable = {};
-			this.fps = 20;
-			this.addKey = function ( key ) {
-
-				this.keys.push( key );
-
-			};
-
-			this.init = function () {
-
-				this.sortKeys();
-
-				if ( this.keys.length > 0 )
-					this.length = this.keys[ this.keys.length - 1 ].time;
-				else
-					this.length = 0;
-
-				if ( ! this.fps ) return;
-
-				for ( var j = 0; j < this.length * this.fps; j ++ ) {
-
-					for ( var i = 0; i < this.keys.length; i ++ ) {
-
-						if ( this.keys[ i ].time == j ) {
-
-							this._accelTable[ j ] = i;
-							break;
-
-						} else if ( this.keys[ i ].time < j / this.fps && this.keys[ i + 1 ] && this.keys[ i + 1 ].time >= j / this.fps ) {
-
-							this._accelTable[ j ] = i;
-							break;
-
-						}
-
-					}
-
-				}
-
-			};
-
-			this.parseFromThree = function ( data ) {
-
-				var fps = data.fps;
-				this.target = data.node;
-				var track = data.hierarchy[ 0 ].keys;
-				for ( var i = 0; i < track.length; i ++ ) {
-
-					this.addKey( new Virtulous.KeyFrame( i / fps || track[ i ].time, track[ i ].targets[ 0 ].data ) );
-
-				}
-
-				this.init();
-
-			};
-
-			this.parseFromCollada = function ( data ) {
-
-				var track = data.keys;
-				var fps = this.fps;
-
-				for ( var i = 0; i < track.length; i ++ ) {
-
-					this.addKey( new Virtulous.KeyFrame( i / fps || track[ i ].time, track[ i ].matrix ) );
-
-				}
-
-				this.init();
-
-			};
-
-			this.sortKeys = function () {
-
-				this.keys.sort( this.keySortFunc );
-
-			};
-
-			this.keySortFunc = function ( a, b ) {
-
-				return a.time - b.time;
-
-			};
-
-			this.clone = function () {
-
-				var t = new Virtulous.KeyFrameTrack();
-				t.target = this.target;
-				t.time = this.time;
-				t.length = this.length;
-
-				for ( var i = 0; i < this.keys.length; i ++ ) {
-
-					t.addKey( this.keys[ i ].clone() );
-
-				}
-
-				t.init();
-				return t;
-
-			};
-
-			this.reTarget = function ( root, compareitor ) {
-
-				if ( ! compareitor ) compareitor = Virtulous.TrackTargetNodeNameCompare;
-				this.target = compareitor( root, this.target );
-
-			};
-
-			this.keySearchAccel = function ( time ) {
-
-				time *= this.fps;
-				time = Math.floor( time );
-				return this._accelTable[ time ] || 0;
-
-			};
-
-			this.setTime = function ( time ) {
-
-				time = Math.abs( time );
-				if ( this.length )
-					time = time % this.length + .05;
-				var key0 = null;
-				var key1 = null;
-
-				for ( var i = this.keySearchAccel( time ); i < this.keys.length; i ++ ) {
-
-					if ( this.keys[ i ].time == time ) {
-
-						key0 = this.keys[ i ];
-						key1 = this.keys[ i ];
-						break;
-
-					} else if ( this.keys[ i ].time < time && this.keys[ i + 1 ] && this.keys[ i + 1 ].time > time ) {
-
-						key0 = this.keys[ i ];
-						key1 = this.keys[ i + 1 ];
-						break;
-
-					} else if ( this.keys[ i ].time < time && i == this.keys.length - 1 ) {
-
-						key0 = this.keys[ i ];
-						key1 = this.keys[ 0 ].clone();
-						key1.time += this.length + .05;
-						break;
-
-					}
-
-				}
-
-				if ( key0 && key1 && key0 !== key1 ) {
-
-					this.target.matrixAutoUpdate = false;
-					this.target.matrix.copy( key0.lerp( key1, time ) );
-					this.target.matrixWorldNeedsUpdate = true;
-					return;
-
-				}
-
-				if ( key0 && key1 && key0 == key1 ) {
-
-					this.target.matrixAutoUpdate = false;
-					this.target.matrix.copy( key0.matrix );
-					this.target.matrixWorldNeedsUpdate = true;
-					return;
-
-				}
-
-			};
-
-		};
-
-		Virtulous.TrackTargetNodeNameCompare = function ( root, target ) {
-
-			function find( node, name ) {
-
-				if ( node.name == name )
-					return node;
-
-				for ( var i = 0; i < node.children.length; i ++ ) {
-
-					var r = find( node.children[ i ], name );
-					if ( r ) return r;
-
-				}
-
-				return null;
-
-			}
-
-			return find( root, target.name );
-
-		};
-
-		Virtulous.Animation = function () {
-
-			this.tracks = [];
-			this.length = 0;
-
-			this.addTrack = function ( track ) {
-
-				this.tracks.push( track );
-				this.length = Math.max( track.length, this.length );
-
-			};
-
-			this.setTime = function ( time ) {
-
-				this.time = time;
-
-				for ( var i = 0; i < this.tracks.length; i ++ )
-					this.tracks[ i ].setTime( time );
-
-			};
-
-			this.clone = function ( target, compareitor ) {
-
-				if ( ! compareitor ) compareitor = Virtulous.TrackTargetNodeNameCompare;
-				var n = new Virtulous.Animation();
-				n.target = target;
-				for ( var i = 0; i < this.tracks.length; i ++ ) {
-
-					var track = this.tracks[ i ].clone();
-					track.reTarget( target, compareitor );
-					n.addTrack( track );
-
-				}
-
-				return n;
-
-			};
-
-		};
-
-		var ASSBIN_CHUNK_AICAMERA = 0x1234;
-		var ASSBIN_CHUNK_AILIGHT = 0x1235;
-		var ASSBIN_CHUNK_AITEXTURE = 0x1236;
-		var ASSBIN_CHUNK_AIMESH = 0x1237;
-		var ASSBIN_CHUNK_AINODEANIM = 0x1238;
-		var ASSBIN_CHUNK_AISCENE = 0x1239;
-		var ASSBIN_CHUNK_AIBONE = 0x123a;
-		var ASSBIN_CHUNK_AIANIMATION = 0x123b;
-		var ASSBIN_CHUNK_AINODE = 0x123c;
-		var ASSBIN_CHUNK_AIMATERIAL = 0x123d;
-		var ASSBIN_CHUNK_AIMATERIALPROPERTY = 0x123e;
-		var ASSBIN_MESH_HAS_POSITIONS = 0x1;
-		var ASSBIN_MESH_HAS_NORMALS = 0x2;
-		var ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS = 0x4;
-		var ASSBIN_MESH_HAS_TEXCOORD_BASE = 0x100;
-		var ASSBIN_MESH_HAS_COLOR_BASE = 0x10000;
-		var AI_MAX_NUMBER_OF_COLOR_SETS = 1;
-		var AI_MAX_NUMBER_OF_TEXTURECOORDS = 4;
-		//var aiLightSource_UNDEFINED = 0x0;
-		//! A directional light source has a well-defined direction
-		//! but is infinitely far away. That's quite a good
-		//! approximation for sun light.
-		var aiLightSource_DIRECTIONAL = 0x1;
-		//! A point light source has a well-defined position
-		//! in space but no direction - it emits light in all
-		//! directions. A normal bulb is a point light.
-		//var aiLightSource_POINT = 0x2;
-		//! A spot light source emits light in a specific
-		//! angle. It has a position and a direction it is pointing to.
-		//! A good example for a spot light is a light spot in
-		//! sport arenas.
-		var aiLightSource_SPOT = 0x3;
-		//! The generic light level of the world, including the bounces
-		//! of all other lightsources.
-		//! Typically, there's at most one ambient light in a scene.
-		//! This light type doesn't have a valid position, direction, or
-		//! other properties, just a color.
-		//var aiLightSource_AMBIENT = 0x4;
-		/** Flat shading. Shading is done on per-face base,
-		 *  diffuse only. Also known as 'faceted shading'.
-		 */
-		//var aiShadingMode_Flat = 0x1;
-		/** Simple Gouraud shading.
-		 */
-		//var aiShadingMode_Gouraud = 0x2;
-		/** Phong-Shading -
-		 */
-		//var aiShadingMode_Phong = 0x3;
-		/** Phong-Blinn-Shading
-		 */
-		//var aiShadingMode_Blinn = 0x4;
-		/** Toon-Shading per pixel
-		 *
-		 *  Also known as 'comic' shader.
-		 */
-		//var aiShadingMode_Toon = 0x5;
-		/** OrenNayar-Shading per pixel
-		 *
-		 *  Extension to standard Lambertian shading, taking the
-		 *  roughness of the material into account
-		 */
-		//var aiShadingMode_OrenNayar = 0x6;
-		/** Minnaert-Shading per pixel
-		 *
-		 *  Extension to standard Lambertian shading, taking the
-		 *  "darkness" of the material into account
-		 */
-		//var aiShadingMode_Minnaert = 0x7;
-		/** CookTorrance-Shading per pixel
-		 *
-		 *  Special shader for metallic surfaces.
-		 */
-		//var aiShadingMode_CookTorrance = 0x8;
-		/** No shading at all. Constant light influence of 1.0.
-		 */
-		//var aiShadingMode_NoShading = 0x9;
-		/** Fresnel shading
-		 */
-		//var aiShadingMode_Fresnel = 0xa;
-		//var aiTextureType_NONE = 0x0;
-		/** The texture is combined with the result of the diffuse
-		 *  lighting equation.
-		 */
-		var aiTextureType_DIFFUSE = 0x1;
-		/** The texture is combined with the result of the specular
-		 *  lighting equation.
-		 */
-		//var aiTextureType_SPECULAR = 0x2;
-		/** The texture is combined with the result of the ambient
-		 *  lighting equation.
-		 */
-		//var aiTextureType_AMBIENT = 0x3;
-		/** The texture is added to the result of the lighting
-		 *  calculation. It isn't influenced by incoming light.
-		 */
-		//var aiTextureType_EMISSIVE = 0x4;
-		/** The texture is a height map.
-		 *
-		 *  By convention, higher gray-scale values stand for
-		 *  higher elevations from the base height.
-		 */
-		//var aiTextureType_HEIGHT = 0x5;
-		/** The texture is a (tangent space) normal-map.
-		 *
-		 *  Again, there are several conventions for tangent-space
-		 *  normal maps. Assimp does (intentionally) not
-		 *  distinguish here.
-		 */
-		var aiTextureType_NORMALS = 0x6;
-		/** The texture defines the glossiness of the material.
-		 *
-		 *  The glossiness is in fact the exponent of the specular
-		 *  (phong) lighting equation. Usually there is a conversion
-		 *  function defined to map the linear color values in the
-		 *  texture to a suitable exponent. Have fun.
-		 */
-		//var aiTextureType_SHININESS = 0x7;
-		/** The texture defines per-pixel opacity.
-		 *
-		 *  Usually 'white' means opaque and 'black' means
-		 *  'transparency'. Or quite the opposite. Have fun.
-		 */
-		var aiTextureType_OPACITY = 0x8;
-		/** Displacement texture
-		 *
-		 *  The exact purpose and format is application-dependent.
-		 *  Higher color values stand for higher vertex displacements.
-		 */
-		//var aiTextureType_DISPLACEMENT = 0x9;
-		/** Lightmap texture (aka Ambient Occlusion)
-		 *
-		 *  Both 'Lightmaps' and dedicated 'ambient occlusion maps' are
-		 *  covered by this material property. The texture contains a
-		 *  scaling value for the final color value of a pixel. Its
-		 *  intensity is not affected by incoming light.
-		 */
-		var aiTextureType_LIGHTMAP = 0xA;
-		/** Reflection texture
-		 *
-		 * Contains the color of a perfect mirror reflection.
-		 * Rarely used, almost never for real-time applications.
-		 */
-		//var aiTextureType_REFLECTION = 0xB;
-		/** Unknown texture
-		 *
-		 *  A texture reference that does not match any of the definitions
-		 *  above is considered to be 'unknown'. It is still imported,
-		 *  but is excluded from any further postprocessing.
-		 */
-		//var aiTextureType_UNKNOWN = 0xC;
-		var BONESPERVERT = 4;
-
-		function ASSBIN_MESH_HAS_TEXCOORD( n ) {
-
-			return ASSBIN_MESH_HAS_TEXCOORD_BASE << n;
-
-		}
-
-		function ASSBIN_MESH_HAS_COLOR( n ) {
-
-			return ASSBIN_MESH_HAS_COLOR_BASE << n;
-
-		}
-
-		function markBones( scene ) {
-
-			for ( var i in scene.mMeshes ) {
-
-				var mesh = scene.mMeshes[ i ];
-				for ( var k in mesh.mBones ) {
-
-					var boneNode = scene.findNode( mesh.mBones[ k ].mName );
-					if ( boneNode )
-						boneNode.isBone = true;
-
-				}
-
-			}
-
-		}
-
-		function cloneTreeToBones( root, scene ) {
-
-			var rootBone = new THREE.Bone();
-			rootBone.matrix.copy( root.matrix );
-			rootBone.matrixWorld.copy( root.matrixWorld );
-			rootBone.position.copy( root.position );
-			rootBone.quaternion.copy( root.quaternion );
-			rootBone.scale.copy( root.scale );
-			scene.nodeCount ++;
-			rootBone.name = 'bone_' + root.name + scene.nodeCount.toString();
-
-			if ( ! scene.nodeToBoneMap[ root.name ] )
-				scene.nodeToBoneMap[ root.name ] = [];
-			scene.nodeToBoneMap[ root.name ].push( rootBone );
-			for ( var i in root.children ) {
-
-				var child = cloneTreeToBones( root.children[ i ], scene );
-				rootBone.add( child );
-
-			}
-
-			return rootBone;
-
-		}
-
-		function sortWeights( indexes, weights ) {
-
-			var pairs = [];
-
-			for ( var i = 0; i < indexes.length; i ++ ) {
-
-				pairs.push( {
-					i: indexes[ i ],
-					w: weights[ i ]
-				} );
-
-			}
-
-			pairs.sort( function ( a, b ) {
-
-				return b.w - a.w;
-
-			 } );
-
-			while ( pairs.length < 4 ) {
-
-				pairs.push( {
-					i: 0,
-					w: 0
-				} );
-
-			}
-
-			if ( pairs.length > 4 )
-				pairs.length = 4;
-			var sum = 0;
-
-			for ( var i = 0; i < 4; i ++ ) {
-
-				sum += pairs[ i ].w * pairs[ i ].w;
-
-			}
-
-			sum = Math.sqrt( sum );
-
-			for ( var i = 0; i < 4; i ++ ) {
-
-				pairs[ i ].w = pairs[ i ].w / sum;
-				indexes[ i ] = pairs[ i ].i;
-				weights[ i ] = pairs[ i ].w;
-
-			}
-
-		}
-
-		function findMatchingBone( root, name ) {
-
-			if ( root.name.indexOf( 'bone_' + name ) == 0 )
-				return root;
-
-			for ( var i in root.children ) {
-
-				var ret = findMatchingBone( root.children[ i ], name );
-
-				if ( ret )
-					return ret;
-
-			}
-
-			return undefined;
-
-		}
-
-		function aiMesh() {
-
-			this.mPrimitiveTypes = 0;
-			this.mNumVertices = 0;
-			this.mNumFaces = 0;
-			this.mNumBones = 0;
-			this.mMaterialIndex = 0;
-			this.mVertices = [];
-			this.mNormals = [];
-			this.mTangents = [];
-			this.mBitangents = [];
-			this.mColors = [
-				[]
-			];
-			this.mTextureCoords = [
-				[]
-			];
-			this.mFaces = [];
-			this.mBones = [];
-			this.hookupSkeletons = function ( scene ) {
-
-				if ( this.mBones.length == 0 ) return;
-
-				var allBones = [];
-				var offsetMatrix = [];
-				var skeletonRoot = scene.findNode( this.mBones[ 0 ].mName );
-
-				while ( skeletonRoot.mParent && skeletonRoot.mParent.isBone ) {
-
-					skeletonRoot = skeletonRoot.mParent;
-
-				}
-
-				var threeSkeletonRoot = skeletonRoot.toTHREE( scene );
-				var threeSkeletonRootBone = cloneTreeToBones( threeSkeletonRoot, scene );
-				this.threeNode.add( threeSkeletonRootBone );
-
-				for ( var i = 0; i < this.mBones.length; i ++ ) {
-
-					var bone = findMatchingBone( threeSkeletonRootBone, this.mBones[ i ].mName );
-
-					if ( bone ) {
-
-						var tbone = bone;
-						allBones.push( tbone );
-						//tbone.matrixAutoUpdate = false;
-						offsetMatrix.push( this.mBones[ i ].mOffsetMatrix.toTHREE() );
-
-					} else {
-
-						var skeletonRoot = scene.findNode( this.mBones[ i ].mName );
-						if ( ! skeletonRoot ) return;
-						var threeSkeletonRoot = skeletonRoot.toTHREE( scene );
-						var threeSkeletonRootBone = cloneTreeToBones( threeSkeletonRoot, scene );
-						this.threeNode.add( threeSkeletonRootBone );
-						var bone = findMatchingBone( threeSkeletonRootBone, this.mBones[ i ].mName );
-						var tbone = bone;
-						allBones.push( tbone );
-						//tbone.matrixAutoUpdate = false;
-						offsetMatrix.push( this.mBones[ i ].mOffsetMatrix.toTHREE() );
-
-					}
-
-				}
-
-				var skeleton = new THREE.Skeleton( allBones, offsetMatrix );
-
-				this.threeNode.bind( skeleton, new THREE.Matrix4() );
-				this.threeNode.material.skinning = true;
-
-			};
-
-			this.toTHREE = function ( scene ) {
-
-				if ( this.threeNode ) return this.threeNode;
-				var geometry = new THREE.BufferGeometry();
-				var mat;
-				if ( scene.mMaterials[ this.mMaterialIndex ] )
-					mat = scene.mMaterials[ this.mMaterialIndex ].toTHREE( scene );
-				else
-					mat = new THREE.MeshLambertMaterial();
-				geometry.setIndex( new THREE.BufferAttribute( new Uint32Array( this.mIndexArray ), 1 ) );
-				geometry.setAttribute( 'position', new THREE.BufferAttribute( this.mVertexBuffer, 3 ) );
-				if ( this.mNormalBuffer && this.mNormalBuffer.length > 0 )
-					geometry.setAttribute( 'normal', new THREE.BufferAttribute( this.mNormalBuffer, 3 ) );
-				if ( this.mColorBuffer && this.mColorBuffer.length > 0 )
-					geometry.setAttribute( 'color', new THREE.BufferAttribute( this.mColorBuffer, 4 ) );
-				if ( this.mTexCoordsBuffers[ 0 ] && this.mTexCoordsBuffers[ 0 ].length > 0 )
-					geometry.setAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( this.mTexCoordsBuffers[ 0 ] ), 2 ) );
-				if ( this.mTexCoordsBuffers[ 1 ] && this.mTexCoordsBuffers[ 1 ].length > 0 )
-					geometry.setAttribute( 'uv1', new THREE.BufferAttribute( new Float32Array( this.mTexCoordsBuffers[ 1 ] ), 2 ) );
-				if ( this.mTangentBuffer && this.mTangentBuffer.length > 0 )
-					geometry.setAttribute( 'tangents', new THREE.BufferAttribute( this.mTangentBuffer, 3 ) );
-				if ( this.mBitangentBuffer && this.mBitangentBuffer.length > 0 )
-					geometry.setAttribute( 'bitangents', new THREE.BufferAttribute( this.mBitangentBuffer, 3 ) );
-				if ( this.mBones.length > 0 ) {
-
-					var weights = [];
-					var bones = [];
-
-					for ( var i = 0; i < this.mBones.length; i ++ ) {
-
-						for ( var j = 0; j < this.mBones[ i ].mWeights.length; j ++ ) {
-
-							var weight = this.mBones[ i ].mWeights[ j ];
-							if ( weight ) {
-
-								if ( ! weights[ weight.mVertexId ] ) weights[ weight.mVertexId ] = [];
-								if ( ! bones[ weight.mVertexId ] ) bones[ weight.mVertexId ] = [];
-								weights[ weight.mVertexId ].push( weight.mWeight );
-								bones[ weight.mVertexId ].push( parseInt( i ) );
-
-							}
-
-						}
-
-					}
-
-					for ( var i in bones ) {
-
-						sortWeights( bones[ i ], weights[ i ] );
-
-					}
-
-					var _weights = [];
-					var _bones = [];
-
-					for ( var i = 0; i < weights.length; i ++ ) {
-
-						for ( var j = 0; j < 4; j ++ ) {
-
-							if ( weights[ i ] && bones[ i ] ) {
-
-								_weights.push( weights[ i ][ j ] );
-								_bones.push( bones[ i ][ j ] );
-
-							} else {
-
-								_weights.push( 0 );
-								_bones.push( 0 );
-
-							}
-
-						}
-
-					}
-
-					geometry.setAttribute( 'skinWeight', new THREE.BufferAttribute( new Float32Array( _weights ), BONESPERVERT ) );
-					geometry.setAttribute( 'skinIndex', new THREE.BufferAttribute( new Float32Array( _bones ), BONESPERVERT ) );
-
-				}
-
-				var mesh;
-
-				if ( this.mBones.length == 0 )
-					mesh = new THREE.Mesh( geometry, mat );
-
-				if ( this.mBones.length > 0 ) {
-
-					mesh = new THREE.SkinnedMesh( geometry, mat );
-					mesh.normalizeSkinWeights();
-
-				}
-
-				this.threeNode = mesh;
-				//mesh.matrixAutoUpdate = false;
-				return mesh;
-
-			};
-
-		}
-
-		function aiFace() {
-
-			this.mNumIndices = 0;
-			this.mIndices = [];
-
-		}
-
-		function aiVector3D() {
-
-			this.x = 0;
-			this.y = 0;
-			this.z = 0;
-
-			this.toTHREE = function () {
-
-				return new THREE.Vector3( this.x, this.y, this.z );
-
-			};
-
-		}
-
-		function aiColor3D() {
-
-			this.r = 0;
-			this.g = 0;
-			this.b = 0;
-			this.a = 0;
-			this.toTHREE = function () {
-
-				return new THREE.Color( this.r, this.g, this.b );
-
-			};
-
-		}
-
-		function aiQuaternion() {
-
-			this.x = 0;
-			this.y = 0;
-			this.z = 0;
-			this.w = 0;
-			this.toTHREE = function () {
-
-				return new THREE.Quaternion( this.x, this.y, this.z, this.w );
-
-			};
-
-		}
-
-		function aiVertexWeight() {
-
-			this.mVertexId = 0;
-			this.mWeight = 0;
-
-		}
-
-		function aiString() {
-
-			this.data = [];
-			this.toString = function () {
-
-				var str = '';
-				this.data.forEach( function ( i ) {
-
-					str += ( String.fromCharCode( i ) );
-
-				} );
-				return str.replace( /[^\x20-\x7E]+/g, '' );
-
-			};
-
-		}
-
-		function aiVectorKey() {
-
-			this.mTime = 0;
-			this.mValue = null;
-
-		}
-
-		function aiQuatKey() {
-
-			this.mTime = 0;
-			this.mValue = null;
-
-		}
-
-		function aiNode() {
-
-			this.mName = '';
-			this.mTransformation = [];
-			this.mNumChildren = 0;
-			this.mNumMeshes = 0;
-			this.mMeshes = [];
-			this.mChildren = [];
-			this.toTHREE = function ( scene ) {
-
-				if ( this.threeNode ) return this.threeNode;
-				var o = new THREE.Object3D();
-				o.name = this.mName;
-				o.matrix = this.mTransformation.toTHREE();
-
-				for ( var i = 0; i < this.mChildren.length; i ++ ) {
-
-					o.add( this.mChildren[ i ].toTHREE( scene ) );
-
-				}
-
-				for ( var i = 0; i < this.mMeshes.length; i ++ ) {
-
-					o.add( scene.mMeshes[ this.mMeshes[ i ] ].toTHREE( scene ) );
-
-				}
-
-				this.threeNode = o;
-				//o.matrixAutoUpdate = false;
-				o.matrix.decompose( o.position, o.quaternion, o.scale );
-				return o;
-
-			};
-
-		}
-
-		function aiBone() {
-
-			this.mName = '';
-			this.mNumWeights = 0;
-			this.mOffsetMatrix = 0;
-
-		}
-
-		function aiMaterialProperty() {
-
-			this.mKey = '';
-			this.mSemantic = 0;
-			this.mIndex = 0;
-			this.mData = [];
-			this.mDataLength = 0;
-			this.mType = 0;
-			this.dataAsColor = function () {
-
-				var array = ( new Uint8Array( this.mData ) ).buffer;
-				var reader = new DataView( array );
-				var r = reader.getFloat32( 0, true );
-				var g = reader.getFloat32( 4, true );
-				var b = reader.getFloat32( 8, true );
-				//var a = reader.getFloat32(12, true);
-				return new THREE.Color( r, g, b );
-
-			};
-
-			this.dataAsFloat = function () {
-
-				var array = ( new Uint8Array( this.mData ) ).buffer;
-				var reader = new DataView( array );
-				var r = reader.getFloat32( 0, true );
-				return r;
-
-			};
-
-			this.dataAsBool = function () {
-
-				var array = ( new Uint8Array( this.mData ) ).buffer;
-				var reader = new DataView( array );
-				var r = reader.getFloat32( 0, true );
-				return !! r;
-
-			};
-
-			this.dataAsString = function () {
-
-				var s = new aiString();
-				s.data = this.mData;
-				return s.toString();
-
-			};
-
-			this.dataAsMap = function () {
-
-				var s = new aiString();
-				s.data = this.mData;
-				var path = s.toString();
-				path = path.replace( /\\/g, '/' );
-
-				if ( path.indexOf( '/' ) != - 1 ) {
-
-					path = path.substr( path.lastIndexOf( '/' ) + 1 );
-
-				}
-
-				return textureLoader.load( path );
-
-			};
-
-		}
-
-		var namePropMapping = {
-
-			'?mat.name': 'name',
-			'$mat.shadingm': 'shading',
-			'$mat.twosided': 'twoSided',
-			'$mat.wireframe': 'wireframe',
-			'$clr.ambient': 'ambient',
-			'$clr.diffuse': 'color',
-			'$clr.specular': 'specular',
-			'$clr.emissive': 'emissive',
-			'$clr.transparent': 'transparent',
-			'$clr.reflective': 'reflect',
-			'$mat.shininess': 'shininess',
-			'$mat.reflectivity': 'reflectivity',
-			'$mat.refracti': 'refraction',
-			'$tex.file': 'map'
-
-		};
-
-		var nameTypeMapping = {
-
-			'?mat.name': 'string',
-			'$mat.shadingm': 'bool',
-			'$mat.twosided': 'bool',
-			'$mat.wireframe': 'bool',
-			'$clr.ambient': 'color',
-			'$clr.diffuse': 'color',
-			'$clr.specular': 'color',
-			'$clr.emissive': 'color',
-			'$clr.transparent': 'color',
-			'$clr.reflective': 'color',
-			'$mat.shininess': 'float',
-			'$mat.reflectivity': 'float',
-			'$mat.refracti': 'float',
-			'$tex.file': 'map'
-
-		};
-
-		function aiMaterial() {
-
-			this.mNumAllocated = 0;
-			this.mNumProperties = 0;
-			this.mProperties = [];
-			this.toTHREE = function () {
-
-				var mat = new THREE.MeshPhongMaterial();
-
-				for ( var i = 0; i < this.mProperties.length; i ++ ) {
-
-					if ( nameTypeMapping[ this.mProperties[ i ].mKey ] == 'float' )
-						mat[ namePropMapping[ this.mProperties[ i ].mKey ] ] = this.mProperties[ i ].dataAsFloat();
-					if ( nameTypeMapping[ this.mProperties[ i ].mKey ] == 'color' )
-						mat[ namePropMapping[ this.mProperties[ i ].mKey ] ] = this.mProperties[ i ].dataAsColor();
-					if ( nameTypeMapping[ this.mProperties[ i ].mKey ] == 'bool' )
-						mat[ namePropMapping[ this.mProperties[ i ].mKey ] ] = this.mProperties[ i ].dataAsBool();
-					if ( nameTypeMapping[ this.mProperties[ i ].mKey ] == 'string' )
-						mat[ namePropMapping[ this.mProperties[ i ].mKey ] ] = this.mProperties[ i ].dataAsString();
-					if ( nameTypeMapping[ this.mProperties[ i ].mKey ] == 'map' ) {
-
-						var prop = this.mProperties[ i ];
-						if ( prop.mSemantic == aiTextureType_DIFFUSE )
-							mat.map = this.mProperties[ i ].dataAsMap();
-						if ( prop.mSemantic == aiTextureType_NORMALS )
-							mat.normalMap = this.mProperties[ i ].dataAsMap();
-						if ( prop.mSemantic == aiTextureType_LIGHTMAP )
-							mat.lightMap = this.mProperties[ i ].dataAsMap();
-						if ( prop.mSemantic == aiTextureType_OPACITY )
-							mat.alphaMap = this.mProperties[ i ].dataAsMap();
-
-					}
-
-				}
-
-				mat.ambient.r = .53;
-				mat.ambient.g = .53;
-				mat.ambient.b = .53;
-				mat.color.r = 1;
-				mat.color.g = 1;
-				mat.color.b = 1;
-				return mat;
-
-			};
-
-		}
-
-
-		function veclerp( v1, v2, l ) {
-
-			var v = new THREE.Vector3();
-			var lm1 = 1 - l;
-			v.x = v1.x * l + v2.x * lm1;
-			v.y = v1.y * l + v2.y * lm1;
-			v.z = v1.z * l + v2.z * lm1;
-			return v;
-
-		}
-
-		function quatlerp( q1, q2, l ) {
-
-			return q1.clone().slerp( q2, 1 - l );
-
-		}
-
-		function sampleTrack( keys, time, lne, lerp ) {
-
-			if ( keys.length == 1 ) return keys[ 0 ].mValue.toTHREE();
-
-			var dist = Infinity;
-			var key = null;
-			var nextKey = null;
-
-			for ( var i = 0; i < keys.length; i ++ ) {
-
-				var timeDist = Math.abs( keys[ i ].mTime - time );
-
-				if ( timeDist < dist && keys[ i ].mTime <= time ) {
-
-					dist = timeDist;
-					key = keys[ i ];
-					nextKey = keys[ i + 1 ];
-
-				}
-
-			}
-
-			if ( ! key ) {
-
-				return null;
-
-			} else if ( nextKey ) {
-
-				var dT = nextKey.mTime - key.mTime;
-				var T = key.mTime - time;
-				var l = T / dT;
-
-				return lerp( key.mValue.toTHREE(), nextKey.mValue.toTHREE(), l );
-
-			} else {
-
-				nextKey = keys[ 0 ].clone();
-				nextKey.mTime += lne;
-
-				var dT = nextKey.mTime - key.mTime;
-				var T = key.mTime - time;
-				var l = T / dT;
-
-				return lerp( key.mValue.toTHREE(), nextKey.mValue.toTHREE(), l );
-
-			}
-
-		}
-
-		function aiNodeAnim() {
-
-			this.mNodeName = '';
-			this.mNumPositionKeys = 0;
-			this.mNumRotationKeys = 0;
-			this.mNumScalingKeys = 0;
-			this.mPositionKeys = [];
-			this.mRotationKeys = [];
-			this.mScalingKeys = [];
-			this.mPreState = '';
-			this.mPostState = '';
-			this.init = function ( tps ) {
-
-				if ( ! tps ) tps = 1;
-
-				function t( t ) {
-
-					t.mTime /= tps;
-
-				}
-
-				this.mPositionKeys.forEach( t );
-				this.mRotationKeys.forEach( t );
-				this.mScalingKeys.forEach( t );
-
-			};
-
-			this.sortKeys = function () {
-
-				function comp( a, b ) {
-
-					return a.mTime - b.mTime;
-
-				}
-
-				this.mPositionKeys.sort( comp );
-				this.mRotationKeys.sort( comp );
-				this.mScalingKeys.sort( comp );
-
-			};
-
-			this.getLength = function () {
-
-				return Math.max(
-					Math.max.apply( null, this.mPositionKeys.map( function ( a ) {
-
-						return a.mTime;
-
-					} ) ),
-					Math.max.apply( null, this.mRotationKeys.map( function ( a ) {
-
-						return a.mTime;
-
-					} ) ),
-					Math.max.apply( null, this.mScalingKeys.map( function ( a ) {
-
-						return a.mTime;
-
-				 } ) )
-				);
-
-			};
-
-			this.toTHREE = function ( o ) {
-
-				this.sortKeys();
-				var length = this.getLength();
-				var track = new Virtulous.KeyFrameTrack();
-
-				for ( var i = 0; i < length; i += .05 ) {
-
-					var matrix = new THREE.Matrix4();
-					var time = i;
-					var pos = sampleTrack( this.mPositionKeys, time, length, veclerp );
-					var scale = sampleTrack( this.mScalingKeys, time, length, veclerp );
-					var rotation = sampleTrack( this.mRotationKeys, time, length, quatlerp );
-					matrix.compose( pos, rotation, scale );
-
-					var key = new Virtulous.KeyFrame( time, matrix );
-					track.addKey( key );
-
-				}
-
-				track.target = o.findNode( this.mNodeName ).toTHREE();
-
-				var tracks = [ track ];
-
-				if ( o.nodeToBoneMap[ this.mNodeName ] ) {
-
-					for ( var i = 0; i < o.nodeToBoneMap[ this.mNodeName ].length; i ++ ) {
-
-						var t2 = track.clone();
-						t2.target = o.nodeToBoneMap[ this.mNodeName ][ i ];
-						tracks.push( t2 );
-
-					}
-
-				}
-
-				return tracks;
-
-			};
-
-		}
-
-		function aiAnimation() {
-
-			this.mName = '';
-			this.mDuration = 0;
-			this.mTicksPerSecond = 0;
-			this.mNumChannels = 0;
-			this.mChannels = [];
-			this.toTHREE = function ( root ) {
-
-				var animationHandle = new Virtulous.Animation();
-
-				for ( var i in this.mChannels ) {
-
-					this.mChannels[ i ].init( this.mTicksPerSecond );
-
-					var tracks = this.mChannels[ i ].toTHREE( root );
-
-					for ( var j in tracks ) {
-
-						tracks[ j ].init();
-						animationHandle.addTrack( tracks[ j ] );
-
-					}
-
-				}
-
-				animationHandle.length = Math.max.apply( null, animationHandle.tracks.map( function ( e ) {
-
-					return e.length;
-
-				} ) );
-				return animationHandle;
-
-			};
-
-		}
-
-		function aiTexture() {
-
-			this.mWidth = 0;
-			this.mHeight = 0;
-			this.texAchFormatHint = [];
-			this.pcData = [];
-
-		}
-
-		function aiLight() {
-
-			this.mName = '';
-			this.mType = 0;
-			this.mAttenuationConstant = 0;
-			this.mAttenuationLinear = 0;
-			this.mAttenuationQuadratic = 0;
-			this.mAngleInnerCone = 0;
-			this.mAngleOuterCone = 0;
-			this.mColorDiffuse = null;
-			this.mColorSpecular = null;
-			this.mColorAmbient = null;
-
-		}
-
-		function aiCamera() {
-
-			this.mName = '';
-			this.mPosition = null;
-			this.mLookAt = null;
-			this.mUp = null;
-			this.mHorizontalFOV = 0;
-			this.mClipPlaneNear = 0;
-			this.mClipPlaneFar = 0;
-			this.mAspect = 0;
-
-		}
-
-		function aiScene() {
-
-			this.versionMajor = 0;
-			this.versionMinor = 0;
-			this.versionRevision = 0;
-			this.compileFlags = 0;
-			this.mFlags = 0;
-			this.mNumMeshes = 0;
-			this.mNumMaterials = 0;
-			this.mNumAnimations = 0;
-			this.mNumTextures = 0;
-			this.mNumLights = 0;
-			this.mNumCameras = 0;
-			this.mRootNode = null;
-			this.mMeshes = [];
-			this.mMaterials = [];
-			this.mAnimations = [];
-			this.mLights = [];
-			this.mCameras = [];
-			this.nodeToBoneMap = {};
-			this.findNode = function ( name, root ) {
-
-				if ( ! root ) {
-
-					root = this.mRootNode;
-
-				}
-
-				if ( root.mName == name ) {
-
-					return root;
-
-				}
-
-				for ( var i = 0; i < root.mChildren.length; i ++ ) {
-
-					var ret = this.findNode( name, root.mChildren[ i ] );
-					if ( ret ) return ret;
-
-				}
-
-				return null;
-
-			};
-
-			this.toTHREE = function () {
-
-				this.nodeCount = 0;
-
-				markBones( this );
-
-				var o = this.mRootNode.toTHREE( this );
-
-				for ( var i in this.mMeshes )
-					this.mMeshes[ i ].hookupSkeletons( this );
-
-				if ( this.mAnimations.length > 0 ) {
-
-					var a = this.mAnimations[ 0 ].toTHREE( this );
-
-				}
-
-				return { object: o, animation: a };
-
-			};
-
-		}
-
-		function aiMatrix4() {
-
-			this.elements = [
-				[],
-				[],
-				[],
-				[]
-			];
-			this.toTHREE = function () {
-
-				var m = new THREE.Matrix4();
-
-				for ( var i = 0; i < 4; ++ i ) {
-
-					for ( var i2 = 0; i2 < 4; ++ i2 ) {
-
-						m.elements[ i * 4 + i2 ] = this.elements[ i2 ][ i ];
-
-					}
-
-				}
-
-				return m;
-
-			};
-
-		}
-
-		var littleEndian = true;
-
-		function readFloat( dataview ) {
-
-			var val = dataview.getFloat32( dataview.readOffset, littleEndian );
-			dataview.readOffset += 4;
-			return val;
-
-		}
-
-		function Read_double( dataview ) {
-
-			var val = dataview.getFloat64( dataview.readOffset, littleEndian );
-			dataview.readOffset += 8;
-			return val;
-
-		}
-
-		function Read_uint8_t( dataview ) {
-
-			var val = dataview.getUint8( dataview.readOffset );
-			dataview.readOffset += 1;
-			return val;
-
-		}
-
-		function Read_uint16_t( dataview ) {
-
-			var val = dataview.getUint16( dataview.readOffset, littleEndian );
-			dataview.readOffset += 2;
-			return val;
-
-		}
-
-		function Read_unsigned_int( dataview ) {
-
-			var val = dataview.getUint32( dataview.readOffset, littleEndian );
-			dataview.readOffset += 4;
-			return val;
-
-		}
-
-		function Read_uint32_t( dataview ) {
-
-			var val = dataview.getUint32( dataview.readOffset, littleEndian );
-			dataview.readOffset += 4;
-			return val;
-
-		}
-
-		function Read_aiVector3D( stream ) {
-
-			var v = new aiVector3D();
-			v.x = readFloat( stream );
-			v.y = readFloat( stream );
-			v.z = readFloat( stream );
-			return v;
-
-		}
-
-		function Read_aiColor3D( stream ) {
-
-			var c = new aiColor3D();
-			c.r = readFloat( stream );
-			c.g = readFloat( stream );
-			c.b = readFloat( stream );
-			return c;
-
-		}
-
-		function Read_aiQuaternion( stream ) {
-
-			var v = new aiQuaternion();
-			v.w = readFloat( stream );
-			v.x = readFloat( stream );
-			v.y = readFloat( stream );
-			v.z = readFloat( stream );
-			return v;
-
-		}
-
-		function Read_aiString( stream ) {
-
-			var s = new aiString();
-			var stringlengthbytes = Read_unsigned_int( stream );
-			stream.ReadBytes( s.data, 1, stringlengthbytes );
-			return s.toString();
-
-		}
-
-		function Read_aiVertexWeight( stream ) {
-
-			var w = new aiVertexWeight();
-			w.mVertexId = Read_unsigned_int( stream );
-			w.mWeight = readFloat( stream );
-			return w;
-
-		}
-
-		function Read_aiMatrix4x4( stream ) {
-
-			var m = new aiMatrix4();
-
-			for ( var i = 0; i < 4; ++ i ) {
-
-				for ( var i2 = 0; i2 < 4; ++ i2 ) {
-
-					m.elements[ i ][ i2 ] = readFloat( stream );
-
-				}
-
-			}
-
-			return m;
-
-		}
-
-		function Read_aiVectorKey( stream ) {
-
-			var v = new aiVectorKey();
-			v.mTime = Read_double( stream );
-			v.mValue = Read_aiVector3D( stream );
-			return v;
-
-		}
-
-		function Read_aiQuatKey( stream ) {
-
-			var v = new aiQuatKey();
-			v.mTime = Read_double( stream );
-			v.mValue = Read_aiQuaternion( stream );
-			return v;
-
-		}
-
-		function ReadArray_aiVertexWeight( stream, data, size ) {
-
-			for ( var i = 0; i < size; i ++ ) data[ i ] = Read_aiVertexWeight( stream );
-
-		}
-
-		function ReadArray_aiVectorKey( stream, data, size ) {
-
-			for ( var i = 0; i < size; i ++ ) data[ i ] = Read_aiVectorKey( stream );
-
-		}
-
-		function ReadArray_aiQuatKey( stream, data, size ) {
-
-			for ( var i = 0; i < size; i ++ ) data[ i ] = Read_aiQuatKey( stream );
-
-		}
-
-		function ReadBounds( stream, T /*p*/, n ) {
-
-			// not sure what to do here, the data isn't really useful.
-			return stream.Seek( sizeof( T ) * n, aiOrigin_CUR ); // eslint-disable-line no-undef
-
-		}
-
-		function ai_assert( bool ) {
-
-			if ( ! bool )
-				throw ( 'asset failed' );
-
-		}
-
-		function ReadBinaryNode( stream, parent, depth ) {
-
-			var chunkID = Read_uint32_t( stream );
-			ai_assert( chunkID == ASSBIN_CHUNK_AINODE );
-			/*uint32_t size =*/
-			Read_uint32_t( stream );
-			var node = new aiNode();
-			node.mParent = parent;
-			node.mDepth = depth;
-			node.mName = Read_aiString( stream );
-			node.mTransformation = Read_aiMatrix4x4( stream );
-			node.mNumChildren = Read_unsigned_int( stream );
-			node.mNumMeshes = Read_unsigned_int( stream );
-
-			if ( node.mNumMeshes ) {
-
-				node.mMeshes = [];
-
-				for ( var i = 0; i < node.mNumMeshes; ++ i ) {
-
-					node.mMeshes[ i ] = Read_unsigned_int( stream );
-
-				}
-
-			}
-
-			if ( node.mNumChildren ) {
-
-				node.mChildren = [];
-
-				for ( var i = 0; i < node.mNumChildren; ++ i ) {
-
-					var node2 = ReadBinaryNode( stream, node, depth ++ );
-					node.mChildren[ i ] = node2;
-
-				}
-
-			}
-
-			return node;
-
-		}
-
-		// -----------------------------------------------------------------------------------
-
-		function ReadBinaryBone( stream, b ) {
-
-			var chunkID = Read_uint32_t( stream );
-			ai_assert( chunkID == ASSBIN_CHUNK_AIBONE );
-			/*uint32_t size =*/
-			Read_uint32_t( stream );
-			b.mName = Read_aiString( stream );
-			b.mNumWeights = Read_unsigned_int( stream );
-			b.mOffsetMatrix = Read_aiMatrix4x4( stream );
-			// for the moment we write dumb min/max values for the bones, too.
-			// maybe I'll add a better, hash-like solution later
-			if ( shortened ) {
-
-				ReadBounds( stream, b.mWeights, b.mNumWeights );
-
-			} else {
-
-				// else write as usual
-
-				b.mWeights = [];
-				ReadArray_aiVertexWeight( stream, b.mWeights, b.mNumWeights );
-
-			}
-
-			return b;
-
-		}
-
-		function ReadBinaryMesh( stream, mesh ) {
-
-			var chunkID = Read_uint32_t( stream );
-			ai_assert( chunkID == ASSBIN_CHUNK_AIMESH );
-			/*uint32_t size =*/
-			Read_uint32_t( stream );
-			mesh.mPrimitiveTypes = Read_unsigned_int( stream );
-			mesh.mNumVertices = Read_unsigned_int( stream );
-			mesh.mNumFaces = Read_unsigned_int( stream );
-			mesh.mNumBones = Read_unsigned_int( stream );
-			mesh.mMaterialIndex = Read_unsigned_int( stream );
-			mesh.mNumUVComponents = [];
-			// first of all, write bits for all existent vertex components
-			var c = Read_unsigned_int( stream );
-
-			if ( c & ASSBIN_MESH_HAS_POSITIONS ) {
-
-				if ( shortened ) {
-
-					ReadBounds( stream, mesh.mVertices, mesh.mNumVertices );
-
-				} else {
-
-					// else write as usual
-
-					mesh.mVertices = [];
-					mesh.mVertexBuffer = stream.subArray32( stream.readOffset, stream.readOffset + mesh.mNumVertices * 3 * 4 );
-					stream.Seek( mesh.mNumVertices * 3 * 4, aiOrigin_CUR );
-
-				}
-
-			}
-
-			if ( c & ASSBIN_MESH_HAS_NORMALS ) {
-
-				if ( shortened ) {
-
-					ReadBounds( stream, mesh.mNormals, mesh.mNumVertices );
-
-				} else {
-
-					// else write as usual
-
-					mesh.mNormals = [];
-					mesh.mNormalBuffer = stream.subArray32( stream.readOffset, stream.readOffset + mesh.mNumVertices * 3 * 4 );
-					stream.Seek( mesh.mNumVertices * 3 * 4, aiOrigin_CUR );
-
-				}
-
-			}
-
-			if ( c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS ) {
-
-				if ( shortened ) {
-
-					ReadBounds( stream, mesh.mTangents, mesh.mNumVertices );
-					ReadBounds( stream, mesh.mBitangents, mesh.mNumVertices );
-
-				} else {
-
-					// else write as usual
-
-					mesh.mTangents = [];
-					mesh.mTangentBuffer = stream.subArray32( stream.readOffset, stream.readOffset + mesh.mNumVertices * 3 * 4 );
-					stream.Seek( mesh.mNumVertices * 3 * 4, aiOrigin_CUR );
-					mesh.mBitangents = [];
-					mesh.mBitangentBuffer = stream.subArray32( stream.readOffset, stream.readOffset + mesh.mNumVertices * 3 * 4 );
-					stream.Seek( mesh.mNumVertices * 3 * 4, aiOrigin_CUR );
-
-				}
-
-			}
-
-			for ( var n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++ n ) {
-
-				if ( ! ( c & ASSBIN_MESH_HAS_COLOR( n ) ) ) break;
-
-				if ( shortened ) {
-
-					ReadBounds( stream, mesh.mColors[ n ], mesh.mNumVertices );
-
-				} else {
-
-					// else write as usual
-
-					mesh.mColors[ n ] = [];
-					mesh.mColorBuffer = stream.subArray32( stream.readOffset, stream.readOffset + mesh.mNumVertices * 4 * 4 );
-					stream.Seek( mesh.mNumVertices * 4 * 4, aiOrigin_CUR );
-
-				}
-
-			}
-
-			mesh.mTexCoordsBuffers = [];
-
-			for ( var n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++ n ) {
-
-				if ( ! ( c & ASSBIN_MESH_HAS_TEXCOORD( n ) ) ) break;
-
-				// write number of UV components
-				mesh.mNumUVComponents[ n ] = Read_unsigned_int( stream );
-
-				if ( shortened ) {
-
-					ReadBounds( stream, mesh.mTextureCoords[ n ], mesh.mNumVertices );
-
-				} else {
-
-					// else write as usual
-
-					mesh.mTextureCoords[ n ] = [];
-					//note that assbin always writes 3d texcoords
-					mesh.mTexCoordsBuffers[ n ] = [];
-
-					for ( var uv = 0; uv < mesh.mNumVertices; uv ++ ) {
-
-						mesh.mTexCoordsBuffers[ n ].push( readFloat( stream ) );
-						mesh.mTexCoordsBuffers[ n ].push( readFloat( stream ) );
-						readFloat( stream );
-
-					}
-
-				}
-
-			}
-
-			// write faces. There are no floating-point calculations involved
-			// in these, so we can write a simple hash over the face data
-			// to the dump file. We generate a single 32 Bit hash for 512 faces
-			// using Assimp's standard hashing function.
-			if ( shortened ) {
-
-				Read_unsigned_int( stream );
-
-			} else {
-
-				// else write as usual
-
-				// if there are less than 2^16 vertices, we can simply use 16 bit integers ...
-				mesh.mFaces = [];
-				mesh.mIndexArray = [];
-
-				for ( var i = 0; i < mesh.mNumFaces; ++ i ) {
-
-					var f = mesh.mFaces[ i ] = new aiFace();
-					// BOOST_STATIC_ASSERT(AI_MAX_FACE_INDICES <= 0xffff);
-					f.mNumIndices = Read_uint16_t( stream );
-					f.mIndices = [];
-
-					for ( var a = 0; a < f.mNumIndices; ++ a ) {
-
-						if ( mesh.mNumVertices < ( 1 << 16 ) ) {
-
-							f.mIndices[ a ] = Read_uint16_t( stream );
-
-						} else {
-
-							f.mIndices[ a ] = Read_unsigned_int( stream );
-
-						}
-
-
-
-					}
-
-					if ( f.mNumIndices === 3 ) {
-
-						mesh.mIndexArray.push( f.mIndices[ 0 ] );
-						mesh.mIndexArray.push( f.mIndices[ 1 ] );
-						mesh.mIndexArray.push( f.mIndices[ 2 ] );
-
-					} else if ( f.mNumIndices === 4 ) {
-
-						mesh.mIndexArray.push( f.mIndices[ 0 ] );
-						mesh.mIndexArray.push( f.mIndices[ 1 ] );
-						mesh.mIndexArray.push( f.mIndices[ 2 ] );
-						mesh.mIndexArray.push( f.mIndices[ 2 ] );
-						mesh.mIndexArray.push( f.mIndices[ 3 ] );
-						mesh.mIndexArray.push( f.mIndices[ 0 ] );
-
-					} else {
-
-						throw ( new Error( 'Sorry, can\'t currently triangulate polys. Use the triangulate preprocessor in Assimp.' ) );
-
-					}
-
-
-
-				}
-
-			}
-
-			// write bones
-			if ( mesh.mNumBones ) {
-
-				mesh.mBones = [];
-
-				for ( var a = 0; a < mesh.mNumBones; ++ a ) {
-
-					mesh.mBones[ a ] = new aiBone();
-					ReadBinaryBone( stream, mesh.mBones[ a ] );
-
-				}
-
-			}
-
-		}
-
-		function ReadBinaryMaterialProperty( stream, prop ) {
-
-			var chunkID = Read_uint32_t( stream );
-			ai_assert( chunkID == ASSBIN_CHUNK_AIMATERIALPROPERTY );
-			/*uint32_t size =*/
-			Read_uint32_t( stream );
-			prop.mKey = Read_aiString( stream );
-			prop.mSemantic = Read_unsigned_int( stream );
-			prop.mIndex = Read_unsigned_int( stream );
-			prop.mDataLength = Read_unsigned_int( stream );
-			prop.mType = Read_unsigned_int( stream );
-			prop.mData = [];
-			stream.ReadBytes( prop.mData, 1, prop.mDataLength );
-
-		}
-
-		// -----------------------------------------------------------------------------------
-
-		function ReadBinaryMaterial( stream, mat ) {
-
-			var chunkID = Read_uint32_t( stream );
-			ai_assert( chunkID == ASSBIN_CHUNK_AIMATERIAL );
-			/*uint32_t size =*/
-			Read_uint32_t( stream );
-			mat.mNumAllocated = mat.mNumProperties = Read_unsigned_int( stream );
-
-			if ( mat.mNumProperties ) {
-
-				if ( mat.mProperties ) {
-
-					delete mat.mProperties;
-
-				}
-
-				mat.mProperties = [];
-
-				for ( var i = 0; i < mat.mNumProperties; ++ i ) {
-
-					mat.mProperties[ i ] = new aiMaterialProperty();
-					ReadBinaryMaterialProperty( stream, mat.mProperties[ i ] );
-
-				}
-
-			}
-
-		}
-
-		function ReadBinaryNodeAnim( stream, nd ) {
-
-			var chunkID = Read_uint32_t( stream );
-			ai_assert( chunkID == ASSBIN_CHUNK_AINODEANIM );
-			/*uint32_t size =*/
-			Read_uint32_t( stream );
-			nd.mNodeName = Read_aiString( stream );
-			nd.mNumPositionKeys = Read_unsigned_int( stream );
-			nd.mNumRotationKeys = Read_unsigned_int( stream );
-			nd.mNumScalingKeys = Read_unsigned_int( stream );
-			nd.mPreState = Read_unsigned_int( stream );
-			nd.mPostState = Read_unsigned_int( stream );
-
-			if ( nd.mNumPositionKeys ) {
-
-				if ( shortened ) {
-
-					ReadBounds( stream, nd.mPositionKeys, nd.mNumPositionKeys );
-
-				} else {
-
-					// else write as usual
-
-					nd.mPositionKeys = [];
-					ReadArray_aiVectorKey( stream, nd.mPositionKeys, nd.mNumPositionKeys );
-
-				}
-
-			}
-
-			if ( nd.mNumRotationKeys ) {
-
-				if ( shortened ) {
-
-					ReadBounds( stream, nd.mRotationKeys, nd.mNumRotationKeys );
-
-				} else {
-
-		 			// else write as usual
-
-					nd.mRotationKeys = [];
-					ReadArray_aiQuatKey( stream, nd.mRotationKeys, nd.mNumRotationKeys );
-
-				}
-
-			}
-
-			if ( nd.mNumScalingKeys ) {
-
-				if ( shortened ) {
-
-					ReadBounds( stream, nd.mScalingKeys, nd.mNumScalingKeys );
-
-				} else {
-
-	 				// else write as usual
-
-					nd.mScalingKeys = [];
-					ReadArray_aiVectorKey( stream, nd.mScalingKeys, nd.mNumScalingKeys );
-
-				}
-
-			}
-
-		}
-
-		function ReadBinaryAnim( stream, anim ) {
-
-			var chunkID = Read_uint32_t( stream );
-			ai_assert( chunkID == ASSBIN_CHUNK_AIANIMATION );
-			/*uint32_t size =*/
-			Read_uint32_t( stream );
-			anim.mName = Read_aiString( stream );
-			anim.mDuration = Read_double( stream );
-			anim.mTicksPerSecond = Read_double( stream );
-			anim.mNumChannels = Read_unsigned_int( stream );
-
-			if ( anim.mNumChannels ) {
-
-				anim.mChannels = [];
-
-				for ( var a = 0; a < anim.mNumChannels; ++ a ) {
-
-					anim.mChannels[ a ] = new aiNodeAnim();
-					ReadBinaryNodeAnim( stream, anim.mChannels[ a ] );
-
-				}
-
-			}
-
-		}
-
-		function ReadBinaryTexture( stream, tex ) {
-
-			var chunkID = Read_uint32_t( stream );
-			ai_assert( chunkID == ASSBIN_CHUNK_AITEXTURE );
-			/*uint32_t size =*/
-			Read_uint32_t( stream );
-			tex.mWidth = Read_unsigned_int( stream );
-			tex.mHeight = Read_unsigned_int( stream );
-			stream.ReadBytes( tex.achFormatHint, 1, 4 );
-
-			if ( ! shortened ) {
-
-				if ( ! tex.mHeight ) {
-
-					tex.pcData = [];
-					stream.ReadBytes( tex.pcData, 1, tex.mWidth );
-
-				} else {
-
-					tex.pcData = [];
-					stream.ReadBytes( tex.pcData, 1, tex.mWidth * tex.mHeight * 4 );
-
-				}
-
-			}
-
-		}
-
-		function ReadBinaryLight( stream, l ) {
-
-			var chunkID = Read_uint32_t( stream );
-			ai_assert( chunkID == ASSBIN_CHUNK_AILIGHT );
-			/*uint32_t size =*/
-			Read_uint32_t( stream );
-			l.mName = Read_aiString( stream );
-			l.mType = Read_unsigned_int( stream );
-
-			if ( l.mType != aiLightSource_DIRECTIONAL ) {
-
-				l.mAttenuationConstant = readFloat( stream );
-				l.mAttenuationLinear = readFloat( stream );
-				l.mAttenuationQuadratic = readFloat( stream );
-
-			}
-
-			l.mColorDiffuse = Read_aiColor3D( stream );
-			l.mColorSpecular = Read_aiColor3D( stream );
-			l.mColorAmbient = Read_aiColor3D( stream );
-
-			if ( l.mType == aiLightSource_SPOT ) {
-
-				l.mAngleInnerCone = readFloat( stream );
-				l.mAngleOuterCone = readFloat( stream );
-
-			}
-
-		}
-
-		function ReadBinaryCamera( stream, cam ) {
-
-			var chunkID = Read_uint32_t( stream );
-			ai_assert( chunkID == ASSBIN_CHUNK_AICAMERA );
-			/*uint32_t size =*/
-			Read_uint32_t( stream );
-			cam.mName = Read_aiString( stream );
-			cam.mPosition = Read_aiVector3D( stream );
-			cam.mLookAt = Read_aiVector3D( stream );
-			cam.mUp = Read_aiVector3D( stream );
-			cam.mHorizontalFOV = readFloat( stream );
-			cam.mClipPlaneNear = readFloat( stream );
-			cam.mClipPlaneFar = readFloat( stream );
-			cam.mAspect = readFloat( stream );
-
-		}
-
-		function ReadBinaryScene( stream, scene ) {
-
-			var chunkID = Read_uint32_t( stream );
-			ai_assert( chunkID == ASSBIN_CHUNK_AISCENE );
-			/*uint32_t size =*/
-			Read_uint32_t( stream );
-			scene.mFlags = Read_unsigned_int( stream );
-			scene.mNumMeshes = Read_unsigned_int( stream );
-			scene.mNumMaterials = Read_unsigned_int( stream );
-			scene.mNumAnimations = Read_unsigned_int( stream );
-			scene.mNumTextures = Read_unsigned_int( stream );
-			scene.mNumLights = Read_unsigned_int( stream );
-			scene.mNumCameras = Read_unsigned_int( stream );
-			// Read node graph
-			scene.mRootNode = new aiNode();
-			scene.mRootNode = ReadBinaryNode( stream, null, 0 );
-			// Read all meshes
-			if ( scene.mNumMeshes ) {
-
-				scene.mMeshes = [];
-
-				for ( var i = 0; i < scene.mNumMeshes; ++ i ) {
-
-					scene.mMeshes[ i ] = new aiMesh();
-					ReadBinaryMesh( stream, scene.mMeshes[ i ] );
-
-				}
-
-			}
-
-			// Read materials
-			if ( scene.mNumMaterials ) {
-
-				scene.mMaterials = [];
-
-				for ( var i = 0; i < scene.mNumMaterials; ++ i ) {
-
-					scene.mMaterials[ i ] = new aiMaterial();
-					ReadBinaryMaterial( stream, scene.mMaterials[ i ] );
-
-				}
-
-			}
-
-			// Read all animations
-			if ( scene.mNumAnimations ) {
-
-				scene.mAnimations = [];
-
-				for ( var i = 0; i < scene.mNumAnimations; ++ i ) {
-
-					scene.mAnimations[ i ] = new aiAnimation();
-					ReadBinaryAnim( stream, scene.mAnimations[ i ] );
-
-				}
-
-			}
-
-			// Read all textures
-			if ( scene.mNumTextures ) {
-
-				scene.mTextures = [];
-
-				for ( var i = 0; i < scene.mNumTextures; ++ i ) {
-
-					scene.mTextures[ i ] = new aiTexture();
-					ReadBinaryTexture( stream, scene.mTextures[ i ] );
-
-				}
-
-			}
-
-			// Read lights
-			if ( scene.mNumLights ) {
-
-				scene.mLights = [];
-
-				for ( var i = 0; i < scene.mNumLights; ++ i ) {
-
-					scene.mLights[ i ] = new aiLight();
-					ReadBinaryLight( stream, scene.mLights[ i ] );
-
-				}
-
-			}
-
-			// Read cameras
-			if ( scene.mNumCameras ) {
-
-				scene.mCameras = [];
-
-				for ( var i = 0; i < scene.mNumCameras; ++ i ) {
-
-					scene.mCameras[ i ] = new aiCamera();
-					ReadBinaryCamera( stream, scene.mCameras[ i ] );
-
-				}
-
-			}
-
-		}
-
-		var aiOrigin_CUR = 0;
-		var aiOrigin_BEG = 1;
-
-		function extendStream( stream ) {
-
-			stream.readOffset = 0;
-			stream.Seek = function ( off, ori ) {
-
-				if ( ori == aiOrigin_CUR ) {
-
-					stream.readOffset += off;
-
-				}
-
-				if ( ori == aiOrigin_BEG ) {
-
-					stream.readOffset = off;
-
-				}
-
-			};
-
-			stream.ReadBytes = function ( buff, size, n ) {
-
-				var bytes = size * n;
-				for ( var i = 0; i < bytes; i ++ )
-					buff[ i ] = Read_uint8_t( this );
-
-			};
-
-			stream.subArray32 = function ( start, end ) {
-
-				var buff = this.buffer;
-				var newbuff = buff.slice( start, end );
-				return new Float32Array( newbuff );
-
-			};
-
-			stream.subArrayUint16 = function ( start, end ) {
-
-				var buff = this.buffer;
-				var newbuff = buff.slice( start, end );
-				return new Uint16Array( newbuff );
-
-			};
-
-			stream.subArrayUint8 = function ( start, end ) {
-
-				var buff = this.buffer;
-				var newbuff = buff.slice( start, end );
-				return new Uint8Array( newbuff );
-
-			};
-
-			stream.subArrayUint32 = function ( start, end ) {
-
-				var buff = this.buffer;
-				var newbuff = buff.slice( start, end );
-				return new Uint32Array( newbuff );
-
-			};
-
-		}
-
-		var shortened, compressed;
-
-		function InternReadFile( pFiledata ) {
-
-			var pScene = new aiScene();
-			var stream = new DataView( pFiledata );
-			extendStream( stream );
-			stream.Seek( 44, aiOrigin_CUR ); // signature
-			/*unsigned int versionMajor =*/
-			pScene.versionMajor = Read_unsigned_int( stream );
-			/*unsigned int versionMinor =*/
-			pScene.versionMinor = Read_unsigned_int( stream );
-			/*unsigned int versionRevision =*/
-			pScene.versionRevision = Read_unsigned_int( stream );
-			/*unsigned int compileFlags =*/
-			pScene.compileFlags = Read_unsigned_int( stream );
-			shortened = Read_uint16_t( stream ) > 0;
-			compressed = Read_uint16_t( stream ) > 0;
-			if ( shortened )
-				throw 'Shortened binaries are not supported!';
-			stream.Seek( 256, aiOrigin_CUR ); // original filename
-			stream.Seek( 128, aiOrigin_CUR ); // options
-			stream.Seek( 64, aiOrigin_CUR ); // padding
-			if ( compressed ) {
-
-				var uncompressedSize = Read_uint32_t( stream );
-				var compressedSize = stream.FileSize() - stream.Tell();
-				var compressedData = [];
-				stream.Read( compressedData, 1, compressedSize );
-				var uncompressedData = [];
-				uncompress( uncompressedData, uncompressedSize, compressedData, compressedSize ); // eslint-disable-line no-undef
-				var buff = new ArrayBuffer( uncompressedData );
-				ReadBinaryScene( buff, pScene );
-
-			} else {
-
-				ReadBinaryScene( stream, pScene );
-
-			}
-
-			return pScene.toTHREE();
-
-		}
-
-		return InternReadFile( buffer );
-
-	}
-
-} );

+ 52 - 4
examples/js/loaders/MMDLoader.js

@@ -583,6 +583,8 @@ THREE.MMDLoader = ( function () {
 				var boneData = data.bones[ i ];
 
 				var bone = {
+					index: i,
+					transformationClass: boneData.transformationClass,
 					parent: boneData.parentIndex,
 					name: boneData.name,
 					pos: boneData.position.slice( 0, 3 ),
@@ -691,6 +693,10 @@ THREE.MMDLoader = ( function () {
 
 					iks.push( param );
 
+					// Save the reference even from bone data for efficiently
+					// simulating PMX animation system
+					bones[ i ].ik = param;
+
 				}
 
 			}
@@ -699,6 +705,9 @@ THREE.MMDLoader = ( function () {
 
 			if ( data.metadata.format === 'pmx' ) {
 
+				// bone index -> grant entry map
+				var grantEntryMap = {};
+
 				for ( var i = 0; i < data.metadata.boneCount; i ++ ) {
 
 					var boneData = data.bones[ i ];
@@ -716,15 +725,54 @@ THREE.MMDLoader = ( function () {
 						transformationClass: boneData.transformationClass
 					};
 
-					grants.push( param );
+					grantEntryMap[ i ] = { parent: null, children: [], param: param, visited: false };
 
 				}
 
-				grants.sort( function ( a, b ) {
+				var rootEntry = { parent: null, children: [], param: null, visited: false };
 
-					return a.transformationClass - b.transformationClass;
+				// Build a tree representing grant hierarchy
 
-				} );
+				for ( var boneIndex in grantEntryMap ) {
+
+					var grantEntry = grantEntryMap[ boneIndex ];
+					var parentGrantEntry = grantEntryMap[ grantEntry.parentIndex ] || rootEntry;
+
+					grantEntry.parent = parentGrantEntry;
+					parentGrantEntry.children.push( grantEntry );
+
+				}
+
+				// Sort grant parameters from parents to children because
+				// grant uses parent's transform that parent's grant is already applied
+				// so grant should be applied in order from parents to children
+
+				function traverse( entry ) {
+
+					if ( entry.param ) {
+
+						grants.push( entry.param );
+
+						// Save the reference even from bone data for efficiently
+						// simulating PMX animation system
+						bones[ entry.param.index ].grant = entry.param;
+
+					}
+
+					entry.visited = true;
+
+					for ( var i = 0, il = entry.children.length; i < il; i ++ ) {
+
+						var child = entry.children[ i ];
+
+						// Cut off a loop if exists. (Is a grant loop invalid?)
+						if ( ! child.visited ) traverse( child );
+
+					}
+
+				}
+
+				traverse( rootEntry );
 
 			}
 

+ 464 - 16
examples/js/loaders/SVGLoader.js

@@ -383,7 +383,7 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
 						break;
 
 					case 'A':
-						var numbers = parseFloats( data );
+						var numbers = parseFloats( data, [ 3, 4 ], 7 );
 
 						for ( var j = 0, jl = numbers.length; j < jl; j += 7 ) {
 
@@ -575,7 +575,7 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
 						break;
 
 					case 'a':
-						var numbers = parseFloats( data );
+						var numbers = parseFloats( data, [ 3, 4 ], 7 );
 
 						for ( var j = 0, jl = numbers.length; j < jl; j += 7 ) {
 
@@ -846,9 +846,9 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
 
 		function parseCircleNode( node ) {
 
-			var x = parseFloatWithUnits( node.getAttribute( 'cx' ) );
-			var y = parseFloatWithUnits( node.getAttribute( 'cy' ) );
-			var r = parseFloatWithUnits( node.getAttribute( 'r' ) );
+			var x = parseFloatWithUnits( node.getAttribute( 'cx' ) || 0 );
+			var y = parseFloatWithUnits( node.getAttribute( 'cy' ) || 0 );
+			var r = parseFloatWithUnits( node.getAttribute( 'r' ) || 0 );
 
 			var subpath = new THREE.Path();
 			subpath.absarc( x, y, r, 0, Math.PI * 2 );
@@ -862,10 +862,10 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
 
 		function parseEllipseNode( node ) {
 
-			var x = parseFloatWithUnits( node.getAttribute( 'cx' ) );
-			var y = parseFloatWithUnits( node.getAttribute( 'cy' ) );
-			var rx = parseFloatWithUnits( node.getAttribute( 'rx' ) );
-			var ry = parseFloatWithUnits( node.getAttribute( 'ry' ) );
+			var x = parseFloatWithUnits( node.getAttribute( 'cx' ) || 0 );
+			var y = parseFloatWithUnits( node.getAttribute( 'cy' ) || 0 );
+			var rx = parseFloatWithUnits( node.getAttribute( 'rx' ) || 0 );
+			var ry = parseFloatWithUnits( node.getAttribute( 'ry' ) || 0 );
 
 			var subpath = new THREE.Path();
 			subpath.absellipse( x, y, rx, ry, 0, Math.PI * 2 );
@@ -879,10 +879,10 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
 
 		function parseLineNode( node ) {
 
-			var x1 = parseFloatWithUnits( node.getAttribute( 'x1' ) );
-			var y1 = parseFloatWithUnits( node.getAttribute( 'y1' ) );
-			var x2 = parseFloatWithUnits( node.getAttribute( 'x2' ) );
-			var y2 = parseFloatWithUnits( node.getAttribute( 'y2' ) );
+			var x1 = parseFloatWithUnits( node.getAttribute( 'x1' ) || 0 );
+			var y1 = parseFloatWithUnits( node.getAttribute( 'y1' ) || 0 );
+			var x2 = parseFloatWithUnits( node.getAttribute( 'x2' ) || 0 );
+			var y2 = parseFloatWithUnits( node.getAttribute( 'y2' ) || 0 );
 
 			var path = new THREE.ShapePath();
 			path.moveTo( x1, y1 );
@@ -975,7 +975,7 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
 
 		// from https://github.com/ppvg/svg-numbers (MIT License)
 
-		function parseFloats( input ) {
+		function parseFloats( input, flags, stride ) {
 
 			if ( typeof input !== 'string' ) {
 
@@ -991,7 +991,8 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
 				SIGN: /[-+]/,
 				POINT: /\./,
 				COMMA: /,/,
-				EXP: /e/i
+				EXP: /e/i,
+				FLAGS: /[01]/
 			};
 
 			// States
@@ -1031,6 +1032,16 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
 
 				current = input[ i ];
 
+				// check for flags
+				if ( Array.isArray( flags ) && flags.includes( result.length % stride ) && RE.FLAGS.test( current ) ) {
+
+					state = INT;
+					number = current;
+					newNumber();
+					continue;
+
+				}
+
 				// parse until next number
 				if ( state === SEP ) {
 
@@ -1136,7 +1147,7 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
 				}
 
 				// parse exponent part
-				if ( state == EXP ) {
+				if ( state === EXP ) {
 
 					if ( RE.DIGIT.test( current ) ) {
 
@@ -1614,6 +1625,443 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
 
 } );
 
+THREE.SVGLoader.createShapes = function ( shapePath ) {
+
+	// Param shapePath: a shapepath as returned by the parse function of this class
+	// Returns Shape object
+
+	const BIGNUMBER = 999999999;
+
+	const IntersectionLocationType = {
+		ORIGIN: 0,
+		DESTINATION: 1,
+		BETWEEN: 2,
+		LEFT: 3,
+		RIGHT: 4,
+		BEHIND: 5,
+		BEYOND: 6
+	};
+
+	const classifyResult = {
+		loc: IntersectionLocationType.ORIGIN,
+		t: 0
+	};
+
+	function findEdgeIntersection( a0, a1, b0, b1 ) {
+
+		var x1 = a0.x;
+		var x2 = a1.x;
+		var x3 = b0.x;
+		var x4 = b1.x;
+		var y1 = a0.y;
+		var y2 = a1.y;
+		var y3 = b0.y;
+		var y4 = b1.y;
+		var nom1 = ( x4 - x3 ) * ( y1 - y3 ) - ( y4 - y3 ) * ( x1 - x3 );
+		var nom2 = ( x2 - x1 ) * ( y1 - y3 ) - ( y2 - y1 ) * ( x1 - x3 );
+		var denom = ( y4 - y3 ) * ( x2 - x1 ) - ( x4 - x3 ) * ( y2 - y1 );
+		var t1 = nom1 / denom;
+		var t2 = nom2 / denom;
+
+		if ( ( ( denom === 0 ) && ( nom1 !== 0 ) ) || ( t1 <= 0 ) || ( t1 >= 1 ) || ( t2 < 0 ) || ( t2 > 1 ) ) {
+
+			//1. lines are parallel or edges don't intersect
+
+			return null;
+
+		} else if ( ( nom1 === 0 ) && ( denom === 0 ) ) {
+
+			//2. lines are colinear
+
+			//check if endpoints of edge2 (b0-b1) lies on edge1 (a0-a1)
+			for ( var i = 0; i < 2; i ++ ) {
+
+				classifyPoint( i === 0 ? b0 : b1, a0, a1 );
+				//find position of this endpoints relatively to edge1
+				if ( classifyResult.loc == IntersectionLocationType.ORIGIN ) {
+
+					var point = ( i === 0 ? b0 : b1 );
+					return { x: point.x, y: point.y, t: classifyResult.t };
+
+				} else if ( classifyResult.loc == IntersectionLocationType.BETWEEN ) {
+
+					var x = + ( ( x1 + classifyResult.t * ( x2 - x1 ) ).toPrecision( 10 ) );
+					var y = + ( ( y1 + classifyResult.t * ( y2 - y1 ) ).toPrecision( 10 ) );
+					return { x: x, y: y, t: classifyResult.t, };
+
+				}
+
+			}
+
+			return null;
+
+		} else {
+
+			//3. edges intersect
+
+			for ( var i = 0; i < 2; i ++ ) {
+
+				classifyPoint( i === 0 ? b0 : b1, a0, a1 );
+
+				if ( classifyResult.loc == IntersectionLocationType.ORIGIN ) {
+
+					var point = ( i === 0 ? b0 : b1 );
+					return { x: point.x, y: point.y, t: classifyResult.t };
+
+				}
+
+			}
+
+			var x = + ( ( x1 + t1 * ( x2 - x1 ) ).toPrecision( 10 ) );
+			var y = + ( ( y1 + t1 * ( y2 - y1 ) ).toPrecision( 10 ) );
+			return { x: x, y: y, t: t1 };
+
+		}
+
+	}
+
+	function classifyPoint( p, edgeStart, edgeEnd ) {
+
+		var ax = edgeEnd.x - edgeStart.x;
+		var ay = edgeEnd.y - edgeStart.y;
+		var bx = p.x - edgeStart.x;
+		var by = p.y - edgeStart.y;
+		var sa = ax * by - bx * ay;
+
+		if ( ( p.x === edgeStart.x ) && ( p.y === edgeStart.y ) ) {
+
+			classifyResult.loc = IntersectionLocationType.ORIGIN;
+			classifyResult.t = 0;
+			return;
+
+		}
+
+		if ( ( p.x === edgeEnd.x ) && ( p.y === edgeEnd.y ) ) {
+
+			classifyResult.loc = IntersectionLocationType.DESTINATION;
+			classifyResult.t = 1;
+			return;
+
+		}
+
+		if ( sa < - Number.EPSILON ) {
+
+			classifyResult.loc = IntersectionLocationType.LEFT;
+			return;
+
+		}
+
+		if ( sa > Number.EPSILON ) {
+
+			classifyResult.loc = IntersectionLocationType.RIGHT;
+			return;
+
+
+		}
+
+		if ( ( ( ax * bx ) < 0 ) || ( ( ay * by ) < 0 ) ) {
+
+			classifyResult.loc = IntersectionLocationType.BEHIND;
+			return;
+
+		}
+
+		if ( ( Math.sqrt( ax * ax + ay * ay ) ) < ( Math.sqrt( bx * bx + by * by ) ) ) {
+
+			classifyResult.loc = IntersectionLocationType.BEYOND;
+			return;
+
+		}
+
+		var t;
+
+		if ( ax !== 0 ) {
+
+			t = bx / ax;
+
+		} else {
+
+			t = by / ay;
+
+		}
+
+		classifyResult.loc = IntersectionLocationType.BETWEEN;
+		classifyResult.t = t;
+
+	}
+
+	function getIntersections( path1, path2 ) {
+
+		const intersectionsRaw = [];
+		const intersections = [];
+
+		for ( let index = 1; index < path1.length; index ++ ) {
+
+			const path1EdgeStart = path1[ index - 1 ];
+			const path1EdgeEnd = path1[ index ];
+
+			for ( let index2 = 1; index2 < path2.length; index2 ++ ) {
+
+				const path2EdgeStart = path2[ index2 - 1 ];
+				const path2EdgeEnd = path2[ index2 ];
+
+				const intersection = findEdgeIntersection( path1EdgeStart, path1EdgeEnd, path2EdgeStart, path2EdgeEnd );
+
+				if ( intersection !== null && intersectionsRaw.find( i => i.t <= intersection.t + Number.EPSILON && i.t >= intersection.t - Number.EPSILON ) === undefined ) {
+
+					intersectionsRaw.push( intersection );
+					intersections.push( new THREE.Vector2( intersection.x, intersection.y ) );
+
+				}
+
+			}
+
+		}
+
+		return intersections;
+
+	}
+
+	function getScanlineIntersections( scanline, boundingBox, paths ) {
+
+		const center = new THREE.Vector2();
+		boundingBox.getCenter( center );
+
+		const allIntersections = [];
+
+		paths.forEach( path => {
+
+			// check if the center of the bounding box is in the bounding box of the paths.
+			// this is a pruning method to limit the search of intersections in paths that can't envelop of the current path.
+			// if a path envelops another path. The center of that oter path, has to be inside the bounding box of the enveloping path.
+			if ( path.boundingBox.containsPoint( center ) ) {
+
+				const intersections = getIntersections( scanline, path.points );
+
+				intersections.forEach( p => {
+
+					allIntersections.push( { identifier: path.identifier, isCW: path.isCW, point: p } );
+
+				} );
+
+			}
+
+		} );
+
+		allIntersections.sort( ( i1, i2 ) => {
+
+			return i1.point.x - i2.point.x;
+
+		} );
+
+		return allIntersections;
+
+	}
+
+	function isHoleTo( simplePath, allPaths, scanlineMinX, scanlineMaxX, _fillRule ) {
+
+		if ( _fillRule === null || _fillRule === undefined || _fillRule === '' ) {
+
+			_fillRule = 'nonzero';
+
+		}
+
+		const centerBoundingBox = new THREE.Vector2();
+		simplePath.boundingBox.getCenter( centerBoundingBox );
+
+		const scanline = [ new THREE.Vector2( scanlineMinX, centerBoundingBox.y ), new THREE.Vector2( scanlineMaxX, centerBoundingBox.y ) ];
+
+		const scanlineIntersections = getScanlineIntersections( scanline, simplePath.boundingBox, allPaths );
+
+		scanlineIntersections.sort( ( i1, i2 ) => {
+
+			return i1.point.x - i2.point.x;
+
+		} );
+
+		const baseIntersections = [];
+		const otherIntersections = [];
+
+		scanlineIntersections.forEach( i => {
+
+			if ( i.identifier === simplePath.identifier ) {
+
+				baseIntersections.push( i );
+
+			} else {
+
+				otherIntersections.push( i );
+
+			}
+
+		} );
+
+		const firstXOfPath = baseIntersections[ 0 ].point.x;
+
+		// build up the path hierarchy
+		const stack = [];
+		let i = 0;
+
+		while ( i < otherIntersections.length && otherIntersections[ i ].point.x < firstXOfPath ) {
+
+			if ( stack.length > 0 && stack[ stack.length - 1 ] === otherIntersections[ i ].identifier ) {
+
+				stack.pop();
+
+			} else {
+
+				stack.push( otherIntersections[ i ].identifier );
+
+			}
+
+			i ++;
+
+		}
+
+		stack.push( simplePath.identifier );
+
+		if ( _fillRule === 'evenodd' ) {
+
+			const isHole = stack.length % 2 === 0 ? true : false;
+			const isHoleFor = stack[ stack.length - 2 ];
+
+			return { identifier: simplePath.identifier, isHole: isHole, for: isHoleFor };
+
+		} else if ( _fillRule === 'nonzero' ) {
+
+			// check if path is a hole by counting the amount of paths with alternating rotations it has to cross.
+			let isHole = true;
+			let isHoleFor = null;
+			let lastCWValue = null;
+
+			for ( let i = 0; i < stack.length; i ++ ) {
+
+				const identifier = stack[ i ];
+				if ( isHole ) {
+
+					lastCWValue = allPaths[ identifier ].isCW;
+					isHole = false;
+					isHoleFor = identifier;
+
+				} else if ( lastCWValue !== allPaths[ identifier ].isCW ) {
+
+					lastCWValue = allPaths[ identifier ].isCW;
+					isHole = true;
+
+				}
+
+			}
+
+			return { identifier: simplePath.identifier, isHole: isHole, for: isHoleFor };
+
+		} else {
+
+			console.warn( 'fill-rule: "' + _fillRule + '" is currently not implemented.' );
+
+		}
+
+	}
+
+	// check for self intersecting paths
+	// TODO
+
+	// check intersecting paths
+	// TODO
+
+	// prepare paths for hole detection
+	let identifier = 0;
+
+	let scanlineMinX = BIGNUMBER;
+	let scanlineMaxX = - BIGNUMBER;
+
+	let simplePaths = shapePath.subPaths.map( p => {
+
+		const points = p.getPoints();
+		let maxY = - BIGNUMBER;
+		let minY = BIGNUMBER;
+		let maxX = - BIGNUMBER;
+		let minX = BIGNUMBER;
+
+      	//points.forEach(p => p.y *= -1);
+
+		for ( let i = 0; i < points.length; i ++ ) {
+
+			const p = points[ i ];
+
+			if ( p.y > maxY ) {
+
+				maxY = p.y;
+
+			}
+
+			if ( p.y < minY ) {
+
+				minY = p.y;
+
+			}
+
+			if ( p.x > maxX ) {
+
+				maxX = p.x;
+
+			}
+
+			if ( p.x < minX ) {
+
+				minX = p.x;
+
+			}
+
+		}
+
+		//
+		if ( scanlineMaxX <= maxX ) {
+
+			scanlineMaxX = maxX + 1;
+
+		}
+
+		if ( scanlineMinX >= minX ) {
+
+			scanlineMinX = minX - 1;
+
+		}
+
+		return { points: points, isCW: THREE.ShapeUtils.isClockWise( points ), identifier: identifier ++, boundingBox: new THREE.Box2( new THREE.Vector2( minX, minY ), new THREE.Vector2( maxX, maxY ) ) };
+
+	} );
+
+	simplePaths = simplePaths.filter( sp => sp.points.length > 0 );
+
+	// check if path is solid or a hole
+	const isAHole = simplePaths.map( p => isHoleTo( p, simplePaths, scanlineMinX, scanlineMaxX, shapePath.userData.style.fillRule ) );
+
+
+	const shapesToReturn = [];
+	simplePaths.forEach( p => {
+
+		const amIAHole = isAHole[ p.identifier ];
+
+		if ( ! amIAHole.isHole ) {
+
+			const shape = new THREE.Shape( p.points );
+			const holes = isAHole.filter( h => h.isHole && h.for === p.identifier );
+			holes.forEach( h => {
+
+				const path = simplePaths[ h.identifier ];
+				shape.holes.push( new THREE.Path( path.points ) );
+
+			} );
+			shapesToReturn.push( shape );
+
+		}
+
+	} );
+
+	return shapesToReturn;
+
+};
+
 THREE.SVGLoader.getStrokeStyle = function ( width, color, lineJoin, lineCap, miterLimit ) {
 
 	// Param width: Stroke width

+ 13 - 42
examples/js/loaders/TGALoader.js

@@ -1,41 +1,13 @@
 THREE.TGALoader = function ( manager ) {
 
-	THREE.Loader.call( this, manager );
+	THREE.DataTextureLoader.call( this, manager );
 
 };
 
-THREE.TGALoader.prototype = Object.assign( Object.create( THREE.Loader.prototype ), {
+THREE.TGALoader.prototype = Object.assign( Object.create( THREE.DataTextureLoader.prototype ), {
 
 	constructor: THREE.TGALoader,
 
-	load: function ( url, onLoad, onProgress, onError ) {
-
-		var scope = this;
-
-		var texture = new THREE.Texture();
-
-		var loader = new THREE.FileLoader( this.manager );
-		loader.setResponseType( 'arraybuffer' );
-		loader.setPath( this.path );
-		loader.setWithCredentials( this.withCredentials );
-
-		loader.load( url, function ( buffer ) {
-
-			texture.image = scope.parse( buffer );
-			texture.needsUpdate = true;
-
-			if ( onLoad !== undefined ) {
-
-				onLoad( texture );
-
-			}
-
-		}, onProgress, onError );
-
-		return texture;
-
-	},
-
 	parse: function ( buffer ) {
 
 		// reference from vthibault, https://github.com/vthibault/roBrowser/blob/master/src/Loaders/Targa.js
@@ -521,21 +493,20 @@ THREE.TGALoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
 
 		//
 
-		var useOffscreen = typeof OffscreenCanvas !== 'undefined';
-
-		var canvas = useOffscreen ? new OffscreenCanvas( header.width, header.height ) : document.createElement( 'canvas' );
-		canvas.width = header.width;
-		canvas.height = header.height;
-
-		var context = canvas.getContext( '2d' );
-		var imageData = context.createImageData( header.width, header.height );
-
+		var imageData = new Uint8Array( header.width * header.height * 4 );
 		var result = tgaParse( use_rle, use_pal, header, offset, content );
-		getTgaRGBA( imageData.data, header.width, header.height, result.pixel_data, result.palettes );
+		getTgaRGBA( imageData, header.width, header.height, result.pixel_data, result.palettes );
+
+		return {
 
-		context.putImageData( imageData, 0, 0 );
+			data: imageData,
+			width: header.width,
+			height: header.height,
+			flipY: true,
+			generateMipmaps: true,
+			minFilter: THREE.LinearMipmapLinearFilter,
 
-		return canvas;
+		};
 
 	}
 

+ 1 - 1
examples/js/misc/ConvexObjectBreaker.js

@@ -347,7 +347,7 @@ THREE.ConvexObjectBreaker.prototype = {
 					var intersection = new THREE.Vector3();
 					intersection = localPlane.intersectLine( this.tempLine1, intersection );
 
-					if ( intersection === undefined ) {
+					if ( intersection === null ) {
 
 						// Shouldn't happen
 						console.error( 'Internal error: segment does not intersect plane.' );

+ 0 - 18
examples/js/objects/Water.js

@@ -283,24 +283,6 @@ THREE.Water = function ( geometry, options ) {
 
 		// Render
 
-		if ( renderer.outputEncoding !== THREE.LinearEncoding ) {
-
-			console.warn( 'THREE.Water: WebGLRenderer must use LinearEncoding as outputEncoding.' );
-			scope.onBeforeRender = function () {};
-
-			return;
-
-		}
-
-		if ( renderer.toneMapping !== THREE.NoToneMapping ) {
-
-			console.warn( 'THREE.Water: WebGLRenderer must use NoToneMapping as toneMapping.' );
-			scope.onBeforeRender = function () {};
-
-			return;
-
-		}
-
 		var currentRenderTarget = renderer.getRenderTarget();
 
 		var currentXrEnabled = renderer.xr.enabled;

+ 6 - 1
examples/js/postprocessing/EffectComposer.js

@@ -261,7 +261,12 @@ Object.assign( THREE.Pass.prototype, {
 THREE.Pass.FullScreenQuad = ( function () {
 
 	var camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
-	var geometry = new THREE.PlaneGeometry( 2, 2 );
+
+	// https://github.com/mrdoob/three.js/pull/21358
+
+	var geometry = new THREE.BufferGeometry();
+	geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( [ - 1, 3, 0, - 1, - 1, 0, 3, - 1, 0 ], 3 ) );
+	geometry.setAttribute( 'uv', new THREE.Float32BufferAttribute( [ 0, 2, 0, 0, 2, 0 ], 2 ) );
 
 	var FullScreenQuad = function ( material ) {
 

+ 1 - 0
examples/js/postprocessing/OutlinePass.js

@@ -134,6 +134,7 @@ THREE.OutlinePass.prototype = Object.assign( Object.create( THREE.Pass.prototype
 	setSize: function ( width, height ) {
 
 		this.renderTargetMaskBuffer.setSize( width, height );
+		this.renderTargetDepthBuffer.setSize( width, height );
 
 		var resx = Math.round( width / this.downSampleRatio );
 		var resy = Math.round( height / this.downSampleRatio );

+ 11 - 1
examples/js/renderers/CSS2DRenderer.js

@@ -93,7 +93,17 @@ THREE.CSS2DRenderer = function () {
 
 			var element = object.element;
 
-			element.style.transform = 'translate(-50%,-50%) translate(' + ( vector.x * _widthHalf + _widthHalf ) + 'px,' + ( - vector.y * _heightHalf + _heightHalf ) + 'px)';
+			if ( /apple/i.test( navigator.vendor ) ) {
+
+				// https://github.com/mrdoob/three.js/issues/21415
+				element.style.transform = 'translate(-50%,-50%) translate(' + Math.round( vector.x * _widthHalf + _widthHalf ) + 'px,' + Math.round( - vector.y * _heightHalf + _heightHalf ) + 'px)';
+
+			} else {
+
+				element.style.transform = 'translate(-50%,-50%) translate(' + ( vector.x * _widthHalf + _widthHalf ) + 'px,' + ( - vector.y * _heightHalf + _heightHalf ) + 'px)';
+
+			}
+
 			element.style.display = ( object.visible && vector.z >= - 1 && vector.z <= 1 ) ? '' : 'none';
 
 			var objectData = {

+ 97 - 83
examples/jsm/animation/CCDIKSolver.js

@@ -53,12 +53,32 @@ var CCDIKSolver = ( function () {
 		constructor: CCDIKSolver,
 
 		/**
-		 * Update IK bones.
+		 * Update all IK bones.
 		 *
 		 * @return {CCDIKSolver}
 		 */
 		update: function () {
 
+			var iks = this.iks;
+
+			for ( var i = 0, il = iks.length; i < il; i ++ ) {
+
+				this.updateOne( iks[ i ] );
+
+			}
+
+			return this;
+
+		},
+
+		/**
+		 * Update one IK bone
+		 *
+		 * @param {Object} ik parameter
+		 * @return {CCDIKSolver}
+		 */
+		updateOne: function () {
+
 			var q = new Quaternion();
 			var targetPos = new Vector3();
 			var targetVec = new Vector3();
@@ -70,137 +90,131 @@ var CCDIKSolver = ( function () {
 			var axis = new Vector3();
 			var vector = new Vector3();
 
-			return function update() {
+			return function update( ik ) {
 
 				var bones = this.mesh.skeleton.bones;
-				var iks = this.iks;
 
 				// for reference overhead reduction in loop
 				var math = Math;
 
-				for ( var i = 0, il = iks.length; i < il; i ++ ) {
-
-					var ik = iks[ i ];
-					var effector = bones[ ik.effector ];
-					var target = bones[ ik.target ];
-
-					// don't use getWorldPosition() here for the performance
-					// because it calls updateMatrixWorld( true ) inside.
-					targetPos.setFromMatrixPosition( target.matrixWorld );
-
-					var links = ik.links;
-					var iteration = ik.iteration !== undefined ? ik.iteration : 1;
-
-					for ( var j = 0; j < iteration; j ++ ) {
+				var effector = bones[ ik.effector ];
+				var target = bones[ ik.target ];
 
-						var rotated = false;
+				// don't use getWorldPosition() here for the performance
+				// because it calls updateMatrixWorld( true ) inside.
+				targetPos.setFromMatrixPosition( target.matrixWorld );
 
-						for ( var k = 0, kl = links.length; k < kl; k ++ ) {
+				var links = ik.links;
+				var iteration = ik.iteration !== undefined ? ik.iteration : 1;
 
-							var link = bones[ links[ k ].index ];
+				for ( var i = 0; i < iteration; i ++ ) {
 
-							// skip this link and following links.
-							// this skip is used for MMD performance optimization.
-							if ( links[ k ].enabled === false ) break;
+					var rotated = false;
 
-							var limitation = links[ k ].limitation;
-							var rotationMin = links[ k ].rotationMin;
-							var rotationMax = links[ k ].rotationMax;
+					for ( var j = 0, jl = links.length; j < jl; j ++ ) {
 
-							// don't use getWorldPosition/Quaternion() here for the performance
-							// because they call updateMatrixWorld( true ) inside.
-							link.matrixWorld.decompose( linkPos, invLinkQ, linkScale );
-							invLinkQ.invert();
-							effectorPos.setFromMatrixPosition( effector.matrixWorld );
+						var link = bones[ links[ j ].index ];
 
-							// work in link world
-							effectorVec.subVectors( effectorPos, linkPos );
-							effectorVec.applyQuaternion( invLinkQ );
-							effectorVec.normalize();
+						// skip this link and following links.
+						// this skip is used for MMD performance optimization.
+						if ( links[ j ].enabled === false ) break;
 
-							targetVec.subVectors( targetPos, linkPos );
-							targetVec.applyQuaternion( invLinkQ );
-							targetVec.normalize();
+						var limitation = links[ j ].limitation;
+						var rotationMin = links[ j ].rotationMin;
+						var rotationMax = links[ j ].rotationMax;
 
-							var angle = targetVec.dot( effectorVec );
+						// don't use getWorldPosition/Quaternion() here for the performance
+						// because they call updateMatrixWorld( true ) inside.
+						link.matrixWorld.decompose( linkPos, invLinkQ, linkScale );
+						invLinkQ.invert();
+						effectorPos.setFromMatrixPosition( effector.matrixWorld );
 
-							if ( angle > 1.0 ) {
+						// work in link world
+						effectorVec.subVectors( effectorPos, linkPos );
+						effectorVec.applyQuaternion( invLinkQ );
+						effectorVec.normalize();
 
-								angle = 1.0;
+						targetVec.subVectors( targetPos, linkPos );
+						targetVec.applyQuaternion( invLinkQ );
+						targetVec.normalize();
 
-							} else if ( angle < - 1.0 ) {
+						var angle = targetVec.dot( effectorVec );
 
-								angle = - 1.0;
+						if ( angle > 1.0 ) {
 
-							}
+							angle = 1.0;
 
-							angle = math.acos( angle );
+						} else if ( angle < - 1.0 ) {
 
-							// skip if changing angle is too small to prevent vibration of bone
-							// Refer to http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mmd.three.js
-							if ( angle < 1e-5 ) continue;
+							angle = - 1.0;
 
-							if ( ik.minAngle !== undefined && angle < ik.minAngle ) {
+						}
 
-								angle = ik.minAngle;
+						angle = math.acos( angle );
 
-							}
+						// skip if changing angle is too small to prevent vibration of bone
+						// Refer to http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mmd.three.js
+						if ( angle < 1e-5 ) continue;
 
-							if ( ik.maxAngle !== undefined && angle > ik.maxAngle ) {
+						if ( ik.minAngle !== undefined && angle < ik.minAngle ) {
 
-								angle = ik.maxAngle;
+							angle = ik.minAngle;
 
-							}
+						}
 
-							axis.crossVectors( effectorVec, targetVec );
-							axis.normalize();
+						if ( ik.maxAngle !== undefined && angle > ik.maxAngle ) {
 
-							q.setFromAxisAngle( axis, angle );
-							link.quaternion.multiply( q );
+							angle = ik.maxAngle;
 
-							// TODO: re-consider the limitation specification
-							if ( limitation !== undefined ) {
+						}
 
-								var c = link.quaternion.w;
+						axis.crossVectors( effectorVec, targetVec );
+						axis.normalize();
 
-								if ( c > 1.0 ) c = 1.0;
+						q.setFromAxisAngle( axis, angle );
+						link.quaternion.multiply( q );
 
-								var c2 = math.sqrt( 1 - c * c );
-								link.quaternion.set( limitation.x * c2,
-								                     limitation.y * c2,
-								                     limitation.z * c2,
-								                     c );
+						// TODO: re-consider the limitation specification
+						if ( limitation !== undefined ) {
 
-							}
+							var c = link.quaternion.w;
 
-							if ( rotationMin !== undefined ) {
+							if ( c > 1.0 ) c = 1.0;
 
-								link.rotation.setFromVector3(
-									link.rotation
-										.toVector3( vector )
-										.max( rotationMin ) );
+							var c2 = math.sqrt( 1 - c * c );
+							link.quaternion.set( limitation.x * c2,
+							                     limitation.y * c2,
+							                     limitation.z * c2,
+							                     c );
 
-							}
+						}
 
-							if ( rotationMax !== undefined ) {
+						if ( rotationMin !== undefined ) {
 
-								link.rotation.setFromVector3(
-									link.rotation
-										.toVector3( vector )
-										.min( rotationMax ) );
+							link.rotation.setFromVector3(
+								link.rotation
+									.toVector3( vector )
+									.max( rotationMin ) );
 
-							}
+						}
 
-							link.updateMatrixWorld( true );
+						if ( rotationMax !== undefined ) {
 
-							rotated = true;
+							link.rotation.setFromVector3(
+								link.rotation
+									.toVector3( vector )
+									.min( rotationMax ) );
 
 						}
 
-						if ( ! rotated ) break;
+						link.updateMatrixWorld( true );
+
+						rotated = true;
 
 					}
 
+					if ( ! rotated ) break;
+
 				}
 
 				return this;

+ 234 - 41
examples/jsm/animation/MMDAnimationHelper.js

@@ -49,7 +49,9 @@ var MMDAnimationHelper = ( function () {
 			afterglow: params.afterglow !== undefined
 				? params.afterglow : 0.0,
 			resetPhysicsOnLoop: params.resetPhysicsOnLoop !== undefined
-				? params.resetPhysicsOnLoop : true
+				? params.resetPhysicsOnLoop : true,
+			pmxAnimation: params.pmxAnimation !== undefined
+				? params.pmxAnimation : false
 		};
 
 		this.enabled = {
@@ -226,15 +228,28 @@ var MMDAnimationHelper = ( function () {
 
 			mesh.updateMatrixWorld( true );
 
-			if ( params.ik !== false ) {
+			// PMX animation system special path
+			if ( this.configuration.pmxAnimation &&
+				mesh.geometry.userData.MMD && mesh.geometry.userData.MMD.format === 'pmx' ) {
 
-				this._createCCDIKSolver( mesh ).update( params.saveOriginalBonesBeforeIK ); // this param is experimental
+				var sortedBonesData = this._sortBoneDataArray( mesh.geometry.userData.MMD.bones.slice() );
+				var ikSolver = params.ik !== false ? this._createCCDIKSolver( mesh ) : null;
+				var grantSolver = params.grant !== false ? this.createGrantSolver( mesh ) : null;
+				this._animatePMXMesh( mesh, sortedBonesData, ikSolver, grantSolver );
 
-			}
+			} else {
+
+				if ( params.ik !== false ) {
+
+					this._createCCDIKSolver( mesh ).update();
 
-			if ( params.grant !== false ) {
+				}
+
+				if ( params.grant !== false ) {
 
-				this.createGrantSolver( mesh ).update();
+					this.createGrantSolver( mesh ).update();
+
+				}
 
 			}
 
@@ -524,28 +539,45 @@ var MMDAnimationHelper = ( function () {
 			var physics = objects.physics;
 			var looped = objects.looped;
 
-			// alternate solution to save/restore bones but less performant?
-			//mesh.pose();
-			//this._updatePropertyMixersBuffer( mesh );
-
 			if ( mixer && this.enabled.animation ) {
 
+				// alternate solution to save/restore bones but less performant?
+				//mesh.pose();
+				//this._updatePropertyMixersBuffer( mesh );
+
 				this._restoreBones( mesh );
 
 				mixer.update( delta );
 
 				this._saveBones( mesh );
 
-				if ( ikSolver && this.enabled.ik ) {
+				// PMX animation system special path
+				if ( this.configuration.pmxAnimation &&
+					mesh.geometry.userData.MMD && mesh.geometry.userData.MMD.format === 'pmx' ) {
 
-					mesh.updateMatrixWorld( true );
-					ikSolver.update();
+					if ( ! objects.sortedBonesData ) objects.sortedBonesData = this._sortBoneDataArray( mesh.geometry.userData.MMD.bones.slice() );
 
-				}
+					this._animatePMXMesh(
+						mesh,
+						objects.sortedBonesData,
+						ikSolver && this.enabled.ik ? ikSolver : null,
+						grantSolver && this.enabled.grant ? grantSolver : null
+					);
 
-				if ( grantSolver && this.enabled.grant ) {
+				} else {
 
-					grantSolver.update();
+					if ( ikSolver && this.enabled.ik ) {
+
+						mesh.updateMatrixWorld( true );
+						ikSolver.update();
+
+					}
+
+					if ( grantSolver && this.enabled.grant ) {
+
+						grantSolver.update();
+
+					}
 
 				}
 
@@ -568,6 +600,142 @@ var MMDAnimationHelper = ( function () {
 
 		},
 
+		// Sort bones in order by 1. transformationClass and 2. bone index.
+		// In PMX animation system, bone transformations should be processed
+		// in this order.
+		_sortBoneDataArray: function ( boneDataArray ) {
+
+			return boneDataArray.sort( function ( a, b ) {
+
+				if ( a.transformationClass !== b.transformationClass ) {
+
+					return a.transformationClass - b.transformationClass;
+
+				} else {
+
+					return a.index - b.index;
+
+				}
+
+			} );
+
+		},
+
+		// PMX Animation system is a bit too complex and doesn't great match to
+		// Three.js Animation system. This method attempts to simulate it as much as
+		// possible but doesn't perfectly simulate.
+		// This method is more costly than the regular one so
+		// you are recommended to set constructor parameter "pmxAnimation: true"
+		// only if your PMX model animation doesn't work well.
+		// If you need better method you would be required to write your own.
+		_animatePMXMesh: function () {
+
+			// Keep working quaternions for less GC
+			var quaternions = [];
+			var quaternionIndex = 0;
+
+			function getQuaternion() {
+
+				if ( quaternionIndex >= quaternions.length ) {
+
+					quaternions.push( new Quaternion() );
+
+				}
+
+				return quaternions[ quaternionIndex ++ ];
+
+			}
+
+			// Save rotation whose grant and IK are already applied
+			// used by grant children
+			var grantResultMap = new Map();
+
+			function updateOne( mesh, boneIndex, ikSolver, grantSolver ) {
+
+				var bones = mesh.skeleton.bones;
+				var bonesData = mesh.geometry.userData.MMD.bones;
+				var boneData = bonesData[ boneIndex ];
+				var bone = bones[ boneIndex ];
+
+				// Return if already updated by being referred as a grant parent.
+				if ( grantResultMap.has( boneIndex ) ) return;
+
+				var quaternion = getQuaternion();
+
+				// Initialize grant result here to prevent infinite loop.
+				// If it's referred before updating with actual result later
+				// result without applyting IK or grant is gotten
+				// but better than composing of infinite loop.
+				grantResultMap.set( boneIndex, quaternion.copy( bone.quaternion ) );
+
+				// @TODO: Support global grant and grant position
+				if ( grantSolver && boneData.grant &&
+					! boneData.grant.isLocal && boneData.grant.affectRotation ) {
+
+					var parentIndex = boneData.grant.parentIndex;
+					var ratio = boneData.grant.ratio;
+
+					if ( ! grantResultMap.has( parentIndex ) ) {
+
+						updateOne( mesh, parentIndex, ikSolver, grantSolver );
+
+					}
+
+					grantSolver.addGrantRotation( bone, grantResultMap.get( parentIndex ), ratio );
+
+				}
+
+				if ( ikSolver && boneData.ik ) {
+
+					// @TODO: Updating world matrices every time solving an IK bone is
+					// costly. Optimize if possible.
+					mesh.updateMatrixWorld( true );
+					ikSolver.updateOne( boneData.ik );
+
+					// No confident, but it seems the grant results with ik links should be updated?
+					var links = boneData.ik.links;
+
+					for ( var i = 0, il = links.length; i < il; i ++ ) {
+
+						var link = links[ i ];
+
+						if ( link.enabled === false ) continue;
+
+						var linkIndex = link.index;
+
+						if ( grantResultMap.has( linkIndex ) ) {
+
+							grantResultMap.set( linkIndex, grantResultMap.get( linkIndex ).copy( bones[ linkIndex ].quaternion ) );
+
+						}
+
+					}
+
+				}
+
+				// Update with the actual result here
+				quaternion.copy( bone.quaternion );
+
+			}
+
+			return function ( mesh, sortedBonesData, ikSolver, grantSolver ) {
+
+				quaternionIndex = 0;
+				grantResultMap.clear();
+
+				for ( var i = 0, il = sortedBonesData.length; i < il; i ++ ) {
+
+					updateOne( mesh, sortedBonesData[ i ].index, ikSolver, grantSolver );
+
+				}
+
+				mesh.updateMatrixWorld( true );
+				return this;
+
+			};
+
+		}(),
+
 		_animateCamera: function ( camera, delta ) {
 
 			var mixer = this.objects.get( camera ).mixer;
@@ -970,6 +1138,10 @@ var MMDAnimationHelper = ( function () {
 	};
 
 	/**
+	 * Solver for Grant (Fuyo in Japanese. I just google translated because
+	 * Fuyo may be MMD specific term and may not be common word in 3D CG terms.)
+	 * Grant propagates a bone's transform to other bones transforms even if
+	 * they are not children.
 	 * @param {THREE.SkinnedMesh} mesh
 	 * @param {Array<Object>} grants
 	 */
@@ -985,54 +1157,75 @@ var MMDAnimationHelper = ( function () {
 		constructor: GrantSolver,
 
 		/**
+		 * Solve all the grant bones
 		 * @return {GrantSolver}
 		 */
 		update: function () {
 
-			var quaternion = new Quaternion();
+			var grants = this.grants;
 
-			return function () {
+			for ( var i = 0, il = grants.length; i < il; i ++ ) {
 
-				var bones = this.mesh.skeleton.bones;
-				var grants = this.grants;
+				this.updateOne( grants[ i ] );
 
-				for ( var i = 0, il = grants.length; i < il; i ++ ) {
+			}
 
-					var grant = grants[ i ];
-					var bone = bones[ grant.index ];
-					var parentBone = bones[ grant.parentIndex ];
+			return this;
 
-					if ( grant.isLocal ) {
+		},
 
-						// TODO: implement
-						if ( grant.affectPosition ) {
+		/**
+		 * Solve a grant bone
+		 * @param {Object} grant - grant parameter
+		 * @return {GrantSolver}
+		 */
+		updateOne: function ( grant ) {
 
-						}
+			var bones = this.mesh.skeleton.bones;
+			var bone = bones[ grant.index ];
+			var parentBone = bones[ grant.parentIndex ];
 
-						// TODO: implement
-						if ( grant.affectRotation ) {
+			if ( grant.isLocal ) {
 
-						}
+				// TODO: implement
+				if ( grant.affectPosition ) {
 
-					} else {
+				}
 
-						// TODO: implement
-						if ( grant.affectPosition ) {
+				// TODO: implement
+				if ( grant.affectRotation ) {
 
-						}
+				}
 
-						if ( grant.affectRotation ) {
+			} else {
 
-							quaternion.set( 0, 0, 0, 1 );
-							quaternion.slerp( parentBone.quaternion, grant.ratio );
-							bone.quaternion.multiply( quaternion );
+				// TODO: implement
+				if ( grant.affectPosition ) {
 
-						}
+				}
 
-					}
+				if ( grant.affectRotation ) {
+
+					this.addGrantRotation( bone, parentBone.quaternion, grant.ratio );
 
 				}
 
+			}
+
+			return this;
+
+		},
+
+		addGrantRotation: function () {
+
+			var quaternion = new Quaternion();
+
+			return function ( bone, q, ratio ) {
+
+				quaternion.set( 0, 0, 0, 1 );
+				quaternion.slerp( q, ratio );
+				bone.quaternion.multiply( quaternion );
+
 				return this;
 
 			};

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