?? camera.java
字號:
*/ normalizingTransformation = new Matrix4x4(); // 1. Translate the "VRP" point to the origin Vector3D VRP; Matrix4x4 T1 = new Matrix4x4(); // Warning: near plane clipping VRP = eyePosition.add(front.multiply(nearPlaneDistance)); //VRP = eyePosition.add(front.multiply(1)); T1.translation(VRP.multiply(-1)); // 2. Rotate the "VRC" coordinate system such as the front axis // become the -z axis Matrix4x4 R1 = new Matrix4x4(); Matrix4x4 R2 = new Matrix4x4(); R1 = getRotation(); R1.invert(); R2.eulerAnglesRotation(Math.toRadians(90), Math.toRadians(-90), 0); // 3. Translate such that the center of projection is at the origin ; // 4. Shear such that the center line of the view volume becomes the // z axis ; // 5. Scale such that the view volume becomes the canonical perspective // view volume Matrix4x4 S1 = new Matrix4x4(); Matrix4x4 S2 = new Matrix4x4(); double dx, dy, dz; // 5.1. Non proportional scaling to adjust the slopes of the piramid // planes to fix 45 degrees in u and v directions dx = rightWithScale.length(); dy = upWithScale.length(); S1.scale(dx, dy, 1); S1.invert(); // 5.2. Proportional scaling to adjust near / far clipping planes // maintaining the piramid form dz = nearPlaneDistance; S2.scale(dz, dz, dz); S2.invert(); // normalizingTransformation = S2.multiply(S1.multiply(R2.multiply(R1.multiply(T1)))); } /** Given a 2D integer coordinate in viewport space, this method calculates a proyector ray that emanates from the eye position and passes over the (u, v) float coordinate in the projection plane. Note that the (u, v) coordinate correspond to the (x, y) coordinate. This method is of vital importance to many fundamental algorithms of visualization (i.e. ray casting, ray tracing, radiosity), object selection and others (simulation, colision detection, visual debugging, etc.). As it is important to improve the efficiency of this method, some precalculated values are stored in the class attributes `_dir`, `upWithScale` and `rightWithScale`, which values are stored in the `updateVectors` method, leading to the following precondition: PRE: - At least a call to the updateVectors method must be done before calling this method, and after changing any camera parameter the updateVectors method must be called again to reflect the changes in this calculation. /todo this method should be named "generateProjectorRay" */ public final Ray generateRay(int x, int y) { double u, v; Ray ray; // 1. Convert integer image coordinates into values in the range [-0.5, 0.5] u = ((double)x - viewportXSize/2.0) / viewportXSize; v = ((viewportYSize - (double)y - 1) - viewportYSize/2.0) / viewportYSize; // 2. Calculate the ray direction Vector3D dv; Vector3D du; if ( projectionMode == PROJECTION_MODE_ORTHOGONAL ) { double fovFactor = viewportXSize/viewportYSize; du = left.multiply(-fovFactor); dv = up; du = du.multiply(2*u/orthogonalZoom); dv = dv.multiply(2*v/orthogonalZoom); ray = new Ray(eyePosition.add(du.add(dv)), front); return ray; } // Default behavior is to assume planar perspective projection du = rightWithScale.multiply(u); dv = upWithScale.multiply(v); Vector3D dir = dv.add(du).add(_dir); // 3. Build up and return a ray with origin in the eye position and with calculated direction ray = new Ray(eyePosition, dir); return ray; } public double getOrthogonalZoom() { return orthogonalZoom; } public void setOrthogonalZoom(double orthogonalZoom) { this.orthogonalZoom = orthogonalZoom; } public void setRotation(Matrix4x4 R) { up.x = R.M[0][2]; up.y = R.M[1][2]; up.z = R.M[2][2]; up.normalize(); front.x = R.M[0][0]; front.y = R.M[1][0]; front.z = R.M[2][0]; front.normalize(); left.x=R.M[0][1]; left.y=R.M[1][1]; left.z=R.M[2][1]; left.normalize(); } public Matrix4x4 getRotation() { //------------------------------------------------------------ Matrix4x4 R = new Matrix4x4(); R.identity(); R.M[0][0] = front.x; R.M[0][1] = left.x; R.M[0][2] = up.x; R.M[1][0] = front.y; R.M[1][1] = left.y; R.M[1][2] = up.y; R.M[2][0] = front.z; R.M[2][1] = left.z; R.M[2][2] = up.z; return R; } /** Note that projectionMatrix = transformationMatrix*viewVolumeMatrix */ public Matrix4x4 calculateViewVolumeMatrix() { //- Calculate the base projection matrix ---------------------------- double leftDistance, rightDistance, upDistance, downDistance, aspect; Matrix4x4 P = new Matrix4x4(); aspect = viewportXSize / viewportYSize; switch ( projectionMode ) { case Camera.PROJECTION_MODE_ORTHOGONAL: P.orthogonalProjection(-aspect/orthogonalZoom, aspect/orthogonalZoom, -1/orthogonalZoom, 1/orthogonalZoom, nearPlaneDistance, farPlaneDistance); break; case Camera.PROJECTION_MODE_PERSPECTIVE: upDistance = nearPlaneDistance * Math.tan(Math.toRadians(fov/2)); downDistance = -upDistance; leftDistance = aspect * downDistance; rightDistance = aspect * upDistance; P.frustumProjection(leftDistance, rightDistance, downDistance, upDistance, nearPlaneDistance, farPlaneDistance); break; } return P; } public Matrix4x4 calculateTransformationMatrix() { return calculateTransformationMatrix(STEREO_MODE_CENTER); } /** Note that projectionMatrix = transformationMatrix*viewVolumeMatrix */ public Matrix4x4 calculateTransformationMatrix(int stereoMode) { //- Take into account the camera position and orientation ---------- Matrix4x4 R; Matrix4x4 R1; Matrix4x4 T1 = new Matrix4x4(); Matrix4x4 R_adic2 = new Matrix4x4(); Matrix4x4 R_adic1 = new Matrix4x4(); Matrix4x4 R2 = new Matrix4x4(); Matrix4x4 Tstereo = new Matrix4x4(); Vector3D pstereo = new Vector3D(); double factor_distancia_entre_ojos = 0.04; R1 = getRotation(); R1.invert(); T1.translation(-eyePosition.x, -eyePosition.y, -eyePosition.z); R_adic2.axisRotation(Math.toRadians(90), 0, 0, 1); R_adic1.axisRotation(Math.toRadians(-90), 1, 0, 0); R = R_adic1.multiply(R_adic2.multiply(R1.multiply(T1))); if ( stereoMode == STEREO_MODE_LEFT_EYE ) { pstereo.x = -R.M[0][0] * factor_distancia_entre_ojos; pstereo.y = -R.M[0][1] * factor_distancia_entre_ojos; pstereo.z = -R.M[0][2] * factor_distancia_entre_ojos; Tstereo.translation(pstereo.x, pstereo.y, pstereo.z); R = R.multiply(Tstereo); } if ( stereoMode == STEREO_MODE_RIGHT_EYE ) { pstereo.x = R.M[0][0] * factor_distancia_entre_ojos; pstereo.y = R.M[0][1] * factor_distancia_entre_ojos; pstereo.z = R.M[0][2] * factor_distancia_entre_ojos; Tstereo.translation(pstereo.x, pstereo.y, pstereo.z); R = R.multiply(Tstereo); } return R; } /** Note that projectionMatrix = transformationMatrix*viewVolumeMatrix */ public Matrix4x4 calculateProjectionMatrix(int stereoMode) { Matrix4x4 P = calculateViewVolumeMatrix(); Matrix4x4 R = calculateTransformationMatrix(stereoMode); return P.multiply(R); } /** Provides an object to text report convertion, optimized for human readability and debugging. Do not use for serialization or persistence purposes. */ public String toString() { //------------------------------------------------------------ String msg; msg = "<Camera>:\n"; msg += " - Name: \"" + getName() + "\"\n"; if ( projectionMode == PROJECTION_MODE_PERSPECTIVE ) { msg = msg + " - Camera in PERSPECTIVE projection mode\n"; } else if ( projectionMode == PROJECTION_MODE_ORTHOGONAL ) { msg = msg + " - Camera in PARALEL projection mode\n"; msg = msg + " - Orthogonal zoom = " + orthogonalZoom + "\n"; } else { msg = msg + " - UNKNOWN Camera projection mode!\n"; } ; msg = msg + " - eyePosition(x, y, z) = " + eyePosition + "\n"; msg = msg + " - focusedPointPosition(x, y, z) = " + eyePosition.add(front.multiply(focalDistance)) + "\n"; //------------------------------------------------------------ Matrix4x4 R, TP; double yaw, pitch, roll; TP = calculateProjectionMatrix(STEREO_MODE_CENTER); R = getRotation(); yaw = R.obtainEulerYawAngle(); pitch = R.obtainEulerPitchAngle(); roll = R.obtainEulerRollAngle(); msg = msg + " - Rotation yaw/pitch/roll: <" + VSDK.formatDouble(yaw) + ", " + VSDK.formatDouble(pitch) + ", " + VSDK.formatDouble(roll) + "> RAD (<" + VSDK.formatDouble(Math.toDegrees(yaw)) + ", " + VSDK.formatDouble(Math.toDegrees(pitch)) + ", " + VSDK.formatDouble(Math.toDegrees(roll)) + "> DEG)\n"; msg = msg + " - Rotation quaternion: " + R.exportToQuaternion() + "\n"; //------------------------------------------------------------ updateVectors(); msg = msg + " - Reference frame:\n"; msg = msg + " . Vector UP = " + up + " (length " + VSDK.formatDouble(up.length()) + ")\n"; msg = msg + " . Vector FRONT = " + front + " (length " + VSDK.formatDouble(front.length()) + ")\n"; msg = msg + " . Vector LEFT = " + left + " (length " + VSDK.formatDouble(front.length()) + ")\n"; msg = msg + " - Reference frame with scales:\n"; msg = msg + " . Vector UP' = " + upWithScale + " (length " + VSDK.formatDouble(upWithScale.length()) + ")\n"; msg = msg + " . Vector FRONT' = " + _dir + " (length " + VSDK.formatDouble(_dir.length()) + ")\n"; msg = msg + " . Vector RIGHT' = " + rightWithScale + " (length " + VSDK.formatDouble(rightWithScale.length()) + ")\n"; msg = msg + " - fov = " + VSDK.formatDouble(fov) + "\n"; msg = msg + " - nearPlaneDistance = " + VSDK.formatDouble(nearPlaneDistance) + "\n"; msg = msg + " - farPlaneDistance = " + VSDK.formatDouble(farPlaneDistance) + "\n"; msg = msg + " - Viewport size in pixels = (" + VSDK.formatDouble(viewportXSize) + ", " + VSDK.formatDouble(viewportYSize) + ")\n"; msg = msg + " - Transformation * projection matrix:" + TP; //------------------------------------------------------------ Matrix4x4 P; double leftDistance, rightDistance, upDistance, downDistance, aspect; P = new Matrix4x4(); aspect = viewportXSize / viewportYSize; if ( projectionMode == PROJECTION_MODE_PERSPECTIVE ) { upDistance = nearPlaneDistance * Math.tan(Math.toRadians(fov/2)); downDistance = -upDistance; leftDistance = aspect * downDistance; rightDistance = aspect * upDistance; P.frustumProjection(leftDistance, rightDistance, downDistance, upDistance, nearPlaneDistance, farPlaneDistance); msg = msg + " - Projection matrix:" + P; } else if ( projectionMode == PROJECTION_MODE_ORTHOGONAL ) { P.orthogonalProjection(-aspect/orthogonalZoom, aspect/orthogonalZoom, -1/orthogonalZoom, 1/orthogonalZoom, nearPlaneDistance, farPlaneDistance); msg = msg + " - Projection matrix:" + P; } //------------------------------------------------------------ return msg; } /** Given `this` camera and the pixel (x, y) in its viewport, this method calculates an infinite plane that pass by the corresponding proyector ray origin and by the proyection plane (u, v) point, where (u, v) is the proyection of pixel (x, y). The plane is perpendicular to the v direction. */ public InfinitePlane calculateUPlaneAtPixel(int x, int y) { // 1. Calculate the angle between the front vector and the plane updateVectors(); double u = ((double)x - viewportXSize/2.0) / viewportXSize; return calculateUPlane(u); } /** Returns an outward pointing "horizontal" plane with respect to current camera (horizontal is left-right direction). Outwards means that the plane normal points outward the visualization volume / frustum. Camera visualization limits for u are inside the interval [-0.5, 0.5]. PRE: updateVectors() must be called before this method if camera model is new or recently changed. */ public InfinitePlane calculateUPlane(double u) { if ( projectionMode == PROJECTION_MODE_ORTHOGONAL ) { u /= orthogonalZoom; u *= 2*(viewportXSize/viewportYSize); Vector3D right = left.multiply(-1); right.normalize();
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -