Explorar el Código

Handle perspective projection edge case

WestLangley hace 8 años
padre
commit
af28b2fb70
Se han modificado 1 ficheros con 37 adiciones y 3 borrados
  1. 37 3
      examples/js/lines/LineMaterial.js

+ 37 - 3
examples/js/lines/LineMaterial.js

@@ -42,6 +42,21 @@ THREE.ShaderLib[ 'line' ] = {
 
 		varying vec2 vUv;
 
+		void trimSegment( const in vec4 start, inout vec4 end ) {
+
+			// trim end segment so it terminates between the camera plane and the near plane
+
+			// conservative estimate of the near plane
+			float a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column
+			float b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column
+			float nearEstimate = - 0.5 * b / a;
+
+			float alpha = ( nearEstimate - start.z ) / ( end.z - start.z );
+
+			end.xyz = mix( start.xyz, end.xyz, alpha );
+
+		}
+
 		void main() {
 
 			#ifdef USE_COLOR
@@ -56,6 +71,27 @@ THREE.ShaderLib[ 'line' ] = {
 			vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );
 			vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );
 
+			// special case for perspective projection, and segments that terminate either in, or behind, the camera plane
+			// clearly the gpu firmware has a way of addressing this issue when projecting into ndc space
+			// but we need to perform ndc-space calculations in the shader, so we must address this issue directly
+			// perhaps there is a more elegant solution -- WestLangley
+
+			bool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column
+
+			if ( perspective ) {
+
+				if ( start.z < 0.0 && end.z >= 0.0 ) {
+
+					trimSegment( start, end );
+
+				} else if ( end.z < 0.0 && start.z >= 0.0 ) {
+
+					trimSegment( end, start );
+
+				}
+
+			}
+
 			// clip space
 			vec4 clipStart = projectionMatrix * start;
 			vec4 clipEnd = projectionMatrix * end;
@@ -95,7 +131,7 @@ THREE.ShaderLib[ 'line' ] = {
 			// adjust for linewidth
 			offset *= linewidth;
 
-			// adjust for clip-space to screen-space conversion // maybe it should be based on viewport ...
+			// adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...
 			offset /= resolution.y;
 
 			// select end
@@ -166,8 +202,6 @@ THREE.LineMaterial = function ( parameters ) {
 
 		type: 'LineMaterial',
 
-		side: THREE.DoubleSide, // for now. there is an issue with segments that terminate behind the camera
-
 		uniforms: THREE.UniformsUtils.clone( THREE.ShaderLib[ 'line' ].uniforms ),
 
 		vertexShader: THREE.ShaderLib[ 'line' ].vertexShader,