Browse Source

* Added near and far plane clipping for THREE.Line rendering in CanvasRenderer.
* Changed THREE.Vertex.positionScreen from a Vector3 to a Vector4 to support clipping.

Julian Walker 14 years ago
parent
commit
49f878c5a5
3 changed files with 96 additions and 24 deletions
  1. 9 1
      src/core/Vector4.js
  2. 1 1
      src/core/Vertex.js
  3. 86 22
      src/renderers/Projector.js

+ 9 - 1
src/core/Vector4.js

@@ -30,7 +30,7 @@ THREE.Vector4.prototype = {
 		this.x = v.x;
 		this.y = v.y;
 		this.z = v.z;
-		this.w = v.w;
+		this.w = v.w || 1.0;
 
 		return this;
 
@@ -101,6 +101,14 @@ THREE.Vector4.prototype = {
 		return this;
 
 	},
+	
+	lerpSelf: function ( v, alpha ) {
+		
+		this.x = this.x + (v.x - this.x) * alpha;
+		this.y = this.y + (v.y - this.y) * alpha;
+		this.z = this.z + (v.z - this.z) * alpha;
+		this.w = this.w + (v.w - this.w) * alpha;
+	}
 
 	clone: function () {
 

+ 1 - 1
src/core/Vertex.js

@@ -6,7 +6,7 @@ THREE.Vertex = function ( position, normal ) {
 
 	this.position = position || new THREE.Vector3();
 	this.positionWorld = new THREE.Vector3();
-	this.positionScreen = new THREE.Vector3();
+	this.positionScreen = new THREE.Vector4();
 
 	this.normal = normal || new THREE.Vector3();
 	this.normalWorld = new THREE.Vector3();

+ 86 - 22
src/renderers/Projector.js

@@ -14,15 +14,74 @@ THREE.Projector = function() {
 	_vector4 = new THREE.Vector4(),
 	_projScreenMatrix = new THREE.Matrix4(),
 	_projScreenObjectMatrix = new THREE.Matrix4();
+	
+	function clipLineSegmentAgainstNearAndFarPlanes ( s0, s1 ) {
+		
+		var visible,
+			alpha0 = 0, alpha1 = 1,
+			
+			// Calculate the boundary coordinate of each vertex for the near and far clip planes,
+			// Z = -1 and Z = +1, respectively.			
+			bc0near =  s0.z + s0.w,
+			bc1near =  s1.z + s1.w,
+			bc0far =  -s0.z + s0.w,
+			bc1far =  -s1.z + s1.w;
+
+		if (bc0near >= 0 && bc1near >= 0 && bc0far >= 0 && bc1far >= 0) {
+			// Both vertices lie entirely within all clip planes.
+			visible = true;
+		} else if ((bc0near < 0 && bc1near < 0) || (bc0far < 0 && bc1far < 0)) {
+			// Both vertices lie entirely outside one of the clip planes.
+			visible = false;
+		} else {
+			
+			// The line segment spans at least one clip plane.
+			
+			if (bc0near < 0) {
+				// vertex0 lies outside the near plane, vertex1 inside
+				alpha0 = Math.max(alpha0, bc0near / (bc0near - bc1near));
+			} else if (bc1near < 0) {
+				// vertex1 lies outside the near plane, vertex0 inside
+				alpha1 = Math.min(alpha1, bc0near / (bc0near - bc1near));
+			}
+			
+			if (bc0far < 0) {
+				// vertex0 lies outside the far plane, vertex1 inside
+				alpha0 = Math.max(alpha0, bc0far / (bc0far - bc1far));
+			} else if (bc1far < 0) {
+				// vertex1 lies outside the far plane, vertex1 inside
+				alpha1 = Math.min(alpha1, bc0far / (bc0far - bc1far));
+			}
+			
+			if (alpha1 < alpha0) {
+				// The line segment spans two boundaries, but is outside both of them.
+				// (This can't happen when we're only clipping against just near/far but good
+				//  to leave the check here for future usage if other clip planes are added.)
+				visible = false;
+			} else {
+			
+				// Update the s0 and s1 vertices to match the clipped line segment.
+				s0.lerpSelf(s1, alpha0);
+				s1.lerpSelf(s0, 1 - alpha1);
+
+				visible = true;
+			}
+		}
+		
+		return visible;
+	}
 
 	this.projectScene = function ( scene, camera ) {
 
 		var o, ol, v, vl, f, fl, objects, object, objectMatrix,
-		vertices, vertex, vertexPositionScreen, vertex2,
+		vertices, vertex, vertex0, vertex1, vertexPositionScreen,
 		faces, face, v1, v2, v3, v4;
 
 		_renderList = [];
-		_face3Count = 0, _face4Count = 0, _lineCount = 0, _particleCount = 0;
+		_face3Count = 0;
+		_face4Count = 0;
+		_lineCount = 0;
+		_particleCount = 0;
 
 		if( camera.autoUpdateMatrix ) {
 
@@ -60,6 +119,11 @@ THREE.Projector = function() {
 					vertexPositionScreen = vertex.positionScreen;
 					vertexPositionScreen.copy( vertex.position );
 					_projScreenObjectMatrix.transform( vertexPositionScreen );
+					
+					// Perform the perspective divide. TODO: This should be be performend 
+					// post clipping (imagine if the vertex lies at the same location as 
+				    // the camera, causing a divide by w = 0).
+					vertexPositionScreen.multiplyScalar( 1.0 / vertexPositionScreen.w );
 
 					vertex.__visible = vertexPositionScreen.z > 0 && vertexPositionScreen.z < 1;
 
@@ -170,32 +234,33 @@ THREE.Projector = function() {
 
 					vertex = vertices[ v ];
 
-					vertexPositionScreen = vertex.positionScreen;
-					vertexPositionScreen.copy( vertex.position );
-					_projScreenObjectMatrix.transform( vertexPositionScreen );
-
-					vertex.__visible = vertexPositionScreen.z > 0 && vertexPositionScreen.z < 1;
-
-					if ( v > 0 ) {
-
-						vertex2 = object.geometry.vertices[ v - 1 ];
+					vertex.positionScreen.copy( vertex.position );
+					_projScreenObjectMatrix.transform( vertex.positionScreen );
+				}
 
-						if ( vertex.__visible && vertex2.__visible ) {
+				for ( v = 1, vl = vertices.length; v < vl; v++ ) {
 
-							_line = _linePool[ _lineCount ] = _linePool[ _lineCount ] || new THREE.RenderableLine();
-							_line.v1.copy( vertex.positionScreen );
-							_line.v2.copy( vertex2.positionScreen );
+					vertex0 = vertices[ v ];
+					vertex1 = vertices[ v - 1 ];
+					
+					if (clipLineSegmentAgainstNearAndFarPlanes(vertex0.positionScreen, vertex1.positionScreen)) {
+						
+						// Perform the perspective divide
+						vertex0.positionScreen.multiplyScalar( 1.0 / vertex0.positionScreen.w );
+						vertex1.positionScreen.multiplyScalar( 1.0 / vertex1.positionScreen.w );
 
-							// TODO: Use centriums here too.
-							_line.z = Math.max( vertex.positionScreen.z, vertex2.positionScreen.z );
+						_line = _linePool[ _lineCount ] = _linePool[ _lineCount ] || new THREE.RenderableLine();
+						_line.v1.copy( vertex0.positionScreen );
+						_line.v2.copy( vertex1.positionScreen );
 
-							_line.material = object.material;
+						// TODO: Use centriums here too.
+						_line.z = Math.max( vertex0.positionScreen.z, vertex1.positionScreen.z );
 
-							_renderList.push( _line );
+						_line.material = object.material;
 
-							_lineCount ++;
+						_renderList.push( _line );
 
-						}
+						_lineCount ++;
 					}
 				}
 
@@ -248,5 +313,4 @@ THREE.Projector = function() {
 		return vector;
 
 	};
-
 };