Browse Source

Merge pull request #8040 from daoshengmu/optimizeSoftwareRender

Fix bug of SoftwareRender sprite and optimize it
Mr.doob 9 years ago
parent
commit
fe2fb084cd
2 changed files with 234 additions and 118 deletions
  1. 180 110
      examples/js/renderers/SoftwareRenderer.js
  2. 54 8
      examples/software_sandbox.html

+ 180 - 110
examples/js/renderers/SoftwareRenderer.js

@@ -52,13 +52,20 @@ THREE.SoftwareRenderer = function ( parameters ) {
 
 	var projector = new THREE.Projector();
 
-	var vector1 = new THREE.Vector3();
-	var vector2 = new THREE.Vector3();
-	var vector3 = new THREE.Vector3();
+	var spriteV1 = new THREE.Vector4();
+	var spriteV2 = new THREE.Vector4();
+	var spriteV3 = new THREE.Vector4();
 
-	var texCoord1 = new THREE.Vector2();
-	var texCoord2 = new THREE.Vector2();
-	var texCoord3 = new THREE.Vector2();
+	var spriteUV1 = new THREE.Vector2();
+	var spriteUV2 = new THREE.Vector2();
+	var spriteUV3 = new THREE.Vector2();
+
+	var mpVPool = [];
+	var mpVPoolCount = 0;
+	var mpNPool = [];
+	var mpNPoolCount = 0;
+	var mpUVPool = [];
+	var mpUVPoolCount = 0;
 
 	this.domElement = canvas;
 
@@ -134,6 +141,9 @@ THREE.SoftwareRenderer = function ( parameters ) {
 		recty1 = Infinity;
 		rectx2 = 0;
 		recty2 = 0;
+		mpVPoolCount = 0;
+		mpNPoolCount = 0;
+		mpUVPoolCount = 0;
 
 		for ( var i = 0; i < numBlocks; i ++ ) {
 
@@ -190,68 +200,68 @@ THREE.SoftwareRenderer = function ( parameters ) {
 				var scaleX = element.scale.x * 0.5;
 				var scaleY = element.scale.y * 0.5;
 
-				vector1.copy( element );
-				vector1.x -= scaleX;
-				vector1.y += scaleY;
+				spriteV1.copy( element );
+				spriteV1.x -= scaleX;
+				spriteV1.y += scaleY;
 
-				vector2.copy( element );
-				vector2.x -= scaleX;
-				vector2.y -= scaleY;
+				spriteV2.copy( element );
+				spriteV2.x -= scaleX;
+				spriteV2.y -= scaleY;
 
-				vector3.copy( element );
-				vector3.x += scaleX;
-				vector3.y += scaleY;
+				spriteV3.copy( element );
+				spriteV3.x += scaleX;
+				spriteV3.y += scaleY;
 
 				if ( material.map ) {
 
-					texCoord1.set( 0, 1 );
-					texCoord2.set( 0, 0 );
-					texCoord3.set( 1, 1 );
+					spriteUV1.set( 0, 1 );
+					spriteUV2.set( 0, 0 );
+					spriteUV3.set( 1, 1 );
 
 					drawTriangle(
-						vector1, vector2, vector3,
-						texCoord1, texCoord2, texCoord3,
+						spriteV1, spriteV2, spriteV3,
+						spriteUV1, spriteUV2, spriteUV3,
 						shader, element, material
 					);
 
 				} else {
 
 					drawTriangle(
-						vector1, vector2, vector3,
+						spriteV1, spriteV2, spriteV3,
 						null, null, null,
 						shader, element, material
 					);
 
 				}
 
-				vector1.copy( element );
-				vector1.x += scaleX;
-				vector1.y += scaleY;
+				spriteV1.copy( element );
+				spriteV1.x += scaleX;
+				spriteV1.y += scaleY;
 
-				vector2.copy( element );
-				vector2.x -= scaleX;
-				vector2.y -= scaleY;
+				spriteV2.copy( element );
+				spriteV2.x -= scaleX;
+				spriteV2.y -= scaleY;
 
-				vector3.copy( element );
-				vector3.x += scaleX;
-				vector3.y -= scaleY;
+				spriteV3.copy( element );
+				spriteV3.x += scaleX;
+				spriteV3.y -= scaleY;
 
 				if ( material.map ) {
 
-					texCoord1.set( 1, 1 );
-					texCoord2.set( 0, 0 );
-					texCoord3.set( 1, 0 );
+					spriteUV1.set( 1, 1 );
+					spriteUV2.set( 0, 0 );
+					spriteUV3.set( 1, 0 );
 
 					drawTriangle(
-						vector1, vector2, vector3,
-						texCoord1, texCoord2, texCoord3,
+						spriteV1, spriteV2, spriteV3,
+						spriteUV1, spriteUV2, spriteUV3,
 						shader, element, material
 					);
 
 				} else {
 
 					drawTriangle(
-						vector1, vector2, vector3,
+						spriteV1, spriteV2, spriteV3,
 						null, null, null,
 						shader, element, material
 					);
@@ -437,25 +447,26 @@ THREE.SoftwareRenderer = function ( parameters ) {
 			buffer[ colorOffset ] = tdata[ tIndex ];
 			buffer[ colorOffset + 1 ] = tdata[ tIndex + 1 ];
 			buffer[ colorOffset + 2 ] = tdata[ tIndex + 2 ];
-			buffer[ colorOffset + 3 ] = material.opacity * 255;
+			buffer[ colorOffset + 3 ] = ( material.opacity << 8 ) - 1;
 			depthBuf[ offset ] = depth;
 
 		} else {
 
-			var opaci = tdata[ tIndex + 3 ] * material.opacity;
-			var texel = ( tdata[ tIndex ] << 16 ) + ( tdata[ tIndex + 1 ] << 8 ) + tdata[ tIndex + 2 ];
-			if ( opaci < 250 ) {
-
-				var backColor = ( buffer[ colorOffset ] << 16 ) + ( buffer[ colorOffset + 1 ] << 8 ) + buffer[ colorOffset + 2 ];
-				texel = texel * opaci + backColor * ( 1 - opaci );
-
-			}
-
-			buffer[ colorOffset ] = ( texel & 0xff0000 ) >> 16;
-			buffer[ colorOffset + 1 ] = ( texel & 0xff00 ) >> 8;
-			buffer[ colorOffset + 2 ] = texel & 0xff;
-			buffer[ colorOffset + 3 ] = material.opacity * 255;
-
+			var srcR = tdata[ tIndex ];
+			var srcG = tdata[ tIndex + 1 ];
+			var srcB = tdata[ tIndex + 2 ];
+			var opaci = tdata[ tIndex + 3 ] * material.opacity / 255;
+			var destR = buffer[ colorOffset ];
+			var destG = buffer[ colorOffset + 1 ];
+			var destB = buffer[ colorOffset + 2 ];
+	
+			buffer[ colorOffset ] = ( srcR * opaci + destR * ( 1 - opaci ) );
+			buffer[ colorOffset + 1 ] = ( srcG * opaci + destG * ( 1 - opaci ) );
+			buffer[ colorOffset + 2 ] = ( srcB * opaci + destB * ( 1 - opaci ) );
+			buffer[ colorOffset + 3 ] = ( material.opacity << 8 ) - 1;
+
+			if ( buffer[ colorOffset + 3 ] == 255 )	// Only opaue pixls write to the depth buffer
+				depthBuf[ offset ] = depth;
 		}
 
 	}
@@ -481,28 +492,26 @@ THREE.SoftwareRenderer = function ( parameters ) {
 			buffer[ colorOffset ] = ( material.palette[ cIndex ] * tdata[ tIndex ] ) >> 8;
 			buffer[ colorOffset + 1 ] = ( material.palette[ cIndex + 1 ] * tdata[ tIndex + 1 ] ) >> 8;
 			buffer[ colorOffset + 2 ] = ( material.palette[ cIndex + 2 ] * tdata[ tIndex + 2 ] ) >> 8;
-			buffer[ colorOffset + 3 ] = material.opacity * 255;
+			buffer[ colorOffset + 3 ] = ( material.opacity << 8 ) - 1;
 			depthBuf[ offset ] = depth;
 
 		} else {
 
-			var opaci = tdata[ tIndex + 3 ] * material.opacity;
-			var foreColor = ( ( material.palette[ cIndex ] * tdata[ tIndex ] ) << 16 )
-							+ ( ( material.palette[ cIndex + 1 ] * tdata[ tIndex + 1 ] ) << 8 )
-							+ ( material.palette[ cIndex + 2 ] * tdata[ tIndex + 2 ] );
-
-			if ( opaci < 250 ) {
-
-				var backColor = buffer[ colorOffset ] << 24 + buffer[ colorOffset + 1 ] << 16 + buffer[ colorOffset + 2 ] << 8;
-				foreColor = foreColor * opaci + backColor * ( 1 - opaci );
-
-			}
-
-			buffer[ colorOffset ] = ( foreColor & 0xff0000 ) >> 16;
-			buffer[ colorOffset + 1 ] = ( foreColor & 0xff00 ) >> 8;
-			buffer[ colorOffset + 2 ] = ( foreColor & 0xff );
-			buffer[ colorOffset + 3 ] = material.opacity * 255;
-
+			var foreColorR = material.palette[ cIndex ] * tdata[ tIndex ];
+			var foreColorG = material.palette[ cIndex + 1 ] * tdata[ tIndex + 1 ];
+			var foreColorB = material.palette[ cIndex + 2 ] * tdata[ tIndex + 2 ];
+			var opaci = tdata[ tIndex + 3 ] * material.opacity / 256;
+			var destR = buffer[ colorOffset ];
+			var destG = buffer[ colorOffset + 1 ];
+			var destB = buffer[ colorOffset + 2 ];
+
+			buffer[ colorOffset ] = foreColorR * opaci + destR * ( 1 - opaci );
+			buffer[ colorOffset + 1 ] = foreColorG * opaci + destG * ( 1 - opaci );
+			buffer[ colorOffset + 2 ] = foreColorB * opaci + destB * ( 1 - opaci );
+			buffer[ colorOffset + 3 ] = ( material.opacity << 8 ) - 1;
+
+			if ( buffer[ colorOffset + 3 ] == 255 )	// Only opaue pixls write to the depth buffer
+				depthBuf[ offset ] = depth;
 		}
 
 	}
@@ -688,13 +697,16 @@ THREE.SoftwareRenderer = function ( parameters ) {
 		var y3 = ( v3.y * viewportYScale + viewportYOffs ) | 0;
 
 		var bHasNormal = face.vertexNormalsModel && face.vertexNormalsModel.length;
+		var bHasUV = uv1 && uv2 && uv3;
 
 		var longestSide = Math.max(
 			Math.sqrt( (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) ),
 			Math.sqrt( (x2 - x3)*(x2 - x3) + (y2 - y3)*(y2 - y3) ),
 			Math.sqrt( (x3 - x1)*(x3 - x1) + (y3 - y1)*(y3 - y1) )
 		);
-		if( longestSide > 100 * fixscale ) {
+
+		if( !(face instanceof THREE.RenderableSprite) 
+			&& (longestSide > 100 * fixscale) ) {
 
 			// 1
 			// |\
@@ -704,32 +716,90 @@ THREE.SoftwareRenderer = function ( parameters ) {
 			// |b\|d\
 			// |__\__\
 			// 2      3
-			var	mpV12 = new THREE.Vector4(),
-				mpV23 = new THREE.Vector4(),
-				mpV31 = new THREE.Vector4(),
-				mpN12 = new THREE.Vector3(),
-				mpN23 = new THREE.Vector3(),
-				mpN31 = new THREE.Vector3(),
-				mpUV12 = new THREE.Vector2(),
-				mpUV23 = new THREE.Vector2(),
-				mpUV31 = new THREE.Vector2(),
-				tempFace = { vertexNormalsModel : []
-							, color : { r: face.color.r, g: face.color.b, b: face.color.b } };
-
-			var weight;
-
-			weight = (1 + v2.z) * (v2.w / v1.w) / (1 + v1.z);
-			mpUV12.copy( uv1 ).multiplyScalar( weight ).add( uv2 ).multiplyScalar( 1 / (weight + 1) );
-			weight = (1 + v3.z) * (v3.w / v2.w) / (1 + v2.z);
-			mpUV23.copy( uv2 ).multiplyScalar( weight ).add( uv3 ).multiplyScalar( 1 / (weight + 1) );
-			weight = (1 + v1.z) * (v1.w / v3.w) / (1 + v3.z);
-			mpUV31.copy( uv3 ).multiplyScalar( weight ).add( uv1 ).multiplyScalar( 1 / (weight + 1) );
+			var tempFace = { vertexNormalsModel : [], 
+						color : face.color };
+			var mpUV12, mpUV23, mpUV31;
+			if ( bHasUV ) {
+				if ( mpUVPoolCount === mpUVPool.length ) {
+					mpUV12 = new THREE.Vector2();
+					mpUVPool.push( mpUV12 );
+					++mpUVPoolCount;
+
+					mpUV23 = new THREE.Vector2();
+					mpUVPool.push( mpUV23 );
+					++mpUVPoolCount;
+
+					mpUV31 = new THREE.Vector2();
+					mpUVPool.push( mpUV31 );
+					++mpUVPoolCount;
+				} else {
+					mpUV12 = mpUVPool[ mpUVPoolCount ];
+					++mpUVPoolCount;				
+					mpUV23 = mpUVPool[ mpUVPoolCount ];
+					++mpUVPoolCount;
+					mpUV31 = mpUVPool[ mpUVPoolCount ];
+					++mpUVPoolCount;
+				}
+
+				var weight;
+
+				weight = (1 + v2.z) * (v2.w / v1.w) / (1 + v1.z);
+				mpUV12.copy( uv1 ).multiplyScalar( weight ).add( uv2 ).multiplyScalar( 1 / (weight + 1) );
+				weight = (1 + v3.z) * (v3.w / v2.w) / (1 + v2.z);
+				mpUV23.copy( uv2 ).multiplyScalar( weight ).add( uv3 ).multiplyScalar( 1 / (weight + 1) );
+				weight = (1 + v1.z) * (v1.w / v3.w) / (1 + v3.z);
+				mpUV31.copy( uv3 ).multiplyScalar( weight ).add( uv1 ).multiplyScalar( 1 / (weight + 1) );
+			}
+			
+			var mpV12, mpV23, mpV31;
+			if ( mpVPoolCount === mpVPool.length ) {
+				mpV12 = new THREE.Vector4();
+				mpVPool.push( mpV12 );
+				++mpVPoolCount;
+
+				mpV23 = new THREE.Vector4();
+				mpVPool.push( mpV23 );
+				++mpVPoolCount;
+
+				mpV31 = new THREE.Vector4();
+				mpVPool.push( mpV31 );
+				++mpVPoolCount;
+			} else {
+				mpV12 = mpVPool[ mpVPoolCount ];
+				++mpVPoolCount;				
+				mpV23 = mpVPool[ mpVPoolCount ];
+				++mpVPoolCount;
+				mpV31 = mpVPool[ mpVPoolCount ];
+				++mpVPoolCount;
+			}
 
 			mpV12.copy( v1 ).add( v2 ).multiplyScalar( 0.5 );
 			mpV23.copy( v2 ).add( v3 ).multiplyScalar( 0.5 );
 			mpV31.copy( v3 ).add( v1 ).multiplyScalar( 0.5 );
 
+			var mpN12, mpN23, mpN31;
 			if( bHasNormal ) {
+				if ( mpNPoolCount === mpNPool.length ) {
+					mpN12 = new THREE.Vector3();
+					mpNPool.push( mpN12 );
+					++mpNPoolCount;
+
+					mpN23 = new THREE.Vector3();
+					mpNPool.push( mpN23 );
+					++mpNPoolCount;
+
+					mpN31 = new THREE.Vector3();
+					mpNPool.push( mpN31 );
+					++mpNPoolCount;
+				} else {
+					mpN12 = mpNPool[ mpNPoolCount ];
+					++mpNPoolCount;				
+					mpN23 = mpNPool[ mpNPoolCount ];
+					++mpNPoolCount;
+					mpN31 = mpNPool[ mpNPoolCount ];
+					++mpNPoolCount;
+				}
+
 				mpN12.copy( face.vertexNormalsModel[ 0 ] ).add( face.vertexNormalsModel[ 1 ] ).normalize();
 				mpN23.copy( face.vertexNormalsModel[ 1 ] ).add( face.vertexNormalsModel[ 2 ] ).normalize();
 				mpN31.copy( face.vertexNormalsModel[ 2 ] ).add( face.vertexNormalsModel[ 0 ] ).normalize();
@@ -1298,20 +1368,20 @@ THREE.SoftwareRenderer = function ( parameters ) {
 		// TODO: Implement per-pixel z-clipping
 		if ( v1.z < -1 || v1.z > 1 || v2.z < -1 || v2.z > 1 ) return;
 
-		var halfLineWidth = Math.floor( (material.linewidth-1) * 0.5 );
+		var halfLineWidth = Math.floor( ( material.linewidth - 1 ) * 0.5 );
 
 		// https://gist.github.com/2486101
 		// explanation: http://pouet.net/topic.php?which=8760&page=1
 
 		// 28.4 fixed-point coordinates
-		var x1 = (v1.x * viewportXScale + viewportXOffs) | 0;
-		var x2 = (v2.x * viewportXScale + viewportXOffs) | 0;
+		var x1 = ( v1.x * viewportXScale + viewportXOffs ) | 0;
+		var x2 = ( v2.x * viewportXScale + viewportXOffs ) | 0;
 
-		var y1 = (v1.y * viewportYScale + viewportYOffs) | 0;
-		var y2 = (v2.y * viewportYScale + viewportYOffs) | 0;
+		var y1 = ( v1.y * viewportYScale + viewportYOffs ) | 0;
+		var y2 = ( v2.y * viewportYScale + viewportYOffs ) | 0;
 
-		var z1 = (v1.z * viewportZScale + viewportZOffs) | 0;
-		var z2 = (v2.z * viewportZScale + viewportZOffs) | 0;
+		var z1 = ( v1.z * viewportZScale + viewportZOffs ) | 0;
+		var z2 = ( v2.z * viewportZScale + viewportZOffs ) | 0;
 
 		// Deltas
 		var dx12 = x1 - x2, dy12 = y1 - y2, dz12 = z1 - z2;
@@ -1322,7 +1392,7 @@ THREE.SoftwareRenderer = function ( parameters ) {
 		var miny = Math.max( ( Math.min( y1, y2 ) + subpixelBias ) >> subpixelBits, 0 );
 		var maxy = Math.min( ( Math.max( y1, y2 ) + subpixelBias ) >> subpixelBits, canvasHeight );
 		var minz = Math.max( ( Math.min( z1, z2 ) + subpixelBias ) >> subpixelBits, 0 );
-		var maxz = Math.min( ( Math.max( z1, z2 ) + subpixelBias ) >> subpixelBits, 0 );
+		var maxz = ( Math.max( z1, z2 ) + subpixelBias ) >> subpixelBits;
 
 		rectx1 = Math.min( minx, rectx1 );
 		rectx2 = Math.max( maxx, rectx2 );
@@ -1330,10 +1400,10 @@ THREE.SoftwareRenderer = function ( parameters ) {
 		recty2 = Math.max( maxy, recty2 );
 
 		// Get the line's unit vector and cross vector
-		var length = Math.sqrt((dy12 * dy12) + (dx12 * dx12));
-		var unitX = (dx12 / length);
-		var unitY = (dy12 / length);
-		var unitZ = (dz12 / length);
+		var length = Math.sqrt( ( dy12 * dy12 ) + ( dx12 * dx12 ) );
+		var unitX = ( dx12 / length );
+		var unitY = ( dy12 / length );
+		var unitZ = ( dz12 / length );
 		var pixelX, pixelY, pixelZ;
 		var pX, pY, pZ;
 		crossVector.set( unitX, unitY, unitZ );
@@ -1343,21 +1413,21 @@ THREE.SoftwareRenderer = function ( parameters ) {
 		while (length > 0) {
 
 			// Get this pixel.
-			pixelX = (x2 + length * unitX);
-			pixelY = (y2 + length * unitY);
-			pixelZ = (z2 + length * unitZ);
+			pixelX = x2 + length * unitX;
+			pixelY = y2 + length * unitY;
+			pixelZ = z2 + length * unitZ;
 
-			pixelX = (pixelX + subpixelBias) >> subpixelBits;
-			pixelY = (pixelY + subpixelBias) >> subpixelBits;
-			pZ = (pixelZ + subpixelBias) >> subpixelBits;
+			pixelX = ( pixelX + subpixelBias ) >> subpixelBits;
+			pixelY = ( pixelY + subpixelBias ) >> subpixelBits;
+			pZ = ( pixelZ + subpixelBias ) >> subpixelBits;
 
 			// Draw line with line width
 			for ( var i = -halfLineWidth; i <= halfLineWidth; ++i ) {
 
 				// Compute the line pixels.
 				// Get the pixels on the vector that crosses to the line vector
-				pX = Math.floor((pixelX + crossVector.x * i));
-				pY = Math.floor((pixelY + crossVector.y * i));
+				pX = Math.floor( ( pixelX + crossVector.x * i ) );
+				pY = Math.floor( ( pixelY + crossVector.y * i ) );
 
 				// if pixel is over the rect. Continue
 				if ( rectx1 >= pX || rectx2 <= pX || recty1 >= pY

+ 54 - 8
examples/software_sandbox.html

@@ -16,21 +16,18 @@
 	<body>
 
 		<script src="../build/three.min.js"></script>
-
+		<script src="js/geometries/hilbert3D.js"></script>
 		<script src="js/controls/TrackballControls.js"></script>
-
 		<script src="js/renderers/Projector.js"></script>
 		<script src="js/renderers/SoftwareRenderer.js"></script>
-
 		<script src="js/libs/stats.min.js"></script>
-
 		<script>
 
 			var container, stats;
 
 			var camera, controls, scene, renderer;
 
-			var torus, cube;
+			var torus, cube, texCube;
 
 			var start = Date.now();
 
@@ -50,13 +47,14 @@
 				info.innerHTML = '<a href="http://threejs.org" target="_blank">three.js<a/> - software renderer<br/>drag to change the point of view';
 				container.appendChild( info );
 
-				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 2000 );
 				camera.position.z = 600;
 
 				controls = new THREE.TrackballControls( camera );
 
 				scene = new THREE.Scene();
 
+				// Torus
 				var geometry = new THREE.TorusKnotGeometry( 150 );
 
 				for ( var i = 0, j = geometry.faces.length; i < j; i ++ ) {
@@ -68,8 +66,7 @@
 				torus = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0x0000ff, vertexColors: THREE.FaceColors } ) );
 				scene.add( torus );
 
-				// Plane
-
+				// Cube
 				var geometry = new THREE.BoxGeometry( 200, 200, 200 );
 
 				for ( var i = 0, j = geometry.faces.length; i < j; i ++ ) {
@@ -79,8 +76,55 @@
 				}
 
 				cube = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0x00ff00, vertexColors: THREE.FaceColors } ) );
+				scene.position.set( 100, 0, 0 );
 				scene.add( cube );
 
+				// Cube with texture
+				var loader = new THREE.TextureLoader();
+				var map = loader.load( 'textures/brick_diffuse.jpg' );
+				texCube = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { map: map, overdraw: 0.5 } ) );
+				texCube.position.set( -300, 0, 0 );
+				scene.add( texCube );
+
+				// Sprite
+				var sprite = new THREE.Sprite( new THREE.SpriteMaterial( { color: 0xff0040 } ) );
+				sprite.scale.set( 100, 100, 1 );
+				sprite.position.set( -100, 200, 0 );
+				scene.add( sprite );
+
+				// Sprite with texture
+				var texLoader = new THREE.TextureLoader();
+				map = texLoader.load( 'textures/sprite1.png' );
+				var texSprite = new THREE.Sprite( new THREE.SpriteMaterial( { map: map,transparent: true } ) );
+				texSprite.scale.set( 100, 100, 1 );
+				texSprite.position.set( 100, 200, 0 );
+				scene.add( texSprite );
+
+				// Line
+				var points = hilbert3D( new THREE.Vector3( 0,0,0 ), 200.0, 1, 0, 1, 2, 3, 4, 5, 6, 7 );
+				var spline = new THREE.Spline( points );
+				var n_sub = 6, colors = [], line;
+				var lineGeometry = new THREE.Geometry()
+
+				for ( i = 0; i < points.length * n_sub; i ++ ) {
+
+					index = i / ( points.length * n_sub );
+					position = spline.getPoint( index );
+
+					lineGeometry.vertices[ i ] = new THREE.Vector3( position.x, position.y, position.z );
+
+					colors[ i ] = new THREE.Color( 0x88aaff );
+
+				}
+
+				lineGeometry.colors = colors;
+
+				material = new THREE.LineBasicMaterial( { opacity: 1, linewidth: 3, vertexColors: THREE.VertexColors } );
+				line = new THREE.Line( lineGeometry, material );
+				line.scale.set( 0.5, 0.5, 0.5 );
+				line.position.set( 0, -200, 0);
+				scene.add( line );
+
 				renderer = new THREE.SoftwareRenderer();
 				renderer.setClearColor( 0xf0f0f0 );
 				renderer.setSize( window.innerWidth, window.innerHeight );
@@ -129,6 +173,8 @@
 				cube.rotation.x = timer * 0.0002;
 				cube.rotation.z = timer * 0.0003;
 
+				texCube.rotation.x = timer * 0.0002;
+				texCube.rotation.z = timer * 0.0003;
 
 				controls.update();