float3 Frustum::CornerPoint(int cornerIndex) const { assume(0 <= cornerIndex && cornerIndex <= 7); switch(cornerIndex) { default: // For release builds where assume() is disabled, return always the first option if out-of-bounds. case 0: return NearPlanePos(-1, -1); case 1: return FarPlanePos(-1, -1); case 2: return NearPlanePos(-1, 1); case 3: return FarPlanePos(-1, 1); case 4: return NearPlanePos(1, -1); case 5: return FarPlanePos(1, -1); case 6: return NearPlanePos(1, 1); case 7: return FarPlanePos(1, 1); } }
Plane Frustum::BottomPlane() const { if (type == PerspectiveFrustum) { vec bottomSide = front - Tan(verticalFov * 0.5f) * up; vec left = -WorldRight(); vec bottomSideNormal = ((handedness == FrustumRightHanded) ? Cross(left, bottomSide) : Cross(bottomSide, left)).Normalized(); return Plane(pos, bottomSideNormal); } else { return Plane(NearPlanePos(0.f, -1.f), -up); } }
Ray Frustum::UnProject(float x, float y) const { assume(x >= -1.f); assume(x <= 1.f); assume(y >= -1.f); assume(y <= 1.f); if (type == PerspectiveFrustum) { float3 nearPlanePos = NearPlanePos(x, y); return Ray(pos, (nearPlanePos - pos).Normalized()); } else return UnProjectFromNearPlane(x, y); }
Plane Frustum::TopPlane() const { if (type == PerspectiveFrustum) { vec topSide = front + Tan(verticalFov * 0.5f) * up; vec right = WorldRight(); vec topSideNormal = ((handedness == FrustumRightHanded) ? Cross(right, topSide) : Cross(topSide, right)).Normalized(); return Plane(pos, topSideNormal); } else { return Plane(NearPlanePos(0.f, 1.f), up); } }
Plane Frustum::RightPlane() const { if (type == PerspectiveFrustum) { vec right = WorldRight(); right.ScaleToLength(Tan(horizontalFov*0.5f)); vec rightSide = front + right; vec rightSideNormal = ((handedness == FrustumRightHanded) ? Cross(rightSide, up) : Cross(up, rightSide)).Normalized(); return Plane(pos, rightSideNormal); } else { vec right = WorldRight(); return Plane(NearPlanePos(1.f, 0.f), right.Normalized()); } }
Plane Frustum::LeftPlane() const { if (type == PerspectiveFrustum) { vec left = -WorldRight(); left.ScaleToLength(Tan(horizontalFov*0.5f)); vec leftSide = front + left; vec leftSideNormal = ((handedness == FrustumRightHanded) ? Cross(up, leftSide) : Cross(leftSide, up)).Normalized(); return Plane(pos, leftSideNormal); } else { vec left = -WorldRight(); return Plane(NearPlanePos(-1.f, 0.f), left.Normalized()); } }
int Frustum::UniqueEdgeDirections(vec *out) const { if (type == PerspectiveFrustum) { out[0] = NearPlanePos(-1, -1) - NearPlanePos(1, -1); out[1] = NearPlanePos(-1, -1) - NearPlanePos(-1, 1); out[2] = FarPlanePos(-1, -1) - NearPlanePos(-1, -1); out[3] = FarPlanePos( 1, -1) - NearPlanePos( 1, -1); out[4] = FarPlanePos(-1, 1) - NearPlanePos(-1, 1); out[5] = FarPlanePos( 1, 1) - NearPlanePos( 1, 1); return 6; } else { out[0] = front; out[1] = up; out[2] = Cross(front, up); return 3; } }
Ray Frustum::LookAt(float x, float y) const { float3 nearPlanePos = NearPlanePos(x, y); return Ray(pos, (nearPlanePos - pos).Normalized()); }
LineSegment Frustum::UnProjectLineSegment(float x, float y) const { float3 nearPlanePos = NearPlanePos(x, y); float3 farPlanePos = FarPlanePos(x, y); return LineSegment(nearPlanePos, farPlanePos); }
float3 Frustum::NearPlanePos(const float2 &point) const { return NearPlanePos(point.x, point.y); }