vector<GfVec3d> GfFrustum::ComputeCornersAtDistance(double d) const { const GfVec2d &winMin = _window.GetMin(); const GfVec2d &winMax = _window.GetMax(); vector<GfVec3d> corners; corners.reserve(4); if (_projectionType == Perspective) { // Similar to ComputeCorners corners.push_back(GfVec3d(d * winMin[0], d * winMin[1], -d)); corners.push_back(GfVec3d(d * winMax[0], d * winMin[1], -d)); corners.push_back(GfVec3d(d * winMin[0], d * winMax[1], -d)); corners.push_back(GfVec3d(d * winMax[0], d * winMax[1], -d)); } else { corners.push_back(GfVec3d(winMin[0], winMin[1], -d)); corners.push_back(GfVec3d(winMax[0], winMin[1], -d)); corners.push_back(GfVec3d(winMin[0], winMax[1], -d)); corners.push_back(GfVec3d(winMax[0], winMax[1], -d)); } // Each corner is then transformed into world space by the inverse // of the view matrix. const GfMatrix4d m = ComputeViewInverse(); for (int i = 0; i < 4; i++) corners[i] = m.Transform(corners[i]); return corners; }
vector<GfVec3d> GfFrustum::ComputeCorners() const { const GfVec2d &winMin = _window.GetMin(); const GfVec2d &winMax = _window.GetMax(); double near = _nearFar.GetMin(); double far = _nearFar.GetMax(); vector<GfVec3d> corners; corners.reserve(8); if (_projectionType == Perspective) { // Compute the eye-space corners of the near-plane and // far-plane frustum rectangles using similar triangles. The // reference plane in which the window rectangle is defined is // a distance of 1 from the eyepoint. By similar triangles, // just multiply the window points by near and far to get the // near and far rectangles. // XXX Note: If we ever allow reference plane depth to be other // than 1.0, we'll need to revisit this. corners.push_back(GfVec3d(near * winMin[0], near * winMin[1], -near)); corners.push_back(GfVec3d(near * winMax[0], near * winMin[1], -near)); corners.push_back(GfVec3d(near * winMin[0], near * winMax[1], -near)); corners.push_back(GfVec3d(near * winMax[0], near * winMax[1], -near)); corners.push_back(GfVec3d(far * winMin[0], far * winMin[1], -far)); corners.push_back(GfVec3d(far * winMax[0], far * winMin[1], -far)); corners.push_back(GfVec3d(far * winMin[0], far * winMax[1], -far)); corners.push_back(GfVec3d(far * winMax[0], far * winMax[1], -far)); } else { // Just use the reference plane rectangle as is, translated to // the near and far planes. corners.push_back(GfVec3d(winMin[0], winMin[1], -near)); corners.push_back(GfVec3d(winMax[0], winMin[1], -near)); corners.push_back(GfVec3d(winMin[0], winMax[1], -near)); corners.push_back(GfVec3d(winMax[0], winMax[1], -near)); corners.push_back(GfVec3d(winMin[0], winMin[1], -far)); corners.push_back(GfVec3d(winMax[0], winMin[1], -far)); corners.push_back(GfVec3d(winMin[0], winMax[1], -far)); corners.push_back(GfVec3d(winMax[0], winMax[1], -far)); } // Each corner is then transformed into world space by the inverse // of the view matrix. GfMatrix4d m = ComputeViewInverse(); for (int i = 0; i < 8; i++) corners[i] = m.Transform(corners[i]); return corners; }
void GfFrustum::_CalculateFrustumPlanes() const { if (!_planes.empty()) return; _planes.reserve(6); // These are values we need to construct the planes. const GfVec2d &winMin = _window.GetMin(); const GfVec2d &winMax = _window.GetMax(); double near = _nearFar.GetMin(); double far = _nearFar.GetMax(); GfMatrix4d m = ComputeViewInverse(); // For a perspective frustum, we use the viewpoint and four // corners of the near-plane frustum rectangle to define the 4 // planes forming the left, right, top, and bottom sides of the // frustum. if (_projectionType == GfFrustum::Perspective) { // // Get the eye-space viewpoint (the origin) and the four corners // of the near-plane frustum rectangle using similar triangles. // // This picture may help: // // top of near plane // frustum rectangle // // + -- // / | | // / | | // / | | h // / | | // / | | // vp +-----------+ -- // center of near plane frustum rectangle // |___________| // near // // The height (h) of this triangle is found by the following // equation, based on the definition of the _window member // variable, which is the size of the image rectangle in the // reference plane (a distance of 1 from the viewpoint): // // h _window.GetMax()[1] // ------ = -------------------- // near 1 // // Solving for h gets the height of the triangle. Doing the // similar math for the other 3 sizes of the near-plane // rectangle is left as an exercise for the reader. // // XXX Note: If we ever allow reference plane depth to be other // than 1.0, we'll need to revisit this. GfVec3d vp(0.0, 0.0, 0.0); GfVec3d lb(near * winMin[0], near * winMin[1], -near); GfVec3d rb(near * winMax[0], near * winMin[1], -near); GfVec3d lt(near * winMin[0], near * winMax[1], -near); GfVec3d rt(near * winMax[0], near * winMax[1], -near); // Transform all 5 points into world space by the inverse of the // view matrix (which converts from world space to eye space). vp = m.Transform(vp); lb = m.Transform(lb); rb = m.Transform(rb); lt = m.Transform(lt); rt = m.Transform(rt); // Construct the 6 planes. The three points defining each plane // should obey the right-hand-rule; they should be in counter-clockwise // order on the inside of the frustum. This makes the intersection of // the half-spaces defined by the planes the contents of the frustum. _planes.push_back( GfPlane(vp, lb, lt) ); // Left _planes.push_back( GfPlane(vp, rt, rb) ); // Right _planes.push_back( GfPlane(vp, rb, lb) ); // Bottom _planes.push_back( GfPlane(vp, lt, rt) ); // Top _planes.push_back( GfPlane(rb, lb, lt) ); // Near } // For an orthographic projection, we need only the four corners // of the near-plane frustum rectangle and the view direction to // define the 4 planes forming the left, right, top, and bottom // sides of the frustum. else { // // The math here is much easier than in the perspective case, // because we have parallel lines instead of triangles. Just // use the size of the image rectangle in the reference plane, // which is the same in the near plane. // GfVec3d lb(winMin[0], winMin[1], -near); GfVec3d rb(winMax[0], winMin[1], -near); GfVec3d lt(winMin[0], winMax[1], -near); GfVec3d rt(winMax[0], winMax[1], -near); // Transform the 4 points into world space by the inverse of // the view matrix (which converts from world space to eye // space). lb = m.Transform(lb); rb = m.Transform(rb); lt = m.Transform(lt); rt = m.Transform(rt); // Transform the canonical view direction (-z axis) into world // space. GfVec3d dir = m.TransformDir(-GfVec3d::ZAxis()); // Construct the 5 planes from these 4 points and the // eye-space view direction. _planes.push_back( GfPlane(lt + dir, lt, lb) ); // Left _planes.push_back( GfPlane(rb + dir, rb, rt) ); // Right _planes.push_back( GfPlane(lb + dir, lb, rb) ); // Bottom _planes.push_back( GfPlane(rt + dir, rt, lt) ); // Top _planes.push_back( GfPlane(rb, lb, lt) ); // Near } // The far plane is the opposite to the near plane. To compute the // distance from the origin for the far plane, we take the distance // for the near plane, add the difference between the far and the near // and then negate that. We do the negation since the far plane // faces the opposite direction. A small drawing would help: // // far - near // /---------------------------\ * // // | | | // | | | // | | | // <----|----> | | // fnormal|nnormal | | // | | | // near plane far plane // // \---------/ * // ndistance // // \---------------------------------------/ * // fdistance // // So, fdistance = - (ndistance + (far - near)) _planes.push_back( GfPlane(-_planes[4].GetNormal(), -(_planes[4].GetDistanceFromOrigin() + (far - near))) ); }