/// <summary> /// Transforms a box with a specified transform. /// </summary> /// <param name="inBox">The box to transform.</param> /// <param name="transform">The transform.</param> /// <returns>The transformed box.</returns> public static Box3F Transform(ref Box3F inBox, ref Matrix transform) { Vector3 center = 0.5f * (inBox.Min + inBox.Max); Vector3 extent = inBox.Max - center; Vector3 newExtent = new Vector3( extent.X * Math.Abs(transform.M11) + extent.Y * Math.Abs(transform.M21) + extent.Z * Math.Abs(transform.M31), extent.X * Math.Abs(transform.M12) + extent.Y * Math.Abs(transform.M22) + extent.Z * Math.Abs(transform.M32), extent.X * Math.Abs(transform.M13) + extent.Y * Math.Abs(transform.M23) + extent.Z * Math.Abs(transform.M33)); center = Vector3.Transform(center, transform); Box3F outBox = new Box3F(center - newExtent, center + newExtent); #if extra_strict_check // extra strict check { // Cycle through all the corners of the box and transform them. Then // extend test box by transformed corners. This box should match the // one we computed above except for precision errors. Box3F testBox= new Box3F(10E10f,10E10f,10E10f,-10E10f,-10E10f,-10E10f); center = 0.5f * (inBox.Min + inBox.Max); for (int i = 0; i < 8; i++) { Vector3 corner = center; corner.X += ((i & 1) == 0) ? extent.X : -extent.X; corner.Y += ((i & 2) == 0) ? extent.Y : -extent.Y; corner.Z += ((i & 4) == 0) ? extent.Z : -extent.Z; corner = Vector3.Transform(corner, transform); testBox.Extend(corner); } Assert.Fatal(Math.Abs(testBox.Min.X - outBox.Min.X) < 0.001f && Math.Abs(testBox.Min.Y - outBox.Min.Y) < 0.001f && Math.Abs(testBox.Min.Z - outBox.Min.Z) < 0.001f, "doh"); Assert.Fatal(Math.Abs(testBox.Max.X - outBox.Max.X) < 0.001f && Math.Abs(testBox.Max.Y - outBox.Max.Y) < 0.001f && Math.Abs(testBox.Max.Z - outBox.Max.Z) < 0.001f, "doh"); } #endif return outBox; }
/// <summary> /// Generate the frustum. /// </summary> /// <param name="nearDist">The distance to the near plane.</param> /// <param name="farDist">The distance to the far plane.</param> /// <param name="fov">The field of view of the frustum.</param> /// <param name="aspectRatio">The aspect ratio.</param> /// <param name="camToWorld">The camera transform.</param> public void SetFrustum(float nearDist, float farDist, float fov, float aspectRatio, Matrix camToWorld) { _nearDist = nearDist; _farDist = farDist; float left = -farDist * (float)Math.Tan(fov * 0.5f) * aspectRatio; float right = -left; float bottom = left / aspectRatio; float top = -bottom; Vector3 farPosLeftUp = new Vector3(left, farDist, top); Vector3 farPosLeftDown = new Vector3(left, farDist, bottom); Vector3 farPosRightUp = new Vector3(right, farDist, top); Vector3 farPosRightDown = new Vector3(right, farDist, bottom); _cameraPos = camToWorld.Translation; _cameraY = MatrixUtil.MatrixGetRow(1, ref camToWorld); farPosLeftUp = MatrixUtil.MatMulP(ref farPosLeftUp, ref camToWorld); farPosLeftDown = MatrixUtil.MatMulP(ref farPosLeftDown, ref camToWorld); farPosRightUp = MatrixUtil.MatMulP(ref farPosRightUp, ref camToWorld); farPosRightDown = MatrixUtil.MatMulP(ref farPosRightDown, ref camToWorld); _bounds = new Box3F(_cameraPos, _cameraPos); _bounds.Extend(farPosLeftUp); _bounds.Extend(farPosLeftDown); _bounds.Extend(farPosRightUp); _bounds.Extend(farPosRightDown); _leftPlaneNormal = Vector3.Cross(farPosLeftUp - _cameraPos, farPosLeftDown - _cameraPos); _rightPlaneNormal = Vector3.Cross(farPosRightDown - _cameraPos, farPosRightUp - _cameraPos); _topPlaneNormal = Vector3.Cross(farPosRightUp - _cameraPos, farPosLeftUp - _cameraPos); _bottomPlaneNormal = Vector3.Cross(farPosLeftDown - _cameraPos, farPosRightDown - _cameraPos); _leftPlaneNormal.Normalize(); _rightPlaneNormal.Normalize(); _topPlaneNormal.Normalize(); _bottomPlaneNormal.Normalize(); _leftPlaneDist = Vector3.Dot(_leftPlaneNormal, _cameraPos); _rightPlaneDist = Vector3.Dot(_rightPlaneNormal, _cameraPos); _topPlaneDist = Vector3.Dot(_topPlaneNormal, _cameraPos); _bottomPlaneDist = Vector3.Dot(_bottomPlaneNormal, _cameraPos); _nearPlaneDist = -nearDist - Vector3.Dot(_cameraY, _cameraPos); _farPlaneDist = farDist + Vector3.Dot(_cameraY, _cameraPos); // precompute sin for quick object accept float minr = Math.Min(right, top); Assert.Fatal(minr > 0.0f, "doh!"); _acceptCos = _farDist / (float)Math.Sqrt(_farDist * _farDist + minr * minr); _acceptInvSin = 1.0f / (float)Math.Sqrt(1.0f - _acceptCos * _acceptCos); // precompute sin for object culling float maxr = (float)Math.Sqrt(right * right + bottom * bottom); // anything outside this cone rejected _rejectCos = _farDist / (float)Math.Sqrt(_farDist * _farDist + maxr * maxr); _rejectInvSin = 1.0f / (float)Math.Sqrt(1.0f - _rejectCos * _rejectCos); }