Browse Source

Merge pull request #10702 from foijord/double-precision-uniforms

hold Matrix4 elements in double precision until uploaded to GL
Mr.doob 8 years ago
parent
commit
0baf2633d4

+ 58 - 47
build/three.js

@@ -3335,14 +3335,14 @@
 
 	function Matrix4() {
 
-		this.elements = new Float32Array( [
+		this.elements = [
 
 			1, 0, 0, 0,
 			0, 1, 0, 0,
 			0, 0, 1, 0,
 			0, 0, 0, 1
 
-		] );
+		];
 
 		if ( arguments.length > 0 ) {
 
@@ -3392,7 +3392,7 @@
 
 		copy: function ( m ) {
 
-			this.elements.set( m.elements );
+			for ( var i = 0; i < 16; i ++ ) this.elements[ i ] = m.elements[ i ];
 
 			return this;
 
@@ -3689,46 +3689,44 @@
 
 		},
 
-		multiplyMatrices: function ( a, b ) {
-
-			var ae = a.elements;
-			var be = b.elements;
-			var te = this.elements;
-
-			var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
-			var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
-			var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
-			var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
-
-			var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
-			var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
-			var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
-			var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
-
-			te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
-			te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
-			te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
-			te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
-
-			te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
-			te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
-			te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
-			te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
-
-			te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
-			te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
-			te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
-			te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
-
-			te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
-			te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
-			te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
-			te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
-
-			return this;
-
-		},
-
+		multiplyMatrices: ( function () {
+		
+			var e = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
+			
+			return function ( a, b ) {
+				
+				var ae = a.elements;
+				var be = b.elements;
+				var te = this.elements;
+				
+				e[ 0 ] = ae[ 0 ] * be[ 0 ] + ae[ 4 ] * be[ 1 ] + ae[ 8 ] * be[ 2 ] + ae[ 12 ] * be[ 3 ];
+				e[ 4 ] = ae[ 0 ] * be[ 4 ] + ae[ 4 ] * be[ 5 ] + ae[ 8 ] * be[ 6 ] + ae[ 12 ] * be[ 7 ];
+				e[ 8 ] = ae[ 0 ] * be[ 8 ] + ae[ 4 ] * be[ 9 ] + ae[ 8 ] * be[ 10 ] + ae[ 12 ] * be[ 11 ];
+				e[ 12 ] = ae[ 0 ] * be[ 12 ] + ae[ 4 ] * be[ 13 ] + ae[ 8 ] * be[ 14 ] + ae[ 12 ] * be[ 15 ];
+				
+				e[ 1 ] = ae[ 1 ] * be[ 0 ] + ae[ 5 ] * be[ 1 ] + ae[ 9 ] * be[ 2 ] + ae[ 13 ] * be[ 3 ];
+				e[ 5 ] = ae[ 1 ] * be[ 4 ] + ae[ 5 ] * be[ 5 ] + ae[ 9 ] * be[ 6 ] + ae[ 13 ] * be[ 7 ];
+				e[ 9 ] = ae[ 1 ] * be[ 8 ] + ae[ 5 ] * be[ 9 ] + ae[ 9 ] * be[ 10 ] + ae[ 13 ] * be[ 11 ];
+				e[ 13 ] = ae[ 1 ] * be[ 12 ] + ae[ 5 ] * be[ 13 ] + ae[ 9 ] * be[ 14 ] + ae[ 13 ] * be[ 15 ];
+				
+				e[ 2 ] = ae[ 2 ] * be[ 0 ] + ae[ 6 ] * be[ 1 ] + ae[ 10 ] * be[ 2 ] + ae[ 14 ] * be[ 3 ];
+				e[ 6 ] = ae[ 2 ] * be[ 4 ] + ae[ 6 ] * be[ 5 ] + ae[ 10 ] * be[ 6 ] + ae[ 14 ] * be[ 7 ];
+				e[ 10 ] = ae[ 2 ] * be[ 8 ] + ae[ 6 ] * be[ 9 ] + ae[ 10 ] * be[ 10 ] + ae[ 14 ] * be[ 11 ];
+				e[ 14 ] = ae[ 2 ] * be[ 12 ] + ae[ 6 ] * be[ 13 ] + ae[ 10 ] * be[ 14 ] + ae[ 14 ] * be[ 15 ];
+				
+				e[ 3 ] = ae[ 3 ] * be[ 0 ] + ae[ 7 ] * be[ 1 ] + ae[ 11 ] * be[ 2 ] + ae[ 15 ] * be[ 3 ];
+				e[ 7 ] = ae[ 3 ] * be[ 4 ] + ae[ 7 ] * be[ 5 ] + ae[ 11 ] * be[ 6 ] + ae[ 15 ] * be[ 7 ];
+				e[ 11 ] = ae[ 3 ] * be[ 8 ] + ae[ 7 ] * be[ 9 ] + ae[ 11 ] * be[ 10 ] + ae[ 15 ] * be[ 11 ];
+				e[ 15 ] = ae[ 3 ] * be[ 12 ] + ae[ 7 ] * be[ 13 ] + ae[ 11 ] * be[ 14 ] + ae[ 15 ] * be[ 15 ];
+				
+				for ( var i = 0; i < 16; i ++ ) te[ i ] = e[ i ];
+				
+				return this;
+				
+			};
+			
+		} )(),
+		
 		multiplyToArray: function ( a, b, r ) {
 
 			var te = this.elements;
@@ -4103,8 +4101,7 @@
 				position.z = te[ 14 ];
 
 				// scale the rotation part
-
-				matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy()
+				for ( var i = 0; i < 16; i ++ ) matrix.elements[ i ] = this.elements[ i ]; // at this point matrix is incomplete so we can't use .copy()
 
 				var invSX = 1 / sx;
 				var invSY = 1 / sy;
@@ -4346,6 +4343,10 @@
 	var arrayCacheF32 = [];
 	var arrayCacheI32 = [];
 
+	// Float32Array cache used for uploading Matrix4 uniform
+
+	var mat4array = new Float32Array(16);
+
 	// Flattening for arrays of vectors and matrices
 
 	function flatten( array, nBlocks, blockSize ) {
@@ -4456,8 +4457,18 @@
 
 	function setValue4fm( gl, v ) {
 
-		gl.uniformMatrix4fv( this.addr, false, v.elements || v );
-
+		if ( v.elements === undefined ) {
+			
+			gl.uniformMatrix4fv( this.addr, false, v );
+			
+		}
+		else {
+			
+			mat4array.set(v.elements);
+			gl.uniformMatrix4fv( this.addr, false, mat4array );
+			
+		}
+		
 	}
 
 	// Single texture (2D / Cube)

+ 58 - 47
build/three.module.js

@@ -3329,14 +3329,14 @@ Object.assign( Vector3.prototype, {
 
 function Matrix4() {
 
-	this.elements = new Float32Array( [
+	this.elements = [
 
 		1, 0, 0, 0,
 		0, 1, 0, 0,
 		0, 0, 1, 0,
 		0, 0, 0, 1
 
-	] );
+	];
 
 	if ( arguments.length > 0 ) {
 
@@ -3386,7 +3386,7 @@ Object.assign( Matrix4.prototype, {
 
 	copy: function ( m ) {
 
-		this.elements.set( m.elements );
+		for ( var i = 0; i < 16; i ++ ) this.elements[ i ] = m.elements[ i ];
 
 		return this;
 
@@ -3683,46 +3683,44 @@ Object.assign( Matrix4.prototype, {
 
 	},
 
-	multiplyMatrices: function ( a, b ) {
-
-		var ae = a.elements;
-		var be = b.elements;
-		var te = this.elements;
-
-		var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
-		var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
-		var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
-		var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
-
-		var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
-		var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
-		var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
-		var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
-
-		te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
-		te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
-		te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
-		te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
-
-		te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
-		te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
-		te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
-		te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
-
-		te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
-		te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
-		te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
-		te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
-
-		te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
-		te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
-		te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
-		te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
-
-		return this;
-
-	},
-
+	multiplyMatrices: ( function () {
+	
+		var e = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
+		
+		return function ( a, b ) {
+			
+			var ae = a.elements;
+			var be = b.elements;
+			var te = this.elements;
+			
+			e[ 0 ] = ae[ 0 ] * be[ 0 ] + ae[ 4 ] * be[ 1 ] + ae[ 8 ] * be[ 2 ] + ae[ 12 ] * be[ 3 ];
+			e[ 4 ] = ae[ 0 ] * be[ 4 ] + ae[ 4 ] * be[ 5 ] + ae[ 8 ] * be[ 6 ] + ae[ 12 ] * be[ 7 ];
+			e[ 8 ] = ae[ 0 ] * be[ 8 ] + ae[ 4 ] * be[ 9 ] + ae[ 8 ] * be[ 10 ] + ae[ 12 ] * be[ 11 ];
+			e[ 12 ] = ae[ 0 ] * be[ 12 ] + ae[ 4 ] * be[ 13 ] + ae[ 8 ] * be[ 14 ] + ae[ 12 ] * be[ 15 ];
+			
+			e[ 1 ] = ae[ 1 ] * be[ 0 ] + ae[ 5 ] * be[ 1 ] + ae[ 9 ] * be[ 2 ] + ae[ 13 ] * be[ 3 ];
+			e[ 5 ] = ae[ 1 ] * be[ 4 ] + ae[ 5 ] * be[ 5 ] + ae[ 9 ] * be[ 6 ] + ae[ 13 ] * be[ 7 ];
+			e[ 9 ] = ae[ 1 ] * be[ 8 ] + ae[ 5 ] * be[ 9 ] + ae[ 9 ] * be[ 10 ] + ae[ 13 ] * be[ 11 ];
+			e[ 13 ] = ae[ 1 ] * be[ 12 ] + ae[ 5 ] * be[ 13 ] + ae[ 9 ] * be[ 14 ] + ae[ 13 ] * be[ 15 ];
+			
+			e[ 2 ] = ae[ 2 ] * be[ 0 ] + ae[ 6 ] * be[ 1 ] + ae[ 10 ] * be[ 2 ] + ae[ 14 ] * be[ 3 ];
+			e[ 6 ] = ae[ 2 ] * be[ 4 ] + ae[ 6 ] * be[ 5 ] + ae[ 10 ] * be[ 6 ] + ae[ 14 ] * be[ 7 ];
+			e[ 10 ] = ae[ 2 ] * be[ 8 ] + ae[ 6 ] * be[ 9 ] + ae[ 10 ] * be[ 10 ] + ae[ 14 ] * be[ 11 ];
+			e[ 14 ] = ae[ 2 ] * be[ 12 ] + ae[ 6 ] * be[ 13 ] + ae[ 10 ] * be[ 14 ] + ae[ 14 ] * be[ 15 ];
+			
+			e[ 3 ] = ae[ 3 ] * be[ 0 ] + ae[ 7 ] * be[ 1 ] + ae[ 11 ] * be[ 2 ] + ae[ 15 ] * be[ 3 ];
+			e[ 7 ] = ae[ 3 ] * be[ 4 ] + ae[ 7 ] * be[ 5 ] + ae[ 11 ] * be[ 6 ] + ae[ 15 ] * be[ 7 ];
+			e[ 11 ] = ae[ 3 ] * be[ 8 ] + ae[ 7 ] * be[ 9 ] + ae[ 11 ] * be[ 10 ] + ae[ 15 ] * be[ 11 ];
+			e[ 15 ] = ae[ 3 ] * be[ 12 ] + ae[ 7 ] * be[ 13 ] + ae[ 11 ] * be[ 14 ] + ae[ 15 ] * be[ 15 ];
+			
+			for ( var i = 0; i < 16; i ++ ) te[ i ] = e[ i ];
+			
+			return this;
+			
+		};
+		
+	} )(),
+	
 	multiplyToArray: function ( a, b, r ) {
 
 		var te = this.elements;
@@ -4097,8 +4095,7 @@ Object.assign( Matrix4.prototype, {
 			position.z = te[ 14 ];
 
 			// scale the rotation part
-
-			matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy()
+			for ( var i = 0; i < 16; i ++ ) matrix.elements[ i ] = this.elements[ i ]; // at this point matrix is incomplete so we can't use .copy()
 
 			var invSX = 1 / sx;
 			var invSY = 1 / sy;
@@ -4340,6 +4337,10 @@ function UniformContainer() {
 var arrayCacheF32 = [];
 var arrayCacheI32 = [];
 
+// Float32Array cache used for uploading Matrix4 uniform
+
+var mat4array = new Float32Array(16);
+
 // Flattening for arrays of vectors and matrices
 
 function flatten( array, nBlocks, blockSize ) {
@@ -4450,8 +4451,18 @@ function setValue3fm( gl, v ) {
 
 function setValue4fm( gl, v ) {
 
-	gl.uniformMatrix4fv( this.addr, false, v.elements || v );
-
+	if ( v.elements === undefined ) {
+		
+		gl.uniformMatrix4fv( this.addr, false, v );
+		
+	}
+	else {
+		
+		mat4array.set(v.elements);
+		gl.uniformMatrix4fv( this.addr, false, mat4array );
+		
+	}
+	
 }
 
 // Single texture (2D / Cube)

+ 19 - 16
examples/webgl_interactive_cubes.html

@@ -25,7 +25,8 @@
 			var camera, scene, raycaster, renderer;
 
 			var mouse = new THREE.Vector2(), INTERSECTED;
-			var radius = 100, theta = 0;
+                        var radius = 1, theta = 0;
+                        var offset = new THREE.Vector3(100000, 100000, 100000);
 
 			init();
 			animate();
@@ -43,7 +44,7 @@
 				info.innerHTML = '<a href="http://threejs.org" target="_blank">three.js</a> webgl - interactive cubes';
 				container.appendChild( info );
 
-				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
+				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, .1, 10000 );
 
 				scene = new THREE.Scene();
 
@@ -51,25 +52,24 @@
 				light.position.set( 1, 1, 1 ).normalize();
 				scene.add( light );
 
-				var geometry = new THREE.BoxBufferGeometry( 20, 20, 20 );
+				var geometry = new THREE.BoxBufferGeometry( .001, .1, .1 );
 
-				for ( var i = 0; i < 2000; i ++ ) {
+				for ( var j = 0; j < 10; j ++ ) {
+					for ( var k = 0; k < 10; k ++ ) {
 
-					var object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );
+						var object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );
 
-					object.position.x = Math.random() * 800 - 400;
-					object.position.y = Math.random() * 800 - 400;
-					object.position.z = Math.random() * 800 - 400;
+						var position = new THREE.Vector3( 0, j/10, k/10 );
+						position.add( offset );
 
-					object.rotation.x = Math.random() * 2 * Math.PI;
-					object.rotation.y = Math.random() * 2 * Math.PI;
-					object.rotation.z = Math.random() * 2 * Math.PI;
+						var scale = new THREE.Vector3( 0.1, 1, 1 );
 
-					object.scale.x = Math.random() + 0.5;
-					object.scale.y = Math.random() + 0.5;
-					object.scale.z = Math.random() + 0.5;
+						object.matrixAutoUpdate = false;
+						object.matrix.setPosition( position );
+						object.matrix.scale( scale );
 
-					scene.add( object );
+						scene.add( object );
+					}
 
 				}
 
@@ -124,11 +124,14 @@
 
 			function render() {
 
-				theta += 0.1;
+				theta = 20;
 
 				camera.position.x = radius * Math.sin( THREE.Math.degToRad( theta ) );
 				camera.position.y = radius * Math.sin( THREE.Math.degToRad( theta ) );
 				camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) );
+
+				camera.position.add( offset );
+
 				camera.lookAt( scene.position );
 
 				camera.updateMatrixWorld();

+ 15 - 14
examples/webgl_performance.html

@@ -57,21 +57,22 @@
 
 					geometry.computeVertexNormals();
 
-					for ( var i = 0; i < 5000; i ++ ) {
+					for ( var i = 0; i < 25; i ++ ) {
+						for ( var j = 0; j < 25; j ++ ) {
+							for ( var k = 0; k < 25; k ++ ) {
 
-						var mesh = new THREE.Mesh( geometry, material );
+								var mesh = new THREE.Mesh( geometry, material );
 
-						mesh.position.x = Math.random() * 8000 - 4000;
-						mesh.position.y = Math.random() * 8000 - 4000;
-						mesh.position.z = Math.random() * 8000 - 4000;
-						mesh.rotation.x = Math.random() * 2 * Math.PI;
-						mesh.rotation.y = Math.random() * 2 * Math.PI;
-						mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 50 + 100;
+								mesh.position.x = (i / 20) * 8000 - 4000;
+								mesh.position.y = (j / 20) * 8000 - 4000;
+								mesh.position.z = (k / 20) * 8000 - 4000;
+								mesh.scale.x = mesh.scale.y = mesh.scale.z = 50 + 100;
 
-						objects.push( mesh );
-
-						scene.add( mesh );
+								objects.push( mesh );
 
+								scene.add( mesh );
+							}
+						}
 					}
 
 				} );
@@ -123,8 +124,8 @@
 
 			function render() {
 
-				camera.position.x += ( mouseX - camera.position.x ) * .05;
-				camera.position.y += ( - mouseY - camera.position.y ) * .05;
+				// camera.position.x += ( mouseX - camera.position.x ) * .05;
+				// camera.position.y += ( - mouseY - camera.position.y ) * .05;
 				camera.lookAt( scene.position );
 
 				for ( var i = 0, il = objects.length; i < il; i ++ ) {
@@ -141,4 +142,4 @@
 		</script>
 
 	</body>
-</html>
+</html

+ 42 - 45
src/math/Matrix4.js

@@ -15,14 +15,14 @@ import { Vector3 } from './Vector3';
 
 function Matrix4() {
 
-	this.elements = new Float32Array( [
+	this.elements = [
 
 		1, 0, 0, 0,
 		0, 1, 0, 0,
 		0, 0, 1, 0,
 		0, 0, 0, 1
 
-	] );
+	];
 
 	if ( arguments.length > 0 ) {
 
@@ -72,7 +72,7 @@ Object.assign( Matrix4.prototype, {
 
 	copy: function ( m ) {
 
-		this.elements.set( m.elements );
+		for ( var i = 0; i < 16; i ++ ) this.elements[ i ] = m.elements[ i ];
 
 		return this;
 
@@ -369,46 +369,44 @@ Object.assign( Matrix4.prototype, {
 
 	},
 
-	multiplyMatrices: function ( a, b ) {
-
-		var ae = a.elements;
-		var be = b.elements;
-		var te = this.elements;
-
-		var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
-		var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
-		var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
-		var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
-
-		var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
-		var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
-		var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
-		var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
-
-		te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
-		te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
-		te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
-		te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
-
-		te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
-		te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
-		te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
-		te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
-
-		te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
-		te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
-		te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
-		te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
-
-		te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
-		te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
-		te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
-		te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
-
-		return this;
-
-	},
-
+	multiplyMatrices: ( function () {
+	
+		var e = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
+		
+		return function ( a, b ) {
+			
+			var ae = a.elements;
+			var be = b.elements;
+			var te = this.elements;
+			
+			e[ 0 ] = ae[ 0 ] * be[ 0 ] + ae[ 4 ] * be[ 1 ] + ae[ 8 ] * be[ 2 ] + ae[ 12 ] * be[ 3 ];
+			e[ 4 ] = ae[ 0 ] * be[ 4 ] + ae[ 4 ] * be[ 5 ] + ae[ 8 ] * be[ 6 ] + ae[ 12 ] * be[ 7 ];
+			e[ 8 ] = ae[ 0 ] * be[ 8 ] + ae[ 4 ] * be[ 9 ] + ae[ 8 ] * be[ 10 ] + ae[ 12 ] * be[ 11 ];
+			e[ 12 ] = ae[ 0 ] * be[ 12 ] + ae[ 4 ] * be[ 13 ] + ae[ 8 ] * be[ 14 ] + ae[ 12 ] * be[ 15 ];
+			
+			e[ 1 ] = ae[ 1 ] * be[ 0 ] + ae[ 5 ] * be[ 1 ] + ae[ 9 ] * be[ 2 ] + ae[ 13 ] * be[ 3 ];
+			e[ 5 ] = ae[ 1 ] * be[ 4 ] + ae[ 5 ] * be[ 5 ] + ae[ 9 ] * be[ 6 ] + ae[ 13 ] * be[ 7 ];
+			e[ 9 ] = ae[ 1 ] * be[ 8 ] + ae[ 5 ] * be[ 9 ] + ae[ 9 ] * be[ 10 ] + ae[ 13 ] * be[ 11 ];
+			e[ 13 ] = ae[ 1 ] * be[ 12 ] + ae[ 5 ] * be[ 13 ] + ae[ 9 ] * be[ 14 ] + ae[ 13 ] * be[ 15 ];
+			
+			e[ 2 ] = ae[ 2 ] * be[ 0 ] + ae[ 6 ] * be[ 1 ] + ae[ 10 ] * be[ 2 ] + ae[ 14 ] * be[ 3 ];
+			e[ 6 ] = ae[ 2 ] * be[ 4 ] + ae[ 6 ] * be[ 5 ] + ae[ 10 ] * be[ 6 ] + ae[ 14 ] * be[ 7 ];
+			e[ 10 ] = ae[ 2 ] * be[ 8 ] + ae[ 6 ] * be[ 9 ] + ae[ 10 ] * be[ 10 ] + ae[ 14 ] * be[ 11 ];
+			e[ 14 ] = ae[ 2 ] * be[ 12 ] + ae[ 6 ] * be[ 13 ] + ae[ 10 ] * be[ 14 ] + ae[ 14 ] * be[ 15 ];
+			
+			e[ 3 ] = ae[ 3 ] * be[ 0 ] + ae[ 7 ] * be[ 1 ] + ae[ 11 ] * be[ 2 ] + ae[ 15 ] * be[ 3 ];
+			e[ 7 ] = ae[ 3 ] * be[ 4 ] + ae[ 7 ] * be[ 5 ] + ae[ 11 ] * be[ 6 ] + ae[ 15 ] * be[ 7 ];
+			e[ 11 ] = ae[ 3 ] * be[ 8 ] + ae[ 7 ] * be[ 9 ] + ae[ 11 ] * be[ 10 ] + ae[ 15 ] * be[ 11 ];
+			e[ 15 ] = ae[ 3 ] * be[ 12 ] + ae[ 7 ] * be[ 13 ] + ae[ 11 ] * be[ 14 ] + ae[ 15 ] * be[ 15 ];
+			
+			for ( var i = 0; i < 16; i ++ ) te[ i ] = e[ i ];
+			
+			return this;
+			
+		};
+		
+	} )(),
+	
 	multiplyToArray: function ( a, b, r ) {
 
 		var te = this.elements;
@@ -783,8 +781,7 @@ Object.assign( Matrix4.prototype, {
 			position.z = te[ 14 ];
 
 			// scale the rotation part
-
-			matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy()
+			for ( var i = 0; i < 16; i ++ ) matrix.elements[ i ] = this.elements[ i ]; // at this point matrix is incomplete so we can't use .copy()
 
 			var invSX = 1 / sx;
 			var invSY = 1 / sy;

+ 17 - 3
src/renderers/webgl/WebGLUniforms.js

@@ -69,6 +69,10 @@ function UniformContainer() {
 var arrayCacheF32 = [];
 var arrayCacheI32 = [];
 
+// Float32Array cache used for uploading Matrix4 uniform
+
+var mat4array = new Float32Array(16);
+
 // Flattening for arrays of vectors and matrices
 
 function flatten( array, nBlocks, blockSize ) {
@@ -179,8 +183,18 @@ function setValue3fm( gl, v ) {
 
 function setValue4fm( gl, v ) {
 
-	gl.uniformMatrix4fv( this.addr, false, v.elements || v );
-
+	if ( v.elements === undefined ) {
+		
+		gl.uniformMatrix4fv( this.addr, false, v );
+		
+	}
+	else {
+		
+		mat4array.set(v.elements);
+		gl.uniformMatrix4fv( this.addr, false, mat4array );
+		
+	}
+	
 }
 
 // Single texture (2D / Cube)
@@ -467,7 +481,7 @@ function WebGLUniforms( gl, program, renderer ) {
 
 	var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
 
-	for ( var i = 0; i < n; ++ i ) {
+	for ( var i = 0; i !== n; ++ i ) {
 
 		var info = gl.getActiveUniform( program, i ),
 			path = info.name,