Kaynağa Gözat

Updated examples builds.

Mr.doob 3 yıl önce
ebeveyn
işleme
9b42ea4d01

+ 4 - 11
examples/js/exporters/OBJExporter.js

@@ -47,9 +47,7 @@
 
 					for ( let i = 0, l = vertices.count; i < l; i ++, nbVertex ++ ) {
 
-						vertex.x = vertices.getX( i );
-						vertex.y = vertices.getY( i );
-						vertex.z = vertices.getZ( i ); // transform the vertex to world space
+						vertex.fromBufferAttribute( vertices, i ); // transform the vertex to world space
 
 						vertex.applyMatrix4( mesh.matrixWorld ); // transform the vertex to export format
 
@@ -64,8 +62,7 @@
 
 					for ( let i = 0, l = uvs.count; i < l; i ++, nbVertexUvs ++ ) {
 
-						uv.x = uvs.getX( i );
-						uv.y = uvs.getY( i ); // transform the uv to export format
+						uv.fromBufferAttribute( uvs, i ); // transform the uv to export format
 
 						output += 'vt ' + uv.x + ' ' + uv.y + '\n';
 
@@ -80,9 +77,7 @@
 
 					for ( let i = 0, l = normals.count; i < l; i ++, nbNormals ++ ) {
 
-						normal.x = normals.getX( i );
-						normal.y = normals.getY( i );
-						normal.z = normals.getZ( i ); // transform the normal to world space
+						normal.fromBufferAttribute( normals, i ); // transform the normal to world space
 
 						normal.applyMatrix3( normalMatrixWorld ).normalize(); // transform the normal to export format
 
@@ -155,9 +150,7 @@
 
 					for ( let i = 0, l = vertices.count; i < l; i ++, nbVertex ++ ) {
 
-						vertex.x = vertices.getX( i );
-						vertex.y = vertices.getY( i );
-						vertex.z = vertices.getZ( i ); // transform the vertex to world space
+						vertex.fromBufferAttribute( vertices, i ); // transform the vertex to world space
 
 						vertex.applyMatrix4( line.matrixWorld ); // transform the vertex to export format
 

+ 4 - 12
examples/js/exporters/PLYExporter.js

@@ -185,9 +185,7 @@
 
 					for ( let i = 0, l = vertices.count; i < l; i ++ ) {
 
-						vertex.x = vertices.getX( i );
-						vertex.y = vertices.getY( i );
-						vertex.z = vertices.getZ( i );
+						vertex.fromBufferAttribute( vertices, i );
 						vertex.applyMatrix4( mesh.matrixWorld ); // Position information
 
 						output.setFloat32( vOffset, vertex.x, options.littleEndian );
@@ -201,9 +199,7 @@
 
 							if ( normals != null ) {
 
-								vertex.x = normals.getX( i );
-								vertex.y = normals.getY( i );
-								vertex.z = normals.getZ( i );
+								vertex.fromBufferAttribute( normals, i );
 								vertex.applyMatrix3( normalMatrixWorld ).normalize();
 								output.setFloat32( vOffset, vertex.x, options.littleEndian );
 								vOffset += 4;
@@ -336,9 +332,7 @@
 
 					for ( let i = 0, l = vertices.count; i < l; i ++ ) {
 
-						vertex.x = vertices.getX( i );
-						vertex.y = vertices.getY( i );
-						vertex.z = vertices.getZ( i );
+						vertex.fromBufferAttribute( vertices, i );
 						vertex.applyMatrix4( mesh.matrixWorld ); // Position information
 
 						let line = vertex.x + ' ' + vertex.y + ' ' + vertex.z; // Normal information
@@ -347,9 +341,7 @@
 
 							if ( normals != null ) {
 
-								vertex.x = normals.getX( i );
-								vertex.y = normals.getY( i );
-								vertex.z = normals.getZ( i );
+								vertex.fromBufferAttribute( normals, i );
 								vertex.applyMatrix3( normalMatrixWorld ).normalize();
 								line += ' ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z;
 

+ 2 - 2
examples/js/helpers/VertexNormalsHelper.js

@@ -51,9 +51,9 @@
 
 				for ( let j = 0, jl = objPos.count; j < jl; j ++ ) {
 
-					_v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld );
+					_v1.fromBufferAttribute( objPos, j ).applyMatrix4( matrixWorld );
 
-					_v2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) );
+					_v2.fromBufferAttribute( objNorm, j );
 
 					_v2.applyMatrix3( _normalMatrix ).normalize().multiplyScalar( this.size ).add( _v1 );
 

+ 2 - 2
examples/js/helpers/VertexTangentsHelper.js

@@ -38,9 +38,9 @@
 
 			for ( let j = 0, jl = objPos.count; j < jl; j ++ ) {
 
-				_v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld );
+				_v1.fromBufferAttribute( objPos, j ).applyMatrix4( matrixWorld );
 
-				_v2.set( objTan.getX( j ), objTan.getY( j ), objTan.getZ( j ) );
+				_v2.fromBufferAttribute( objTan, j );
 
 				_v2.transformDirection( matrixWorld ).multiplyScalar( this.size ).add( _v1 );
 

+ 245 - 244
examples/js/shaders/FXAAShader.js

@@ -30,255 +30,256 @@
 
 		}`,
 		fragmentShader: `
-		precision highp float;
+	precision highp float;
+
+	uniform sampler2D tDiffuse;
+
+	uniform vec2 resolution;
+
+	varying vec2 vUv;
+
+	// FXAA 3.11 implementation by NVIDIA, ported to WebGL by Agost Biro ([email protected])
+
+	//----------------------------------------------------------------------------------
+	// File:        es3-kepler\FXAA\assets\shaders/FXAA_DefaultES.frag
+	// SDK Version: v3.00
+	// Email:       [email protected]
+	// Site:        http://developer.nvidia.com/
+	//
+	// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
+	//
+	// Redistribution and use in source and binary forms, with or without
+	// modification, are permitted provided that the following conditions
+	// are met:
+	//  * Redistributions of source code must retain the above copyright
+	//    notice, this list of conditions and the following disclaimer.
+	//  * Redistributions in binary form must reproduce the above copyright
+	//    notice, this list of conditions and the following disclaimer in the
+	//    documentation and/or other materials provided with the distribution.
+	//  * Neither the name of NVIDIA CORPORATION nor the names of its
+	//    contributors may be used to endorse or promote products derived
+	//    from this software without specific prior written permission.
+	//
+	// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+	// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+	// PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+	// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+	// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+	// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+	// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+	// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+	// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+	// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+	//
+	//----------------------------------------------------------------------------------
+
+	#ifndef FXAA_DISCARD
+			//
+			// Only valid for PC OpenGL currently.
+			// Probably will not work when FXAA_GREEN_AS_LUMA = 1.
+			//
+			// 1 = Use discard on pixels which don't need AA.
+			//     For APIs which enable concurrent TEX+ROP from same surface.
+			// 0 = Return unchanged color on pixels which don't need AA.
+			//
+			#define FXAA_DISCARD 0
+	#endif
+
+	/*--------------------------------------------------------------------------*/
+	#define FxaaTexTop(t, p) texture2D(t, p, -100.0)
+	#define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r), -100.0)
+	/*--------------------------------------------------------------------------*/
+
+	#define NUM_SAMPLES 5
+
+	// assumes colors have premultipliedAlpha, so that the calculated color contrast is scaled by alpha
+	float contrast( vec4 a, vec4 b ) {
+			vec4 diff = abs( a - b );
+			return max( max( max( diff.r, diff.g ), diff.b ), diff.a );
+	}
+
+	/*============================================================================
+
+									FXAA3 QUALITY - PC
+
+	============================================================================*/
+
+	/*--------------------------------------------------------------------------*/
+	vec4 FxaaPixelShader(
+			vec2 posM,
+			sampler2D tex,
+			vec2 fxaaQualityRcpFrame,
+			float fxaaQualityEdgeThreshold,
+			float fxaaQualityinvEdgeThreshold
+	) {
+			vec4 rgbaM = FxaaTexTop(tex, posM);
+			vec4 rgbaS = FxaaTexOff(tex, posM, vec2( 0.0, 1.0), fxaaQualityRcpFrame.xy);
+			vec4 rgbaE = FxaaTexOff(tex, posM, vec2( 1.0, 0.0), fxaaQualityRcpFrame.xy);
+			vec4 rgbaN = FxaaTexOff(tex, posM, vec2( 0.0,-1.0), fxaaQualityRcpFrame.xy);
+			vec4 rgbaW = FxaaTexOff(tex, posM, vec2(-1.0, 0.0), fxaaQualityRcpFrame.xy);
+			// . S .
+			// W M E
+			// . N .
+
+			bool earlyExit = max( max( max(
+					contrast( rgbaM, rgbaN ),
+					contrast( rgbaM, rgbaS ) ),
+					contrast( rgbaM, rgbaE ) ),
+					contrast( rgbaM, rgbaW ) )
+					< fxaaQualityEdgeThreshold;
+			// . 0 .
+			// 0 0 0
+			// . 0 .
+
+			#if (FXAA_DISCARD == 1)
+					if(earlyExit) FxaaDiscard;
+			#else
+					if(earlyExit) return rgbaM;
+			#endif
+
+			float contrastN = contrast( rgbaM, rgbaN );
+			float contrastS = contrast( rgbaM, rgbaS );
+			float contrastE = contrast( rgbaM, rgbaE );
+			float contrastW = contrast( rgbaM, rgbaW );
+
+			float relativeVContrast = ( contrastN + contrastS ) - ( contrastE + contrastW );
+			relativeVContrast *= fxaaQualityinvEdgeThreshold;
+
+			bool horzSpan = relativeVContrast > 0.;
+			// . 1 .
+			// 0 0 0
+			// . 1 .
+
+			// 45 deg edge detection and corners of objects, aka V/H contrast is too similar
+			if( abs( relativeVContrast ) < .3 ) {
+					// locate the edge
+					vec2 dirToEdge;
+					dirToEdge.x = contrastE > contrastW ? 1. : -1.;
+					dirToEdge.y = contrastS > contrastN ? 1. : -1.;
+					// . 2 .      . 1 .
+					// 1 0 2  ~=  0 0 1
+					// . 1 .      . 0 .
+
+					// tap 2 pixels and see which ones are "outside" the edge, to
+					// determine if the edge is vertical or horizontal
+
+					vec4 rgbaAlongH = FxaaTexOff(tex, posM, vec2( dirToEdge.x, -dirToEdge.y ), fxaaQualityRcpFrame.xy);
+					float matchAlongH = contrast( rgbaM, rgbaAlongH );
+					// . 1 .
+					// 0 0 1
+					// . 0 H
+
+					vec4 rgbaAlongV = FxaaTexOff(tex, posM, vec2( -dirToEdge.x, dirToEdge.y ), fxaaQualityRcpFrame.xy);
+					float matchAlongV = contrast( rgbaM, rgbaAlongV );
+					// V 1 .
+					// 0 0 1
+					// . 0 .
+
+					relativeVContrast = matchAlongV - matchAlongH;
+					relativeVContrast *= fxaaQualityinvEdgeThreshold;
+
+					if( abs( relativeVContrast ) < .3 ) { // 45 deg edge
+							// 1 1 .
+							// 0 0 1
+							// . 0 1
+
+							// do a simple blur
+							return mix(
+									rgbaM,
+									(rgbaN + rgbaS + rgbaE + rgbaW) * .25,
+									.4
+							);
+					}
+
+					horzSpan = relativeVContrast > 0.;
+			}
 
-		uniform sampler2D tDiffuse;
+			if(!horzSpan) rgbaN = rgbaW;
+			if(!horzSpan) rgbaS = rgbaE;
+			// . 0 .      1
+			// 1 0 1  ->  0
+			// . 0 .      1
+
+			bool pairN = contrast( rgbaM, rgbaN ) > contrast( rgbaM, rgbaS );
+			if(!pairN) rgbaN = rgbaS;
+
+			vec2 offNP;
+			offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;
+			offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;
+
+			bool doneN = false;
+			bool doneP = false;
+
+			float nDist = 0.;
+			float pDist = 0.;
+
+			vec2 posN = posM;
+			vec2 posP = posM;
+
+			int iterationsUsed = 0;
+			int iterationsUsedN = 0;
+			int iterationsUsedP = 0;
+			for( int i = 0; i < NUM_SAMPLES; i++ ) {
+					iterationsUsed = i;
+
+					float increment = float(i + 1);
+
+					if(!doneN) {
+							nDist += increment;
+							posN = posM + offNP * nDist;
+							vec4 rgbaEndN = FxaaTexTop(tex, posN.xy);
+							doneN = contrast( rgbaEndN, rgbaM ) > contrast( rgbaEndN, rgbaN );
+							iterationsUsedN = i;
+					}
+
+					if(!doneP) {
+							pDist += increment;
+							posP = posM - offNP * pDist;
+							vec4 rgbaEndP = FxaaTexTop(tex, posP.xy);
+							doneP = contrast( rgbaEndP, rgbaM ) > contrast( rgbaEndP, rgbaN );
+							iterationsUsedP = i;
+					}
+
+					if(doneN || doneP) break;
+			}
 
-		uniform vec2 resolution;
 
-		varying vec2 vUv;
+			if ( !doneP && !doneN ) return rgbaM; // failed to find end of edge
 
-		// FXAA 3.11 implementation by NVIDIA, ported to WebGL by Agost Biro ([email protected])
-
-		//----------------------------------------------------------------------------------
-		// File:        es3-kepler\FXAA\assets\shaders/FXAA_DefaultES.frag
-		// SDK Version: v3.00
-		// Email:       [email protected]
-		// Site:        http://developer.nvidia.com/
-		//
-		// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
-		//
-		// Redistribution and use in source and binary forms, with or without
-		// modification, are permitted provided that the following conditions
-		// are met:
-		//  * Redistributions of source code must retain the above copyright
-		//    notice, this list of conditions and the following disclaimer.
-		//  * Redistributions in binary form must reproduce the above copyright
-		//    notice, this list of conditions and the following disclaimer in the
-		//    documentation and/or other materials provided with the distribution.
-		//  * Neither the name of NVIDIA CORPORATION nor the names of its
-		//    contributors may be used to endorse or promote products derived
-		//    from this software without specific prior written permission.
-		//
-		// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
-		// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-		// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-		// PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-		// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-		// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-		// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-		// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
-		// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-		// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-		// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-		//
-		//----------------------------------------------------------------------------------
-
-		#ifndef FXAA_DISCARD
-				//
-				// Only valid for PC OpenGL currently.
-				// Probably will not work when FXAA_GREEN_AS_LUMA = 1.
-				//
-				// 1 = Use discard on pixels which don't need AA.
-				//     For APIs which enable concurrent TEX+ROP from same surface.
-				// 0 = Return unchanged color on pixels which don't need AA.
-				//
-				#define FXAA_DISCARD 0
-		#endif
-
-		/*--------------------------------------------------------------------------*/
-		#define FxaaTexTop(t, p) texture2D(t, p, -100.0)
-		#define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r), -100.0)
-		/*--------------------------------------------------------------------------*/
-
-		#define NUM_SAMPLES 5
-
-		// assumes colors have premultipliedAlpha, so that the calculated color contrast is scaled by alpha
-		float contrast( vec4 a, vec4 b ) {
-				vec4 diff = abs( a - b );
-				return max( max( max( diff.r, diff.g ), diff.b ), diff.a );
-		}
-
-		/*============================================================================
-
-										FXAA3 QUALITY - PC
-
-		============================================================================*/
-
-		/*--------------------------------------------------------------------------*/
-		vec4 FxaaPixelShader(
-				vec2 posM,
-				sampler2D tex,
-				vec2 fxaaQualityRcpFrame,
-				float fxaaQualityEdgeThreshold,
-				float fxaaQualityinvEdgeThreshold
-		) {
-				vec4 rgbaM = FxaaTexTop(tex, posM);
-				vec4 rgbaS = FxaaTexOff(tex, posM, vec2( 0.0, 1.0), fxaaQualityRcpFrame.xy);
-				vec4 rgbaE = FxaaTexOff(tex, posM, vec2( 1.0, 0.0), fxaaQualityRcpFrame.xy);
-				vec4 rgbaN = FxaaTexOff(tex, posM, vec2( 0.0,-1.0), fxaaQualityRcpFrame.xy);
-				vec4 rgbaW = FxaaTexOff(tex, posM, vec2(-1.0, 0.0), fxaaQualityRcpFrame.xy);
-				// . S .
-				// W M E
-				// . N .
-
-				bool earlyExit = max( max( max(
-						contrast( rgbaM, rgbaN ),
-						contrast( rgbaM, rgbaS ) ),
-						contrast( rgbaM, rgbaE ) ),
-						contrast( rgbaM, rgbaW ) )
-						< fxaaQualityEdgeThreshold;
-				// . 0 .
-				// 0 0 0
-				// . 0 .
-
-				#if (FXAA_DISCARD == 1)
-						if(earlyExit) FxaaDiscard;
-				#else
-						if(earlyExit) return rgbaM;
-				#endif
-
-				float contrastN = contrast( rgbaM, rgbaN );
-				float contrastS = contrast( rgbaM, rgbaS );
-				float contrastE = contrast( rgbaM, rgbaE );
-				float contrastW = contrast( rgbaM, rgbaW );
-
-				float relativeVContrast = ( contrastN + contrastS ) - ( contrastE + contrastW );
-				relativeVContrast *= fxaaQualityinvEdgeThreshold;
-
-				bool horzSpan = relativeVContrast > 0.;
-				// . 1 .
-				// 0 0 0
-				// . 1 .
-
-				// 45 deg edge detection and corners of objects, aka V/H contrast is too similar
-				if( abs( relativeVContrast ) < .3 ) {
-						// locate the edge
-						vec2 dirToEdge;
-						dirToEdge.x = contrastE > contrastW ? 1. : -1.;
-						dirToEdge.y = contrastS > contrastN ? 1. : -1.;
-						// . 2 .      . 1 .
-						// 1 0 2  ~=  0 0 1
-						// . 1 .      . 0 .
-
-						// tap 2 pixels and see which ones are "outside" the edge, to
-						// determine if the edge is vertical or horizontal
-
-						vec4 rgbaAlongH = FxaaTexOff(tex, posM, vec2( dirToEdge.x, -dirToEdge.y ), fxaaQualityRcpFrame.xy);
-						float matchAlongH = contrast( rgbaM, rgbaAlongH );
-						// . 1 .
-						// 0 0 1
-						// . 0 H
-
-						vec4 rgbaAlongV = FxaaTexOff(tex, posM, vec2( -dirToEdge.x, dirToEdge.y ), fxaaQualityRcpFrame.xy);
-						float matchAlongV = contrast( rgbaM, rgbaAlongV );
-						// V 1 .
-						// 0 0 1
-						// . 0 .
-
-						relativeVContrast = matchAlongV - matchAlongH;
-						relativeVContrast *= fxaaQualityinvEdgeThreshold;
-
-						if( abs( relativeVContrast ) < .3 ) { // 45 deg edge
-								// 1 1 .
-								// 0 0 1
-								// . 0 1
-
-								// do a simple blur
-								return mix(
-										rgbaM,
-										(rgbaN + rgbaS + rgbaE + rgbaW) * .25,
-										.4
-								);
-						}
-
-						horzSpan = relativeVContrast > 0.;
-				}
-
-				if(!horzSpan) rgbaN = rgbaW;
-				if(!horzSpan) rgbaS = rgbaE;
-				// . 0 .      1
-				// 1 0 1  ->  0
-				// . 0 .      1
-
-				bool pairN = contrast( rgbaM, rgbaN ) > contrast( rgbaM, rgbaS );
-				if(!pairN) rgbaN = rgbaS;
-
-				vec2 offNP;
-				offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;
-				offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;
-
-				bool doneN = false;
-				bool doneP = false;
-
-				float nDist = 0.;
-				float pDist = 0.;
-
-				vec2 posN = posM;
-				vec2 posP = posM;
-
-				int iterationsUsed = 0;
-				int iterationsUsedN = 0;
-				int iterationsUsedP = 0;
-				for( int i = 0; i < NUM_SAMPLES; i++ ) {
-						iterationsUsed = i;
-
-						float increment = float(i + 1);
-
-						if(!doneN) {
-								nDist += increment;
-								posN = posM + offNP * nDist;
-								vec4 rgbaEndN = FxaaTexTop(tex, posN.xy);
-								doneN = contrast( rgbaEndN, rgbaM ) > contrast( rgbaEndN, rgbaN );
-								iterationsUsedN = i;
-						}
-
-						if(!doneP) {
-								pDist += increment;
-								posP = posM - offNP * pDist;
-								vec4 rgbaEndP = FxaaTexTop(tex, posP.xy);
-								doneP = contrast( rgbaEndP, rgbaM ) > contrast( rgbaEndP, rgbaN );
-								iterationsUsedP = i;
-						}
-
-						if(doneN || doneP) break;
-				}
-
-
-				if ( !doneP && !doneN ) return rgbaM; // failed to find end of edge
-
-				float dist = min(
-						doneN ? float( iterationsUsedN ) / float( NUM_SAMPLES - 1 ) : 1.,
-						doneP ? float( iterationsUsedP ) / float( NUM_SAMPLES - 1 ) : 1.
-				);
-
-				// hacky way of reduces blurriness of mostly diagonal edges
-				// but reduces AA quality
-				dist = pow(dist, .5);
-
-				dist = 1. - dist;
-
-				return mix(
-						rgbaM,
-						rgbaN,
-						dist * .5
-				);
-		}
+			float dist = min(
+					doneN ? float( iterationsUsedN ) / float( NUM_SAMPLES - 1 ) : 1.,
+					doneP ? float( iterationsUsedP ) / float( NUM_SAMPLES - 1 ) : 1.
+			);
 
-		void main() {
-				const float edgeDetectionQuality = .2;
-				const float invEdgeDetectionQuality = 1. / edgeDetectionQuality;
-
-				gl_FragColor = FxaaPixelShader(
-						vUv,
-						tDiffuse,
-						resolution,
-						edgeDetectionQuality, // [0,1] contrast needed, otherwise early discard
-						invEdgeDetectionQuality
-				);
-
-		}
-		`
+			// hacky way of reduces blurriness of mostly diagonal edges
+			// but reduces AA quality
+			dist = pow(dist, .5);
+
+			dist = 1. - dist;
+
+			return mix(
+					rgbaM,
+					rgbaN,
+					dist * .5
+			);
+	}
+
+	void main() {
+			const float edgeDetectionQuality = .2;
+			const float invEdgeDetectionQuality = 1. / edgeDetectionQuality;
+
+			gl_FragColor = FxaaPixelShader(
+					vUv,
+					tDiffuse,
+					resolution,
+					edgeDetectionQuality, // [0,1] contrast needed, otherwise early discard
+					invEdgeDetectionQuality
+			);
+
+	}
+	`
+	};
 
 	THREE.FXAAShader = FXAAShader;
 

+ 59 - 0
examples/js/utils/SceneUtils.js

@@ -23,6 +23,64 @@
 
 	}
 
+	function createMeshesFromMultiMaterialMesh( mesh ) {
+
+		if ( Array.isArray( mesh.material ) === false ) {
+
+			console.warn( 'THREE.SceneUtils.createMeshesFromMultiMaterialMesh(): The given mesh has no multiple materials.' );
+			return mesh;
+
+		}
+
+		const object = new THREE.Group();
+		object.copy( mesh ); // merge groups (which automatically sorts them)
+
+		const geometry = THREE.mergeGroups( mesh.geometry );
+		const index = geometry.index;
+		const groups = geometry.groups;
+		const attributeNames = Object.keys( geometry.attributes ); // create a mesh for each group by extracting the buffer data into a new geometry
+
+		for ( let i = 0; i < groups.length; i ++ ) {
+
+			const group = groups[ i ];
+			const start = group.start;
+			const end = start + group.count;
+			const newGeometry = new THREE.BufferGeometry();
+			const newMaterial = mesh.material[ group.materialIndex ]; // process all buffer attributes
+
+			for ( let j = 0; j < attributeNames.length; j ++ ) {
+
+				const name = attributeNames[ j ];
+				const attribute = geometry.attributes[ name ];
+				const itemSize = attribute.itemSize;
+				const newLength = group.count * itemSize;
+				const type = attribute.array.constructor;
+				const newArray = new type( newLength );
+				const newAttribute = new THREE.BufferAttribute( newArray, itemSize );
+
+				for ( let k = start, n = 0; k < end; k ++, n ++ ) {
+
+					const ind = index.getX( k );
+					if ( itemSize >= 1 ) newAttribute.setX( n, attribute.getX( ind ) );
+					if ( itemSize >= 2 ) newAttribute.setY( n, attribute.getY( ind ) );
+					if ( itemSize >= 3 ) newAttribute.setZ( n, attribute.getZ( ind ) );
+					if ( itemSize >= 4 ) newAttribute.setW( n, attribute.getW( ind ) );
+
+				}
+
+				newGeometry.setAttribute( name, newAttribute );
+
+			}
+
+			const newMesh = new THREE.Mesh( newGeometry, newMaterial );
+			object.add( newMesh );
+
+		}
+
+		return object;
+
+	}
+
 	function createMultiMaterialObject( geometry, materials ) {
 
 		const group = new THREE.Group();
@@ -54,6 +112,7 @@
 	THREE.SceneUtils = {};
 	THREE.SceneUtils.attach = attach;
 	THREE.SceneUtils.createMeshesFromInstancedMesh = createMeshesFromInstancedMesh;
+	THREE.SceneUtils.createMeshesFromMultiMaterialMesh = createMeshesFromMultiMaterialMesh;
 	THREE.SceneUtils.createMultiMaterialObject = createMultiMaterialObject;
 	THREE.SceneUtils.detach = detach;