فهرست منبع

VolumeShader: Support perspective cameras. (#33493)

Michael Herzog 1 ماه پیش
والد
کامیت
ab8364f52e
2فایلهای تغییر یافته به همراه30 افزوده شده و 45 حذف شده
  1. 29 44
      examples/jsm/shaders/VolumeShader.js
  2. 1 1
      examples/webgl_texture3d.html

+ 29 - 44
examples/jsm/shaders/VolumeShader.js

@@ -31,34 +31,23 @@ const VolumeRenderShader1 = {
 
 	vertexShader: /* glsl */`
 
-		varying vec4 v_nearpos;
-		varying vec4 v_farpos;
 		varying vec3 v_position;
+		varying vec3 v_cameraInObj;
+		varying vec3 v_viewDirInObj;
 
 		void main() {
-				// Prepare transforms to map to "camera view". See also:
-				// https://threejs.org/docs/#api/renderers/webgl/WebGLProgram
-				mat4 viewtransformf = modelViewMatrix;
-				mat4 viewtransformi = inverse(modelViewMatrix);
-
-				// Project local vertex coordinate to camera position. Then do a step
-				// backward (in cam coords) to the near clipping plane, and project back. Do
-				// the same for the far clipping plane. This gives us all the information we
-				// need to calculate the ray and truncate it to the viewing cone.
 				vec4 position4 = vec4(position, 1.0);
-				vec4 pos_in_cam = viewtransformf * position4;
 
-				// Intersection of ray and near clipping plane (z = -1 in clip coords)
-				pos_in_cam.z = -pos_in_cam.w;
-				v_nearpos = viewtransformi * pos_in_cam;
+				v_position = position;
 
-				// Intersection of ray and far clipping plane (z = +1 in clip coords)
-				pos_in_cam.z = pos_in_cam.w;
-				v_farpos = viewtransformi * pos_in_cam;
+				// Express the camera position and view direction in the object's local
+				// space so the fragment shader can build the per-fragment view ray.
+				// For perspective cameras, rays converge at v_cameraInObj.
+				// For orthographic cameras, rays travel along v_viewDirInObj.
+				v_cameraInObj = (inverse(modelMatrix) * vec4(cameraPosition, 1.0)).xyz;
+				v_viewDirInObj = (inverse(modelViewMatrix) * vec4(0.0, 0.0, -1.0, 0.0)).xyz;
 
-				// Set varyings and output pos
-				v_position = position;
-				gl_Position = projectionMatrix * viewMatrix * modelMatrix * position4;
+				gl_Position = projectionMatrix * modelViewMatrix * position4;
 		}`,
 
 	fragmentShader: /* glsl */`
@@ -75,8 +64,8 @@ const VolumeRenderShader1 = {
 				uniform sampler2D u_cmdata;
 
 				varying vec3 v_position;
-				varying vec4 v_nearpos;
-				varying vec4 v_farpos;
+				varying vec3 v_cameraInObj;
+				varying vec3 v_viewDirInObj;
 
 				// The maximum distance through our rendering volume is sqrt(3).
 				const int MAX_STEPS = 887;	// 887 for 512^3, 1774 for 1024^3
@@ -96,33 +85,29 @@ const VolumeRenderShader1 = {
 
 
 				void main() {
-						// Normalize clipping plane info
-						vec3 farpos = v_farpos.xyz / v_farpos.w;
-						vec3 nearpos = v_nearpos.xyz / v_nearpos.w;
-
-						// Calculate unit vector pointing in the view direction through this fragment.
-						vec3 view_ray = normalize(nearpos.xyz - farpos.xyz);
-
-						// Compute the (negative) distance to the front surface or near clipping plane.
-						// v_position is the back face of the cuboid, so the initial distance calculated in the dot
-						// product below is the distance from near clip plane to the back of the cuboid
-						float distance = dot(nearpos - v_position, view_ray);
-						distance = max(distance, min((-0.5 - v_position.x) / view_ray.x,
-																				(u_size.x - 0.5 - v_position.x) / view_ray.x));
-						distance = max(distance, min((-0.5 - v_position.y) / view_ray.y,
-																				(u_size.y - 0.5 - v_position.y) / view_ray.y));
-						distance = max(distance, min((-0.5 - v_position.z) / view_ray.z,
-																				(u_size.z - 0.5 - v_position.z) / view_ray.z));
-
-						// Now we have the starting position on the front surface
-						vec3 front = v_position + view_ray * distance;
+						// Per-fragment ray direction in object space, pointing from the back
+						// face toward the camera. For perspective cameras the rays converge
+						// at the camera position; for orthographic cameras they are parallel
+						// to the view direction.
+						vec3 view_ray = isOrthographic
+								? normalize(-v_viewDirInObj)
+								: normalize(v_cameraInObj - v_position);
+
+						// Slab-based ray/AABB intersection: v_position lies on the back face
+						// of the cuboid, so stepping along view_ray traverses the volume and
+						// exits through the front face at t = distance.
+						vec3 t1 = (vec3(-0.5) - v_position) / view_ray;
+						vec3 t2 = (u_size - vec3(0.5) - v_position) / view_ray;
+						vec3 tmax = max(t1, t2);
+						float distance = min(min(tmax.x, tmax.y), tmax.z);
 
 						// Decide how many steps to take
-						int nsteps = int(-distance / relative_step_size + 0.5);
+						int nsteps = int(distance / relative_step_size + 0.5);
 						if ( nsteps < 1 )
 								discard;
 
 						// Get starting location and step vector in texture coordinates
+						vec3 front = v_position + view_ray * distance;
 						vec3 step = ((v_position - front) / u_size) / float(nsteps);
 						vec3 start_loc = front / u_size;
 

+ 1 - 1
examples/webgl_texture3d.html

@@ -50,7 +50,7 @@
 			renderer.setSize( window.innerWidth, window.innerHeight );
 			document.body.appendChild( renderer.domElement );
 
-			// Create camera (The volume renderer does not work very well with perspective yet)
+			// Create camera
 			const h = 512; // frustum height
 			const aspect = window.innerWidth / window.innerHeight;
 			camera = new THREE.OrthographicCamera( - h * aspect / 2, h * aspect / 2, h / 2, - h / 2, 1, 1000 );

粤ICP备19079148号