?? camera.java
字號:
if ( u > 0 ) { return new InfinitePlane(right, eyePosition.add(right.multiply(u))); } else { return new InfinitePlane(left, eyePosition.add(right.multiply(u))); } } Vector3D du = rightWithScale.multiply(u); Vector3D f = new Vector3D(front); Vector3D dir = du.add(_dir); f.normalize(); double alpha; dir.normalize(); alpha = Math.acos(f.dotProduct(dir)); if ( u > 0 ) alpha *= -1; // 2. Calculate the plane normal Matrix4x4 R = new Matrix4x4(); Vector3D n; R.axisRotation(alpha, up); n = R.multiply(du); n.normalize(); // 3. Build the plane and return InfinitePlane plane; plane = new InfinitePlane(n, eyePosition); return plane; } /** 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 calculateVPlaneAtPixel(int x, int y) { // 1. Calculate the angle between the front vector and the plane updateVectors(); double v = ((viewportYSize - (double)y - 1) - viewportYSize/2.0) / viewportYSize; return calculateVPlane(v); } /** PRE: updateVectors() must be called before this method if camera model is new or recently changed. */ public InfinitePlane calculateVPlane(double v) { if ( projectionMode == PROJECTION_MODE_ORTHOGONAL ) { v /= orthogonalZoom; v *= 2; Vector3D up2 = new Vector3D(up); up.normalize(); if ( v > 0 ) { return new InfinitePlane(up, eyePosition.add(up.multiply(v))); } else { Vector3D down = up.multiply(-1); return new InfinitePlane(down, eyePosition.add(up.multiply(v))); } } Vector3D dv = upWithScale.multiply(v); Vector3D f = new Vector3D(front); Vector3D dir = dv.add(_dir); f.normalize(); double alpha; dir.normalize(); alpha = Math.acos(f.dotProduct(dir)); if ( v > 0 ) alpha *= -1; // 2. Calculate the plane normal Matrix4x4 R = new Matrix4x4(); Vector3D n; R.axisRotation(alpha, left); n = R.multiply(dv); n.normalize(); // 3. Build the plane and return InfinitePlane plane; plane = new InfinitePlane(n, eyePosition); return plane; } /** PRE: updateVectors() must be called before this method if camera model is new or recently changed. WARNING: This is currently considering only the perspective case! TODO: The paralel projection case! */ public InfinitePlane calculateNearPlane() { InfinitePlane plane; Vector3D f = new Vector3D(front); f.normalize(); Vector3D back = f.multiply(-1); f = f.multiply(nearPlaneDistance); Vector3D c = eyePosition.add(f); plane = new InfinitePlane(back, c); return plane; } /** PRE: updateVectors() must be called before this method if camera model is new or recently changed. WARNING: This is currently considering only the perspective case! TODO: The paralel projection case! */ public InfinitePlane calculateFarPlane() { InfinitePlane plane; Vector3D f = new Vector3D(front); f.normalize(); f = f.multiply(farPlaneDistance); Vector3D c = eyePosition.add(f); plane = new InfinitePlane(front, c); return plane; } /** Given a point in "clipping coordinates space", this method calculates a six bit opcode, as explained in [FOLE1992].6.5.3, suitable for use in the Cohen-Suterland line clipping algorithm, taking the input point in homogeneous space, as noted in [FOLE1992].6.5.4. Note that the "clipping coodinate space" is the result of transforming world coordinate space with the composed transform-project matrix for current camera, as returned by the `calculateProjectionMatrix` method. Note that in VSDK, the clipping space correspond to the frustum for the minmax cube from <-1, -1, -1> to <1, 1, 1>. WARNING: This algoritm FAILS when the point to be tested is in the plane passing through eye position of the camera and paralel to near plane! In this case, W gets 0 value, and points are not correctly classified. @todo: check this method... currently disabled due to non working cases! */ private int calculateOutcodeBits(Vector4D p) { int bits = 0x00; if ( p.w > 0 ) { if ( p.x > p.w ) bits |= OPCODE_RIGHT; if ( p.x < -p.w ) bits |= OPCODE_LEFT; if ( p.y > p.w ) bits |= OPCODE_UP; if ( p.y < -p.w ) bits |= OPCODE_DOWN; if ( p.z > p.w ) bits |= OPCODE_FAR; if ( p.z < -p.w ) bits |= OPCODE_NEAR; } else { if ( p.x > -p.w ) bits |= OPCODE_RIGHT; if ( p.x < p.w ) bits |= OPCODE_LEFT; if ( p.y > -p.w ) bits |= OPCODE_UP; if ( p.y < p.w ) bits |= OPCODE_DOWN; if ( p.z > -p.w ) bits |= OPCODE_FAR; if ( p.z < p.w ) bits |= OPCODE_NEAR; } return bits; } private double fpd() { return (farPlaneDistance - nearPlaneDistance) / nearPlaneDistance; } /** Given a point in "clipping coordinates space", this method calculates a six bit opcode, as explained in [FOLE1992].6.5.3, suitable for use in the Cohen-Suterland line clipping algorithm. Note that in VSDK, the clipping space correspond to the frustum for the minmax cube from <-1, -1, -1> to <1, 1, 1>. WARNING: Currently is only implementing the perspective case! */ private int calculateOutcodeBits(Vector3D p) { int bits = 0x00; if ( p.z + p.x - 1 > 0 ) bits |= OPCODE_RIGHT; if ( p.z - p.x - 1 > 0 ) bits |= OPCODE_LEFT; if ( p.z + p.y - 1 > 0 ) bits |= OPCODE_UP; if ( p.z - p.y - 1 > 0 ) bits |= OPCODE_DOWN; // Warning: near plane clipping if ( p.z > 0 ) bits |= OPCODE_NEAR; if ( p.z < -fpd() ) bits |= OPCODE_FAR; return bits; } /** Given a point in world space, this method calculates a six bit opcode, as explained in [FOLE1992].6.5.3, suitable for use in the Cohen-Suterland line clipping algorithm. The camera view volume should be represented by its six bounding planes. */ private int calculateOutcodeBits(Vector3D p, InfinitePlane right, InfinitePlane left, InfinitePlane up, InfinitePlane down, InfinitePlane far, InfinitePlane near) { int bits = 0x00; if ( right.doContainmentTestHalfSpace(p, VSDK.EPSILON) == Geometry.OUTSIDE ) { bits |= OPCODE_RIGHT; } if ( left.doContainmentTestHalfSpace(p, VSDK.EPSILON) == Geometry.OUTSIDE ) { bits |= OPCODE_LEFT; } if ( up.doContainmentTestHalfSpace(p, VSDK.EPSILON) == Geometry.OUTSIDE) { bits |= OPCODE_UP; } if ( down.doContainmentTestHalfSpace(p, VSDK.EPSILON) == Geometry.OUTSIDE ) { bits |= OPCODE_DOWN; } if ( far.doContainmentTestHalfSpace(p, VSDK.EPSILON) == Geometry.OUTSIDE ) { bits |= OPCODE_FAR; } if ( near.doContainmentTestHalfSpace(p, VSDK.EPSILON) == Geometry.OUTSIDE ) { bits |= OPCODE_NEAR; } return bits; } /** This method implements the Cohen-Sutherland line clipping algorithm with respect to the view volume defined by current camera. Recieves the two line endpoints and return true if any part of this line lies inside the view volume. In the case the line crosses the view volume, the new resulting endpoints are calculated and returned. This algorithm structure follows the one proposed in [FOLE1992].3.12.3, generalizing it to the 3D case, as noted in [FOLE1992].6.5.3. */ public boolean clipLineCohenSutherlandPlanes( Vector3D point0, Vector3D point1, Vector3D clippedPoint0, Vector3D clippedPoint1) { //- Local variables definition ------------------------------------ int outcode0; // 6bit containment code for point0 int outcode1; // 6bit containment code for point1 int outcodeout; // Selected endpoint code for iteration Vector3D clippingMidPoint; // Selected endpoint clipped for iteration Ray testRay; // Ray use for general line/plane clipping Vector3D dirFromP0ToP1; // Temporary for testRay construction InfinitePlane rightPlane; // 6 planes defining current camera InfinitePlane leftPlane; // view volume. Note that intersection InfinitePlane upPlane; // tests are done against these planes InfinitePlane downPlane; // using general case non-optimal InfinitePlane nearPlane; // intersections! This sould be InfinitePlane farPlane; // optimized InfinitePlane clippingPlane; // Selected plane for each iteration //- Algorithm initial state --------------------------------------- clippedPoint0.x = point0.x; clippedPoint0.y = point0.y; clippedPoint0.z = point0.z; clippedPoint1.x = point1.x; clippedPoint1.y = point1.y; clippedPoint1.z = point1.z; updateVectors(); clippingMidPoint = new Vector3D(); rightPlane = calculateUPlane(0.5); leftPlane = calculateUPlane(-0.5); upPlane = calculateVPlane(0.5); downPlane = calculateVPlane(-0.5); nearPlane = calculateNearPlane(); farPlane = calculateFarPlane(); clippingPlane = null; outcode0 = calculateOutcodeBits(point0, rightPlane, leftPlane, upPlane, downPlane, nearPlane, farPlane); outcode1 = calculateOutcodeBits(point1, rightPlane, leftPlane, upPlane, downPlane, nearPlane, farPlane); dirFromP0ToP1 = point1.substract(point0); dirFromP0ToP1.normalize(); //- Main Cohen-Sutherland iteration cycle (incremental clipping) -- boolean linePasses = false; // Algorithm return value boolean done = false; // Iteration exit condition do { //- Trivial cases: trivial accept and trivial reject ---------- if ( outcode0 == 0x0 && outcode1 == 0x0 ) { linePasses = true; done = true; } else if ( (outcode0 & outcode1) != 0x0 ) { linePasses = false; done = true; } //- Iterative cases: clipping with each of the 6 planes ------- else { if ( dirFromP0ToP1.length() < VSDK.EPSILON ) { // continue; return false; } //-------------------------------------------------- if ( outcode0 != 0 ) { outcodeout = outcode0; } else { outcodeout = outcode1; } testRay = new Ray(point0, dirFromP0ToP1); //-------------------------------------------------- clippingPlane = null; if ( (OPCODE_UP & outcodeout) != 0x0 ) { clippingPlane = upPlane; } else if ( (OPCODE_DOWN & outcodeout) != 0x0 ) { clippingPlane = downPlane; } else if ( (OPCODE_LEFT & outcodeout) != 0x0 ) { clippingPlane = leftPlane; } else if ( (OPCODE_RIGHT & outcodeout) != 0x0 ) { clippingPlane = rightPlane; } else if ( (OPCODE_NEAR & outcodeout) != 0x0 ) { // Warning: Why test with the contrary plane? clippingPlane = farPlane; } else if ( (OPCODE_FAR & outcodeout) != 0x0 ) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -