Browse Source

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

gogoend 6 years ago
parent
commit
49832ba25e
42 changed files with 778 additions and 533 deletions
  1. 1 1
      .github/ISSUE_TEMPLATE.md
  2. 1 1
      README.md
  3. 49 59
      build/three.js
  4. 171 292
      build/three.min.js
  5. 49 59
      build/three.module.js
  6. 155 0
      docs/examples/en/postprocessing/EffectComposer.html
  7. 153 0
      docs/examples/zh/postprocessing/EffectComposer.html
  8. 8 0
      docs/list.js
  9. 1 1
      editor/sw.js
  10. 13 20
      examples/js/loaders/FBXLoader.js
  11. 7 0
      examples/js/loaders/GLTFLoader.js
  12. 1 1
      examples/js/loaders/OBJLoader.js
  13. 4 0
      examples/js/postprocessing/MaskPass.js
  14. 14 22
      examples/jsm/loaders/FBXLoader.js
  15. 7 0
      examples/jsm/loaders/GLTFLoader.js
  16. 1 1
      examples/jsm/loaders/OBJLoader.js
  17. 2 2
      examples/jsm/nodes/postprocessing/NodePass.d.ts
  18. 4 0
      examples/jsm/postprocessing/MaskPass.js
  19. 1 1
      examples/jsm/utils/MathUtils.d.ts
  20. 1 1
      examples/jsm/utils/ShadowMapViewer.d.ts
  21. 1 1
      examples/jsm/utils/SkeletonUtils.d.ts
  22. 1 1
      examples/jsm/utils/UVsDebug.d.ts
  23. 2 0
      examples/main.css
  24. 12 5
      examples/webgl_materials_channels.html
  25. 3 4
      examples/webgl_shadowmap_pointlight.html
  26. BIN
      icon.png
  27. 1 1
      package.json
  28. 1 1
      rollup.config.js
  29. 1 1
      src/constants.js
  30. 2 2
      src/geometries/PolyhedronGeometry.js
  31. 6 6
      src/math/Euler.js
  32. 3 3
      src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js
  33. 9 9
      src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js
  34. 9 9
      src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl.js
  35. 6 6
      src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl.js
  36. 6 6
      src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl.js
  37. 50 10
      src/renderers/webgl/WebGLLights.js
  38. 7 2
      src/renderers/webgl/WebGLProgram.js
  39. 4 0
      src/renderers/webgl/WebGLPrograms.js
  40. 8 4
      src/renderers/webgl/WebGLState.js
  41. 2 0
      src/renderers/webvr/WebVRManager.d.ts
  42. 1 1
      utils/modularize.js

+ 1 - 1
.github/ISSUE_TEMPLATE.md

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

+ 1 - 1
README.md

@@ -19,7 +19,7 @@ The aim of the project is to create an easy to use, lightweight, 3D library with
 [Questions](http://stackoverflow.com/questions/tagged/three.js) —
 [Forum](https://discourse.threejs.org/) —
 [Gitter](https://gitter.im/mrdoob/three.js) —
-[Slack](https://threejs-slack.herokuapp.com/)
+[Slack](https://join.slack.com/t/threejs/shared_invite/enQtMzYxMzczODM2OTgxLTQ1YmY4YTQxOTFjNDAzYmQ4NjU2YzRhNzliY2RiNDEyYjU2MjhhODgyYWQ5Y2MyZTU3MWNkOGVmOGRhOTQzYTk)
 
 ### Usage ###
 

File diff suppressed because it is too large
+ 49 - 59
build/three.js


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


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


+ 155 - 0
docs/examples/en/postprocessing/EffectComposer.html

@@ -0,0 +1,155 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+
+		<h1>[name]</h1>
+
+		<p class="desc">
+			Used to implement post-processing effects in three.js. The class manages a chain of post-processing passes
+			to produce the final visual result. Post-processing passes are executed in order of their addition/insertion.
+			The last pass is automatically rendered to screen.
+		</p>
+
+		<h2>Examples</h2>
+
+		<p>
+			[example:webgl_postprocessing postprocessing]<br />
+			[example:webgl_postprocessing_advanced postprocessing advanced]<br />
+			[example:webgl_postprocessing_backgrounds postprocessing backgrounds]<br />
+			[example:webgl_postprocessing_crossfade postprocessing crossfade]<br />
+			[example:webgl_postprocessing_dof postprocessing depth-of-field]<br />
+			[example:webgl_postprocessing_dof2 postprocessing depth-of-field 2]<br />
+			[example:webgl_postprocessing_fxaa postprocessing fxaa]<br />
+			[example:webgl_postprocessing_glitch postprocessing glitch]<br />
+			[example:webgl_postprocessing_godrays postprocessing godrays]<br />
+			[example:webgl_postprocessing_masking postprocessing masking]<br />
+			[example:webgl_postprocessing_nodes postprocessing node material]<br />
+			[example:webgl_postprocessing_outline postprocessing outline]<br />
+			[example:webgl_postprocessing_pixel postprocessing pixelate]<br />
+			[example:webgl_postprocessing_procedural postprocessing procedural]<br />
+			[example:webgl_postprocessing_rgb_halftone postprocessing rgb halftone]<br />
+			[example:webgl_postprocessing_sao postprocessing sao]<br />
+			[example:webgl_postprocessing_smaa postprocessing smaa]<br />
+			[example:webgl_postprocessing_sobel postprocessing sobel]<br />
+			[example:webgl_postprocessing_ssaa postprocessing ssaa]<br />
+			[example:webgl_postprocessing_ssao postprocessing ssao]<br />
+			[example:webgl_postprocessing_taa postprocessing taa]<br />
+			[example:webgl_postprocessing_unreal_bloom postprocessing unreal bloom]<br />
+			[example:webgl_postprocessing_unreal_bloom_selective postprocessing unreal bloom selective]<br />
+		</p>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [param:WebGLRenderer renderer], [param:WebGLRenderTarget renderTarget] )</h3>
+		<p>
+		[page:WebGLRenderer renderer] -- The renderer used to render the scene. <br />
+		[page:WebGLRenderTarget renderTarget] -- (optional) A preconfigured render target internally used by [name].
+		</p>
+
+		<h2>Properties</h2>
+
+		<h3>[property:Boolean passes]</h3>
+		<p>
+			An array representing the (ordered) chain of post-processing passes.
+		</p>
+
+		<h3>[property:WebGLRendererTarget readBuffer]</h3>
+		<p>
+			A reference to the internal read buffer. Passes usually read the previous render result from this buffer.
+		</p>
+
+		<h3>[property:WebGLRenderer renderer]</h3>
+		<p>
+			A reference to the internal renderer.
+		</p>
+
+		<h3>[property:Boolean renderToScreen]</h3>
+		<p>
+			Whether the final pass is rendered to the screen (default framebuffer) or not.
+		</p>
+
+		<h3>[property:WebGLRendererTarget writeBuffer]</h3>
+		<p>
+			A reference to the internal write buffer. Passes usually write their result into this buffer.
+		</p>
+
+		<h2>Methods</h2>
+
+		<h3>[method:void addPass]( [param:Pass pass] )</h3>
+
+		<p>
+			pass -- The pass to add to the pass chain.<br /><br />
+
+			Adds the given pass to the pass chain.
+		</p>
+
+		<h3>[method:void insertPass]( [param:Pass pass], [param:Integer index] )</h3>
+
+		<p>
+			pass -- The pass to insert into the pass chain.<br />
+			index -- Defines the position in the pass chain where the pass should be inserted.<br /><br />
+
+			Inserts the given pass into the pass chain at the given index.
+		</p>
+
+		<h3>[method:boolean isLastEnabledPass]( [param:Integer passIndex] )</h3>
+
+		<p>
+			passIndex -- The pass to check.<br /><br />
+
+			Returns true if the pass for the given index is the last enabled pass in the pass chain.
+			Used by [name] to determine when a pass should be rendered to screen.
+		</p>
+
+		<h3>[method:void render]( [param:Float deltaTime] )</h3>
+
+		<p>
+			deltaTime -- The delta time value.<br /><br />
+
+			Executes all enabled post-processing passes in order to produce the final frame.
+		</p>
+
+		<h3>[method:void reset]( [param:WebGLRenderTarget renderTarget] )</h3>
+
+		<p>
+			[page:WebGLRenderTarget renderTarget] -- (optional) A preconfigured render target internally used by [name]..<br /><br />
+
+			Resets the internal state of the [name].
+		</p>
+
+		<h3>[method:void setPixelRatio]( [param:Float pixelRatio] )</h3>
+
+		<p>
+			pixelRatio -- The device pixel ratio.<br /><br />
+
+			Sets device pixel ratio. This is usually used for HiDPI device to prevent bluring output.
+				Thus, the semantic of the method is similar to [page:WebGLRenderer.setPixelRatio]().
+		</p>
+
+		<h3>[method:void setSize]( [param:Integer width], [param:Integer height] )</h3>
+
+		<p>
+			width -- The width of the [name].<br />
+			height -- The height of the [name].<br /><br />
+
+				Resizes the internal render buffers and passes to (width, height) with device pixel ratio taken into account.
+				Thus, the semantic of the method is similar to [page:WebGLRenderer.setSize]().
+		</p>
+
+		<h3>[method:void swapBuffers]()</h3>
+
+		<p>Swaps the internal read/write buffers.</p>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/postprocessing/EffectComposer.js examples/js/postprocessing/EffectComposer.js]
+	</body>
+</html>

+ 153 - 0
docs/examples/zh/postprocessing/EffectComposer.html

@@ -0,0 +1,153 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+
+		<h1>[name]</h1>
+
+		<p class="desc">
+			TODO
+		</p>
+
+		<h2>Examples</h2>
+
+		<p>
+			[example:webgl_postprocessing postprocessing]<br />
+			[example:webgl_postprocessing_advanced postprocessing advanced]<br />
+			[example:webgl_postprocessing_backgrounds postprocessing backgrounds]<br />
+			[example:webgl_postprocessing_crossfade postprocessing crossfade]<br />
+			[example:webgl_postprocessing_dof postprocessing depth-of-field]<br />
+			[example:webgl_postprocessing_dof2 postprocessing depth-of-field 2]<br />
+			[example:webgl_postprocessing_fxaa postprocessing fxaa]<br />
+			[example:webgl_postprocessing_glitch postprocessing glitch]<br />
+			[example:webgl_postprocessing_godrays postprocessing godrays]<br />
+			[example:webgl_postprocessing_masking postprocessing masking]<br />
+			[example:webgl_postprocessing_nodes postprocessing node material]<br />
+			[example:webgl_postprocessing_outline postprocessing outline]<br />
+			[example:webgl_postprocessing_pixel postprocessing pixelate]<br />
+			[example:webgl_postprocessing_procedural postprocessing procedural]<br />
+			[example:webgl_postprocessing_rgb_halftone postprocessing rgb halftone]<br />
+			[example:webgl_postprocessing_sao postprocessing sao]<br />
+			[example:webgl_postprocessing_smaa postprocessing smaa]<br />
+			[example:webgl_postprocessing_sobel postprocessing sobel]<br />
+			[example:webgl_postprocessing_ssaa postprocessing ssaa]<br />
+			[example:webgl_postprocessing_ssao postprocessing ssao]<br />
+			[example:webgl_postprocessing_taa postprocessing taa]<br />
+			[example:webgl_postprocessing_unreal_bloom postprocessing unreal bloom]<br />
+			[example:webgl_postprocessing_unreal_bloom_selective postprocessing unreal bloom selective]<br />
+		</p>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [param:WebGLRenderer renderer], [param:WebGLRenderTarget renderTarget] )</h3>
+		<p>
+		[page:WebGLRenderer renderer] -- The renderer used to render the scene. <br />
+		[page:WebGLRenderTarget renderTarget] -- (optional) A preconfigured render target internally used by [name].
+		</p>
+
+		<h2>Properties</h2>
+
+		<h3>[property:Boolean passes]</h3>
+		<p>
+			An array representing the (ordered) chain of post-processing passes.
+		</p>
+
+		<h3>[property:WebGLRendererTarget readBuffer]</h3>
+		<p>
+			A reference to the internal read buffer. Passes usually read the previous render result from this buffer.
+		</p>
+
+		<h3>[property:WebGLRenderer renderer]</h3>
+		<p>
+			A reference to the internal renderer.
+		</p>
+
+		<h3>[property:Boolean renderToScreen]</h3>
+		<p>
+			Whether the final pass is rendered to the screen (default framebuffer) or not.
+		</p>
+
+		<h3>[property:WebGLRendererTarget writeBuffer]</h3>
+		<p>
+			A reference to the internal write buffer. Passes usually write their result into this buffer.
+		</p>
+
+		<h2>Methods</h2>
+
+		<h3>[method:void addPass]( [param:Pass pass] )</h3>
+
+		<p>
+			pass -- The pass to add to the pass chain.<br /><br />
+
+			Adds the given pass to the pass chain.
+		</p>
+
+		<h3>[method:void insertPass]( [param:Pass pass], [param:Integer index] )</h3>
+
+		<p>
+			pass -- The pass to insert into the pass chain.<br />
+			index -- Defines the position in the pass chain where the pass should be inserted.<br /><br />
+
+			Inserts the given pass into the pass chain at the given index.
+		</p>
+
+		<h3>[method:boolean isLastEnabledPass]( [param:Integer passIndex] )</h3>
+
+		<p>
+			passIndex -- The pass to check.<br /><br />
+
+			Returns true if the pass for the given index is the last enabled pass in the pass chain.
+			Used by [name] to determine when a pass should be rendered to screen.
+		</p>
+
+		<h3>[method:void render]( [param:Float deltaTime] )</h3>
+
+		<p>
+			deltaTime -- The delta time value.<br /><br />
+
+			Executes all enabled post-processing passes in order to produce the final frame.
+		</p>
+
+		<h3>[method:void reset]( [param:WebGLRenderTarget renderTarget] )</h3>
+
+		<p>
+			[page:WebGLRenderTarget renderTarget] -- (optional) A preconfigured render target internally used by [name]..<br /><br />
+
+			Resets the internal state of the [name].
+		</p>
+
+		<h3>[method:void setPixelRatio]( [param:Float pixelRatio] )</h3>
+
+		<p>
+			pixelRatio -- The device pixel ratio.<br /><br />
+
+			Sets device pixel ratio. This is usually used for HiDPI device to prevent bluring output.
+				Thus, the semantic of the method is similar to [page:WebGLRenderer.setPixelRatio]().
+		</p>
+
+		<h3>[method:void setSize]( [param:Integer width], [param:Integer height] )</h3>
+
+		<p>
+			width -- The width of the [name].<br />
+			height -- The height of the [name].<br /><br />
+
+				Resizes the internal render buffers and passes to (width, height) with device pixel ratio taken into account.
+				Thus, the semantic of the method is similar to [page:WebGLRenderer.setSize]().
+		</p>
+
+		<h3>[method:void swapBuffers]()</h3>
+
+		<p>Swaps the internal read/write buffers.</p>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/postprocessing/EffectComposer.js examples/js/postprocessing/EffectComposer.js]
+	</body>
+</html>

+ 8 - 0
docs/list.js

@@ -384,6 +384,10 @@ var list = {
 				"Lensflare": "examples/en/objects/Lensflare",
 			},
 
+			"Post-Processing": {
+				"EffectComposer": "examples/en/postprocessing/EffectComposer"
+			},
+
 			"Exporters": {
 				"GLTFExporter": "examples/en/exporters/GLTFExporter",
 				"PLYExporter": "examples/en/exporters/PLYExporter",
@@ -815,6 +819,10 @@ var list = {
 				"Lensflare": "examples/zh/objects/Lensflare",
 			},
 
+			"Post-Processing": {
+				"EffectComposer": "examples/zh/postprocessing/EffectComposer"
+			},
+
 			"导出器": {
 				"GLTFExporter": "examples/zh/exporters/GLTFExporter",
 				"PLYExporter": "examples/zh/exporters/PLYExporter"

+ 1 - 1
editor/sw.js

@@ -1,4 +1,4 @@
-// r106
+// r107
 
 const staticAssets = [
 	'./',

+ 13 - 20
examples/js/loaders/FBXLoader.js

@@ -288,27 +288,15 @@ THREE.FBXLoader = ( function () {
 
 				case 'tga':
 
-					if ( typeof THREE.TGALoader !== 'function' ) {
+					if ( THREE.Loader.Handlers.get( '.tga' ) === null ) {
 
-						console.warn( 'FBXLoader: THREE.TGALoader is required to load TGA textures' );
-						return;
-
-					} else {
-
-						if ( THREE.Loader.Handlers.get( '.tga' ) === null ) {
-
-							var tgaLoader = new THREE.TGALoader();
-							tgaLoader.setPath( this.textureLoader.path );
-
-							THREE.Loader.Handlers.add( /\.tga$/i, tgaLoader );
-
-						}
-
-						type = 'image/tga';
-						break;
+						console.warn( 'FBXLoader: TGA loader not found, skipping ', fileName );
 
 					}
 
+					type = 'image/tga';
+					break;
+
 				default:
 
 					console.warn( 'FBXLoader: Image type "' + extension + '" is not supported.' );
@@ -417,7 +405,7 @@ THREE.FBXLoader = ( function () {
 
 				if ( loader === null ) {
 
-					console.warn( 'FBXLoader: TGALoader not found, creating empty placeholder texture for', fileName );
+					console.warn( 'FBXLoader: TGA loader not found, creating placeholder texture for', textureNode.RelativeFilename );
 					texture = new THREE.Texture();
 
 				} else {
@@ -428,7 +416,7 @@ THREE.FBXLoader = ( function () {
 
 			} else if ( extension === 'psd' ) {
 
-				console.warn( 'FBXLoader: PSD textures are not supported, creating empty placeholder texture for', fileName );
+				console.warn( 'FBXLoader: PSD textures are not supported, creating placeholder texture for', textureNode.RelativeFilename );
 				texture = new THREE.Texture();
 
 			} else {
@@ -609,6 +597,7 @@ THREE.FBXLoader = ( function () {
 					case 'DiffuseColor':
 					case 'Maya|TEX_color_map':
 						parameters.map = self.getTexture( textureMap, child.ID );
+						parameters.map.encoding = THREE.sRGBEncoding;
 						break;
 
 					case 'DisplacementColor':
@@ -617,6 +606,7 @@ THREE.FBXLoader = ( function () {
 
 					case 'EmissiveColor':
 						parameters.emissiveMap = self.getTexture( textureMap, child.ID );
+						parameters.emissiveMap.encoding = THREE.sRGBEncoding;
 						break;
 
 					case 'NormalMap':
@@ -627,10 +617,12 @@ THREE.FBXLoader = ( function () {
 					case 'ReflectionColor':
 						parameters.envMap = self.getTexture( textureMap, child.ID );
 						parameters.envMap.mapping = THREE.EquirectangularReflectionMapping;
+						parameters.envMap.encoding = THREE.sRGBEncoding;
 						break;
 
 					case 'SpecularColor':
 						parameters.specularMap = self.getTexture( textureMap, child.ID );
+						parameters.specularMap.encoding = THREE.sRGBEncoding;
 						break;
 
 					case 'TransparentColor':
@@ -1554,6 +1546,7 @@ THREE.FBXLoader = ( function () {
 
 		},
 
+
 		// Parse single node mesh geometry in FBXTree.Objects.Geometry
 		parseMeshGeometry: function ( relationships, geoNode, deformers ) {
 
@@ -4133,4 +4126,4 @@ THREE.FBXLoader = ( function () {
 
 	return FBXLoader;
 
-} )();
+} )();

+ 7 - 0
examples/js/loaders/GLTFLoader.js

@@ -1187,6 +1187,13 @@ THREE.GLTFLoader = ( function () {
 
 		// Invalid URL
 		if ( typeof url !== 'string' || url === '' ) return '';
+		
+		// Host Relative URL
+		if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) {
+
+			path = path.replace( /(^https?:\/\/[^\/]+).*/i , '$1' );
+
+		}
 
 		// Absolute URL http://,https://,//
 		if ( /^(https?:)?\/\//i.test( url ) ) return url;

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

@@ -459,7 +459,7 @@ THREE.OBJLoader = ( function () {
 								parseFloat( data[ 2 ] ),
 								parseFloat( data[ 3 ] )
 							);
-							if ( data.length === 8 ) {
+							if ( data.length >= 7 ) {
 
 								state.colors.push(
 									parseFloat( data[ 4 ] ),

+ 4 - 0
examples/js/postprocessing/MaskPass.js

@@ -55,6 +55,7 @@ THREE.MaskPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ),
 		state.buffers.stencil.setOp( context.REPLACE, context.REPLACE, context.REPLACE );
 		state.buffers.stencil.setFunc( context.ALWAYS, writeValue, 0xffffffff );
 		state.buffers.stencil.setClear( clearValue );
+		state.buffers.stencil.setLocked( true );
 
 		// draw into the stencil buffer
 
@@ -73,8 +74,10 @@ THREE.MaskPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ),
 
 		// only render where stencil is set to 1
 
+		state.buffers.stencil.setLocked( false );
 		state.buffers.stencil.setFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1
 		state.buffers.stencil.setOp( context.KEEP, context.KEEP, context.KEEP );
+		state.buffers.stencil.setLocked( true );
 
 	}
 
@@ -95,6 +98,7 @@ Object.assign( THREE.ClearMaskPass.prototype, {
 
 	render: function ( renderer /*, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
 
+		renderer.state.buffers.stencil.setLocked( false );
 		renderer.state.buffers.stencil.setTest( false );
 
 	}

+ 14 - 22
examples/jsm/loaders/FBXLoader.js

@@ -61,10 +61,10 @@ import {
 	Vector3,
 	Vector4,
 	VectorKeyframeTrack,
-	VertexColors
+	VertexColors,
+	sRGBEncoding
 } from "../../../build/three.module.js";
 import { Zlib } from "../libs/inflate.module.min.js";
-import { TGALoader } from "../loaders/TGALoader.js";
 import { NURBSCurve } from "../curves/NURBSCurve.js";
 
 
@@ -337,27 +337,15 @@ var FBXLoader = ( function () {
 
 				case 'tga':
 
-					if ( typeof TGALoader !== 'function' ) {
+					if ( Loader.Handlers.get( '.tga' ) === null ) {
 
-						console.warn( 'FBXLoader: TGALoader is required to load TGA textures' );
-						return;
-
-					} else {
-
-						if ( Loader.Handlers.get( '.tga' ) === null ) {
-
-							var tgaLoader = new TGALoader();
-							tgaLoader.setPath( this.textureLoader.path );
-
-							Loader.Handlers.add( /\.tga$/i, tgaLoader );
-
-						}
-
-						type = 'image/tga';
-						break;
+						console.warn( 'FBXLoader: TGA loader not found, skipping ', fileName );
 
 					}
 
+					type = 'image/tga';
+					break;
+
 				default:
 
 					console.warn( 'FBXLoader: Image type "' + extension + '" is not supported.' );
@@ -466,7 +454,7 @@ var FBXLoader = ( function () {
 
 				if ( loader === null ) {
 
-					console.warn( 'FBXLoader: TGALoader not found, creating empty placeholder texture for', fileName );
+					console.warn( 'FBXLoader: TGA loader not found, creating placeholder texture for', textureNode.RelativeFilename );
 					texture = new Texture();
 
 				} else {
@@ -477,7 +465,7 @@ var FBXLoader = ( function () {
 
 			} else if ( extension === 'psd' ) {
 
-				console.warn( 'FBXLoader: PSD textures are not supported, creating empty placeholder texture for', fileName );
+				console.warn( 'FBXLoader: PSD textures are not supported, creating placeholder texture for', textureNode.RelativeFilename );
 				texture = new Texture();
 
 			} else {
@@ -658,6 +646,7 @@ var FBXLoader = ( function () {
 					case 'DiffuseColor':
 					case 'Maya|TEX_color_map':
 						parameters.map = self.getTexture( textureMap, child.ID );
+						parameters.map.encoding = sRGBEncoding;
 						break;
 
 					case 'DisplacementColor':
@@ -666,6 +655,7 @@ var FBXLoader = ( function () {
 
 					case 'EmissiveColor':
 						parameters.emissiveMap = self.getTexture( textureMap, child.ID );
+						parameters.emissiveMap.encoding = sRGBEncoding;
 						break;
 
 					case 'NormalMap':
@@ -676,10 +666,12 @@ var FBXLoader = ( function () {
 					case 'ReflectionColor':
 						parameters.envMap = self.getTexture( textureMap, child.ID );
 						parameters.envMap.mapping = EquirectangularReflectionMapping;
+						parameters.envMap.encoding = sRGBEncoding;
 						break;
 
 					case 'SpecularColor':
 						parameters.specularMap = self.getTexture( textureMap, child.ID );
+						parameters.specularMap.encoding = sRGBEncoding;
 						break;
 
 					case 'TransparentColor':
@@ -1603,6 +1595,7 @@ var FBXLoader = ( function () {
 
 		},
 
+
 		// Parse single node mesh geometry in FBXTree.Objects.Geometry
 		parseMeshGeometry: function ( relationships, geoNode, deformers ) {
 
@@ -4183,5 +4176,4 @@ var FBXLoader = ( function () {
 	return FBXLoader;
 
 } )();
-
 export { FBXLoader };

+ 7 - 0
examples/jsm/loaders/GLTFLoader.js

@@ -1252,6 +1252,13 @@ var GLTFLoader = ( function () {
 
 		// Invalid URL
 		if ( typeof url !== 'string' || url === '' ) return '';
+		
+		// Host Relative URL
+		if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) {
+
+			path = path.replace( /(^https?:\/\/[^\/]+).*/i , '$1' );
+
+		}
 
 		// Absolute URL http://,https://,//
 		if ( /^(https?:)?\/\//i.test( url ) ) return url;

+ 1 - 1
examples/jsm/loaders/OBJLoader.js

@@ -476,7 +476,7 @@ var OBJLoader = ( function () {
 								parseFloat( data[ 2 ] ),
 								parseFloat( data[ 3 ] )
 							);
-							if ( data.length === 8 ) {
+							if ( data.length >= 7 ) {
 
 								state.colors.push(
 									parseFloat( data[ 4 ] ),

+ 2 - 2
examples/jsm/nodes/postprocessing/NodePass.d.ts

@@ -1,4 +1,4 @@
-import { NodeMaterial } from './NodeMaterial';
+import { NodeMaterial } from '../materials/NodeMaterial';
 import { ShaderPass } from '../../postprocessing/ShaderPass';
 import { ScreenNode } from '../inputs/ScreenNode';
 
@@ -13,4 +13,4 @@ export class NodePass extends ShaderPass {
 
   copy(source: NodePass): this;
   toJSON(meta?: object | string): object;
-}
+}

+ 4 - 0
examples/jsm/postprocessing/MaskPass.js

@@ -58,6 +58,7 @@ MaskPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 		state.buffers.stencil.setOp( context.REPLACE, context.REPLACE, context.REPLACE );
 		state.buffers.stencil.setFunc( context.ALWAYS, writeValue, 0xffffffff );
 		state.buffers.stencil.setClear( clearValue );
+		state.buffers.stencil.setLocked( true );
 
 		// draw into the stencil buffer
 
@@ -76,8 +77,10 @@ MaskPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 
 		// only render where stencil is set to 1
 
+		state.buffers.stencil.setLocked( false );
 		state.buffers.stencil.setFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1
 		state.buffers.stencil.setOp( context.KEEP, context.KEEP, context.KEEP );
+		state.buffers.stencil.setLocked( true );
 
 	}
 
@@ -98,6 +101,7 @@ Object.assign( ClearMaskPass.prototype, {
 
 	render: function ( renderer /*, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
 
+		renderer.state.buffers.stencil.setLocked( false );
 		renderer.state.buffers.stencil.setTest( false );
 
 	}

+ 1 - 1
examples/jsm/utils/MathUtils.d.ts

@@ -1,4 +1,4 @@
-import {Quaternion} from "../../..";
+import {Quaternion} from "../../../src/Three";
 
 export namespace MathUtils {
 	export function setQuaternionFromProperEuler(q: Quaternion, a: number, b: number, c: number, order: string): void ;

+ 1 - 1
examples/jsm/utils/ShadowMapViewer.d.ts

@@ -1,4 +1,4 @@
-import {Light} from "../../..";
+import {Light} from "../../../src/Three";
 
 export class ShadowMapViewer {
 	constructor(light: Light)

+ 1 - 1
examples/jsm/utils/SkeletonUtils.d.ts

@@ -1,4 +1,4 @@
-import {AnimationClip, Bone, Matrix4, Object3D, Skeleton, SkeletonHelper} from "../../..";
+import {AnimationClip, Bone, Matrix4, Object3D, Skeleton, SkeletonHelper} from "../../../src/Three";
 
 export namespace SkeletonUtils {
 	export function retarget(target: Object3D | Skeleton,

+ 1 - 1
examples/jsm/utils/UVsDebug.d.ts

@@ -1,3 +1,3 @@
-import {Geometry} from "../../..";
+import {Geometry} from "../../../src/Three";
 
 export function UVsDebug(geometry: Geometry, size: number): HTMLCanvasElement;

+ 2 - 0
examples/main.css

@@ -10,6 +10,7 @@ body {
 a {
 	color: #ff0;
 	text-decoration: none;
+	pointer-events: auto;
 }
 
 a:hover {
@@ -36,6 +37,7 @@ canvas {
 	-webkit-user-select: none;
 	-ms-user-select: none;
 	user-select: none;
+	pointer-events: none;
 	z-index: 1; /* TODO Solve this in HTML */
 }
 

+ 12 - 5
examples/webgl_materials_channels.html

@@ -78,7 +78,7 @@
 				scene = new THREE.Scene();
 
 				var aspect = window.innerWidth / window.innerHeight;
-				cameraPerspective = new THREE.PerspectiveCamera( 45, aspect, 1000, 2500 );
+				cameraPerspective = new THREE.PerspectiveCamera( 45, aspect, 500, 3000 );
 				cameraPerspective.position.z = 1500;
 				scene.add( cameraPerspective );
 
@@ -90,13 +90,13 @@
 
 				controlsPerspective = new OrbitControls( cameraPerspective, renderer.domElement );
 				controlsPerspective.minDistance = 1000;
-				controlsPerspective.maxDistance = 2500;
+				controlsPerspective.maxDistance = 2400;
 				controlsPerspective.enablePan = false;
 				controlsPerspective.enableDamping = true;
 
 				controlsOrtho = new OrbitControls( cameraOrtho, renderer.domElement );
 				controlsOrtho.minZoom = 0.5;
-				controlsOrtho.maxZoom = 2;
+				controlsOrtho.maxZoom = 1.5;
 				controlsOrtho.enablePan = false;
 				controlsOrtho.enableDamping = true;
 
@@ -272,11 +272,18 @@
 
 				switch ( params.camera ) {
 
-					case 'perspective': camera = cameraPerspective; break;
-					case 'ortho': camera = cameraOrtho; break;
+					case 'perspective':
+						camera = cameraPerspective;
+						break;
+					case 'ortho':
+						camera = cameraOrtho;
+						break;
 
 				}
 
+				controlsPerspective.update();
+				controlsOrtho.update(); // must update both controls for damping to complete
+
 				renderer.render( scene, camera );
 
 			}

+ 3 - 4
examples/webgl_shadowmap_pointlight.html

@@ -55,7 +55,7 @@
 					texture.magFilter = THREE.NearestFilter;
 					texture.wrapT = THREE.RepeatWrapping;
 					texture.wrapS = THREE.RepeatWrapping;
-					texture.repeat.set( 1, 3.5 );
+					texture.repeat.set( 1, 4.5 );
 
 					var geometry = new THREE.SphereBufferGeometry( 2, 32, 8 );
 					var material = new THREE.MeshPhongMaterial( {
@@ -85,7 +85,6 @@
 
 				pointLight2 = createLight( 0xff8888 );
 				scene.add( pointLight2 );
-
 				//
 
 				var geometry = new THREE.BoxBufferGeometry( 30, 30, 30 );
@@ -159,7 +158,7 @@
 				var time = performance.now() * 0.001;
 
 				pointLight.position.x = Math.sin( time * 0.6 ) * 9;
-				pointLight.position.y = Math.sin( time * 0.7 ) * 9 + 5;
+				pointLight.position.y = Math.sin( time * 0.7 ) * 9 + 6;
 				pointLight.position.z = Math.sin( time * 0.8 ) * 9;
 
 				pointLight.rotation.x = time;
@@ -168,7 +167,7 @@
 				time += 10000;
 
 				pointLight2.position.x = Math.sin( time * 0.6 ) * 9;
-				pointLight2.position.y = Math.sin( time * 0.7 ) * 9 + 5;
+				pointLight2.position.y = Math.sin( time * 0.7 ) * 9 + 6;
 				pointLight2.position.z = Math.sin( time * 0.8 ) * 9;
 
 				pointLight2.rotation.x = time;

BIN
icon.png


+ 1 - 1
package.json

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

+ 1 - 1
rollup.config.js

@@ -207,7 +207,7 @@ export default {
 			indent: '\t'
 		},
 		{
-			format: 'es',
+			format: 'esm',
 			file: 'build/three.module.js',
 			indent: '\t'
 		}

+ 1 - 1
src/constants.js

@@ -1,4 +1,4 @@
-export var REVISION = '107dev';
+export var REVISION = '108dev';
 export var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 };
 export var TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 };
 export var CullFaceNone = 0;

+ 2 - 2
src/geometries/PolyhedronGeometry.js

@@ -63,7 +63,7 @@ function PolyhedronBufferGeometry( vertices, indices, radius, detail ) {
 
 	// all vertices should lie on a conceptual sphere with a given radius
 
-	appplyRadius( radius );
+	applyRadius( radius );
 
 	// finally, create the uv data
 
@@ -176,7 +176,7 @@ function PolyhedronBufferGeometry( vertices, indices, radius, detail ) {
 
 	}
 
-	function appplyRadius( radius ) {
+	function applyRadius( radius ) {
 
 		var vertex = new Vector3();
 

+ 6 - 6
src/math/Euler.js

@@ -149,7 +149,7 @@ Object.assign( Euler.prototype, {
 
 			this._y = Math.asin( clamp( m13, - 1, 1 ) );
 
-			if ( Math.abs( m13 ) < 0.99999 ) {
+			if ( Math.abs( m13 ) < 0.9999999 ) {
 
 				this._x = Math.atan2( - m23, m33 );
 				this._z = Math.atan2( - m12, m11 );
@@ -165,7 +165,7 @@ Object.assign( Euler.prototype, {
 
 			this._x = Math.asin( - clamp( m23, - 1, 1 ) );
 
-			if ( Math.abs( m23 ) < 0.99999 ) {
+			if ( Math.abs( m23 ) < 0.9999999 ) {
 
 				this._y = Math.atan2( m13, m33 );
 				this._z = Math.atan2( m21, m22 );
@@ -181,7 +181,7 @@ Object.assign( Euler.prototype, {
 
 			this._x = Math.asin( clamp( m32, - 1, 1 ) );
 
-			if ( Math.abs( m32 ) < 0.99999 ) {
+			if ( Math.abs( m32 ) < 0.9999999 ) {
 
 				this._y = Math.atan2( - m31, m33 );
 				this._z = Math.atan2( - m12, m22 );
@@ -197,7 +197,7 @@ Object.assign( Euler.prototype, {
 
 			this._y = Math.asin( - clamp( m31, - 1, 1 ) );
 
-			if ( Math.abs( m31 ) < 0.99999 ) {
+			if ( Math.abs( m31 ) < 0.9999999 ) {
 
 				this._x = Math.atan2( m32, m33 );
 				this._z = Math.atan2( m21, m11 );
@@ -213,7 +213,7 @@ Object.assign( Euler.prototype, {
 
 			this._z = Math.asin( clamp( m21, - 1, 1 ) );
 
-			if ( Math.abs( m21 ) < 0.99999 ) {
+			if ( Math.abs( m21 ) < 0.9999999 ) {
 
 				this._x = Math.atan2( - m23, m22 );
 				this._y = Math.atan2( - m31, m11 );
@@ -229,7 +229,7 @@ Object.assign( Euler.prototype, {
 
 			this._z = Math.asin( - clamp( m12, - 1, 1 ) );
 
-			if ( Math.abs( m12 ) < 0.99999 ) {
+			if ( Math.abs( m12 ) < 0.9999999 ) {
 
 				this._x = Math.atan2( m32, m22 );
 				this._y = Math.atan2( m13, m11 );

+ 3 - 3
src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js

@@ -33,7 +33,7 @@ IncidentLight directLight;
 
 		getPointDirectLightIrradiance( pointLight, geometry, directLight );
 
-		#ifdef USE_SHADOWMAP
+		#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )
 		directLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;
 		#endif
 
@@ -54,7 +54,7 @@ IncidentLight directLight;
 
 		getSpotDirectLightIrradiance( spotLight, geometry, directLight );
 
-		#ifdef USE_SHADOWMAP
+		#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )
 		directLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
 		#endif
 
@@ -75,7 +75,7 @@ IncidentLight directLight;
 
 		getDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );
 
-		#ifdef USE_SHADOWMAP
+		#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )
 		directLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;
 		#endif
 

+ 9 - 9
src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js

@@ -1,24 +1,24 @@
 export default /* glsl */`
 #ifdef USE_SHADOWMAP
 
-	#if NUM_DIR_LIGHTS > 0
+	#if NUM_DIR_LIGHT_SHADOWS > 0
 
-		uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];
-		varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];
+		uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];
+		varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];
 
 	#endif
 
-	#if NUM_SPOT_LIGHTS > 0
+	#if NUM_SPOT_LIGHT_SHADOWS > 0
 
-		uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];
-		varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];
+		uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];
+		varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];
 
 	#endif
 
-	#if NUM_POINT_LIGHTS > 0
+	#if NUM_POINT_LIGHT_SHADOWS > 0
 
-		uniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];
-		varying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];
+		uniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];
+		varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];
 
 	#endif
 

+ 9 - 9
src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl.js

@@ -1,24 +1,24 @@
 export default /* glsl */`
 #ifdef USE_SHADOWMAP
 
-	#if NUM_DIR_LIGHTS > 0
+	#if NUM_DIR_LIGHT_SHADOWS > 0
 
-		uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];
-		varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];
+		uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];
+		varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];
 
 	#endif
 
-	#if NUM_SPOT_LIGHTS > 0
+	#if NUM_SPOT_LIGHT_SHADOWS > 0
 
-		uniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];
-		varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];
+		uniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];
+		varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];
 
 	#endif
 
-	#if NUM_POINT_LIGHTS > 0
+	#if NUM_POINT_LIGHT_SHADOWS > 0
 
-		uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];
-		varying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];
+		uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];
+		varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];
 
 	#endif
 

+ 6 - 6
src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl.js

@@ -1,10 +1,10 @@
 export default /* glsl */`
 #ifdef USE_SHADOWMAP
 
-	#if NUM_DIR_LIGHTS > 0
+	#if NUM_DIR_LIGHT_SHADOWS > 0
 
 	#pragma unroll_loop
-	for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
+	for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {
 
 		vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;
 
@@ -12,10 +12,10 @@ export default /* glsl */`
 
 	#endif
 
-	#if NUM_SPOT_LIGHTS > 0
+	#if NUM_SPOT_LIGHT_SHADOWS > 0
 
 	#pragma unroll_loop
-	for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {
+	for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {
 
 		vSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;
 
@@ -23,10 +23,10 @@ export default /* glsl */`
 
 	#endif
 
-	#if NUM_POINT_LIGHTS > 0
+	#if NUM_POINT_LIGHT_SHADOWS > 0
 
 	#pragma unroll_loop
-	for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {
+	for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {
 
 		vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;
 

+ 6 - 6
src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl.js

@@ -5,12 +5,12 @@ float getShadowMask() {
 
 	#ifdef USE_SHADOWMAP
 
-	#if NUM_DIR_LIGHTS > 0
+	#if NUM_DIR_LIGHT_SHADOWS > 0
 
 	DirectionalLight directionalLight;
 
 	#pragma unroll_loop
-	for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
+	for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {
 
 		directionalLight = directionalLights[ i ];
 		shadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;
@@ -19,12 +19,12 @@ float getShadowMask() {
 
 	#endif
 
-	#if NUM_SPOT_LIGHTS > 0
+	#if NUM_SPOT_LIGHT_SHADOWS > 0
 
 	SpotLight spotLight;
 
 	#pragma unroll_loop
-	for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {
+	for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {
 
 		spotLight = spotLights[ i ];
 		shadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
@@ -33,12 +33,12 @@ float getShadowMask() {
 
 	#endif
 
-	#if NUM_POINT_LIGHTS > 0
+	#if NUM_POINT_LIGHT_SHADOWS > 0
 
 	PointLight pointLight;
 
 	#pragma unroll_loop
-	for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {
+	for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {
 
 		pointLight = pointLights[ i ];
 		shadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;

+ 50 - 10
src/renderers/webgl/WebGLLights.js

@@ -102,6 +102,12 @@ function UniformsCache() {
 
 var nextVersion = 0;
 
+function shadowCastingLightsFirst( lightA, lightB ) {
+
+	return ( lightB.castShadow ? 1 : 0 ) - ( lightA.castShadow ? 1 : 0 );
+
+}
+
 function WebGLLights() {
 
 	var cache = new UniformsCache();
@@ -116,7 +122,10 @@ function WebGLLights() {
 			spotLength: - 1,
 			rectAreaLength: - 1,
 			hemiLength: - 1,
-			shadowsLength: - 1,
+
+			numDirectionalShadows: - 1,
+			numPointShadows: - 1,
+			numSpotShadows: - 1,
 		},
 
 		ambient: [ 0, 0, 0 ],
@@ -131,7 +140,11 @@ function WebGLLights() {
 		point: [],
 		pointShadowMap: [],
 		pointShadowMatrix: [],
-		hemi: []
+		hemi: [],
+
+		numDirectionalShadows: - 1,
+		numPointShadows: - 1,
+		numSpotShadows: - 1
 
 	};
 
@@ -153,8 +166,14 @@ function WebGLLights() {
 		var rectAreaLength = 0;
 		var hemiLength = 0;
 
+		var numDirectionalShadows = 0;
+		var numPointShadows = 0;
+		var numSpotShadows = 0;
+
 		var viewMatrix = camera.matrixWorldInverse;
 
+		lights.sort( shadowCastingLightsFirst );
+
 		for ( var i = 0, l = lights.length; i < l; i ++ ) {
 
 			var light = lights[ i ];
@@ -199,10 +218,13 @@ function WebGLLights() {
 					uniforms.shadowRadius = shadow.radius;
 					uniforms.shadowMapSize = shadow.mapSize;
 
+					state.directionalShadowMap[ directionalLength ] = shadowMap;
+					state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
+
+					numDirectionalShadows ++;
+
 				}
 
-				state.directionalShadowMap[ directionalLength ] = shadowMap;
-				state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
 				state.directional[ directionalLength ] = uniforms;
 
 				directionalLength ++;
@@ -236,10 +258,13 @@ function WebGLLights() {
 					uniforms.shadowRadius = shadow.radius;
 					uniforms.shadowMapSize = shadow.mapSize;
 
+					state.spotShadowMap[ spotLength ] = shadowMap;
+					state.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
+
+					numSpotShadows ++;
+
 				}
 
-				state.spotShadowMap[ spotLength ] = shadowMap;
-				state.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
 				state.spot[ spotLength ] = uniforms;
 
 				spotLength ++;
@@ -299,10 +324,13 @@ function WebGLLights() {
 					uniforms.shadowCameraNear = shadow.camera.near;
 					uniforms.shadowCameraFar = shadow.camera.far;
 
+					state.pointShadowMap[ pointLength ] = shadowMap;
+					state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
+
+					numPointShadows ++;
+
 				}
 
-				state.pointShadowMap[ pointLength ] = shadowMap;
-				state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
 				state.point[ pointLength ] = uniforms;
 
 				pointLength ++;
@@ -337,7 +365,9 @@ function WebGLLights() {
 			hash.spotLength !== spotLength ||
 			hash.rectAreaLength !== rectAreaLength ||
 			hash.hemiLength !== hemiLength ||
-			hash.shadowsLength !== shadows.length ) {
+			hash.numDirectionalShadows !== numDirectionalShadows ||
+			hash.numPointShadows !== numPointShadows ||
+			hash.numSpotShadows !== numSpotShadows ) {
 
 			state.directional.length = directionalLength;
 			state.spot.length = spotLength;
@@ -345,12 +375,22 @@ function WebGLLights() {
 			state.point.length = pointLength;
 			state.hemi.length = hemiLength;
 
+			state.directionalShadowMap.length = numDirectionalShadows;
+			state.pointShadowMap.length = numPointShadows;
+			state.spotShadowMap.length = numSpotShadows;
+			state.directionalShadowMatrix.length = numDirectionalShadows;
+			state.pointShadowMatrix.length = numPointShadows;
+			state.spotShadowMatrix.length = numSpotShadows;
+
 			hash.directionalLength = directionalLength;
 			hash.pointLength = pointLength;
 			hash.spotLength = spotLength;
 			hash.rectAreaLength = rectAreaLength;
 			hash.hemiLength = hemiLength;
-			hash.shadowsLength = shadows.length;
+
+			hash.numDirectionalShadows = numDirectionalShadows;
+			hash.numPointShadows = numPointShadows;
+			hash.numSpotShadows = numSpotShadows;
 
 			state.version = nextVersion ++;
 

+ 7 - 2
src/renderers/webgl/WebGLProgram.js

@@ -180,7 +180,10 @@ function replaceLightNums( string, parameters ) {
 		.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
 		.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
 		.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
-		.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights );
+		.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )
+		.replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )
+		.replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
+		.replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );
 
 }
 
@@ -224,7 +227,9 @@ function unrollLoops( string ) {
 
 		for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) {
 
-			unroll += snippet.replace( /\[ i \]/g, '[ ' + i + ' ]' );
+			unroll += snippet
+				.replace( /\[ i \]/g, '[ ' + i + ' ]' )
+				.replace( /UNROLLED_LOOP_INDEX/g, i );
 
 		}
 

+ 4 - 0
src/renderers/webgl/WebGLPrograms.js

@@ -190,6 +190,10 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
 			numRectAreaLights: lights.rectArea.length,
 			numHemiLights: lights.hemi.length,
 
+			numDirLightShadows: lights.directionalShadowMap.length,
+			numPointLightShadows: lights.pointShadowMap.length,
+			numSpotLightShadows: lights.spotShadowMap.length,
+
 			numClippingPlanes: nClipPlanes,
 			numClipIntersection: nClipIntersection,
 

+ 8 - 4
src/renderers/webgl/WebGLState.js

@@ -215,13 +215,17 @@ function WebGLState( gl, extensions, utils, capabilities ) {
 
 			setTest: function ( stencilTest ) {
 
-				if ( stencilTest ) {
+				if ( ! locked ) {
 
-					enable( gl.STENCIL_TEST );
+					if ( stencilTest ) {
 
-				} else {
+						enable( gl.STENCIL_TEST );
+
+					} else {
 
-					disable( gl.STENCIL_TEST );
+						disable( gl.STENCIL_TEST );
+
+					}
 
 				}
 

+ 2 - 0
src/renderers/webvr/WebVRManager.d.ts

@@ -1,6 +1,7 @@
 import { Object3D } from '../../core/Object3D';
 import { PerspectiveCamera } from '../../cameras/PerspectiveCamera';
 import { ArrayCamera } from '../../cameras/ArrayCamera';
+import { Matrix4 } from '../../math/Matrix4';
 
 export interface WebVRManager {
 	enabled: boolean;
@@ -10,4 +11,5 @@ export interface WebVRManager {
 	getCamera( camera: PerspectiveCamera ): PerspectiveCamera | ArrayCamera;
 	submitFrame(): void;
 	dispose(): void;
+	getStandingMatrix(): Matrix4;
 }

+ 1 - 1
utils/modularize.js

@@ -87,7 +87,7 @@ var files = [
 	{ path: 'loaders/DRACOLoader.js', dependencies: [], ignoreList: [ 'LoadingManager' ] },
 	{ path: 'loaders/EXRLoader.js', dependencies: [], ignoreList: [] },
 	{ path: 'loaders/EquirectangularToCubeGenerator.js', dependencies: [], ignoreList: [] },
-	{ path: 'loaders/FBXLoader.js', dependencies: [ { name: 'Zlib', path: 'libs/inflate.module.min.js' }, { name: 'TGALoader', path: 'loaders/TGALoader.js' }, { name: 'NURBSCurve', path: 'curves/NURBSCurve.js' } ], ignoreList: [] },
+	{ path: 'loaders/FBXLoader.js', dependencies: [ { name: 'Zlib', path: 'libs/inflate.module.min.js' }, { name: 'NURBSCurve', path: 'curves/NURBSCurve.js' } ], ignoreList: [] },
 	{ path: 'loaders/GCodeLoader.js', dependencies: [], ignoreList: [] },
 	{ path: 'loaders/GLTFLoader.js', dependencies: [], ignoreList: [ 'NoSide', 'Matrix2', 'Camera', 'Texture' ] },
 	{ path: 'loaders/HDRCubeTextureLoader.js', dependencies: [ { name: 'RGBELoader', path: 'loaders/RGBELoader.js' } ], ignoreList: [] },

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