public FFrustum(FPlane[] cameraPlanes) { if (cameraPlanes.Length != 6) throw new ArgumentException("A frustum must be built from 6 planes!", "cameraPlanes"); m_planes = cameraPlanes; }
/// <summary> /// Determines if the ray intersects with the given plane. /// </summary> /// <param name="plane">Plane to check intersection with</param> /// <returns></returns> public bool IntersectsWith(FPlane plane, out float intersectDist) { float a = Vector3.Dot(Direction, plane.Normal); float num = -Vector3.Dot(Origin, plane.Normal) - plane.Distance; if (Math.Abs(a) < float.Epsilon) { intersectDist = 0f; return false; } intersectDist = num / a; return intersectDist > 0f; }
/// <summary> /// Determines if the ray intersects with the given plane. /// </summary> /// <param name="plane">Plane to check intersection with</param> /// <returns></returns> public bool IntersectsWith(FPlane plane, out float intersectDist) { float a = Vector3.Dot(Direction, plane.Normal); float num = -Vector3.Dot(Origin, plane.Normal) - plane.Distance; if (Math.Abs(a) < float.Epsilon) { intersectDist = 0f; return(false); } intersectDist = num / a; return(intersectDist > 0f); }
private void PlanesFromPoints(Vector3[] points) { if (points.Length != 8) throw new ArgumentException("A frustum must be built from the 8 corners of the frustum!", "points"); // Construct planes out of the given points. m_planes = new FPlane[6]; m_planes[0] = new FPlane(points[0], points[2], points[4]); // Left m_planes[1] = new FPlane(points[5], points[7], points[1]); // Right m_planes[2] = new FPlane(points[0], points[4], points[1]); // Top m_planes[3] = new FPlane(points[3], points[7], points[2]); // Down m_planes[4] = new FPlane(points[1], points[3], points[0]); // Near m_planes[5] = new FPlane(points[7], points[5], points[4]); // Far }
public bool TransformFromInput(FRay ray, WSceneView view) { if (m_mode != FTransformMode.Translation) { WrapCursor(); } // Store the cursor position in viewport coordinates. Vector2 screenDimensions = App.GetScreenGeometry(); Vector2 cursorPos = App.GetCursorPosition(); Vector2 mouseCoords = new Vector2(((2f * cursorPos.X) / screenDimensions.X) - 1f, (1f - ((2f * cursorPos.Y) / screenDimensions.Y))); //[-1,1] range bool shiftPressed = WInput.GetKey(Key.LeftShift) || WInput.GetKey(Key.RightShift); if (m_mode == FTransformMode.Translation) { // Create a Translation Plane Vector3 axisA, axisB; if (GetNumSelectedAxes() == 1) { if (m_selectedAxes == FSelectedAxes.X) { axisB = Vector3.UnitX; } else if (m_selectedAxes == FSelectedAxes.Y) { axisB = Vector3.UnitY; } else { axisB = Vector3.UnitZ; } Vector3 dirToCamera = (m_position - view.GetCameraPos()).Normalized(); axisA = Vector3.Cross(axisB, dirToCamera); } else { axisA = ContainsAxis(m_selectedAxes, FSelectedAxes.X) ? Vector3.UnitX : Vector3.UnitZ; axisB = ContainsAxis(m_selectedAxes, FSelectedAxes.Y) ? Vector3.UnitY : Vector3.UnitZ; } Vector3 planeNormal = Vector3.Cross(axisA, axisB).Normalized(); m_translationPlane = new FPlane(planeNormal, m_position); float intersectDist; if (m_translationPlane.RayIntersectsPlane(ray, out intersectDist)) { Vector3 hitPos = ray.Origin + (ray.Direction * intersectDist); Vector3 localDelta = Vector3.Transform(hitPos - m_position, m_rotation.Inverted()); // Calculate a new position Vector3 newPos = m_position; if (ContainsAxis(m_selectedAxes, FSelectedAxes.X)) { newPos += Vector3.Transform(Vector3.UnitX, m_rotation) * localDelta.X; } if (ContainsAxis(m_selectedAxes, FSelectedAxes.Y)) { newPos += Vector3.Transform(Vector3.UnitY, m_rotation) * localDelta.Y; } if (ContainsAxis(m_selectedAxes, FSelectedAxes.Z)) { newPos += Vector3.Transform(Vector3.UnitZ, m_rotation) * localDelta.Z; } if (shiftPressed) { // Round to nearest 100 unit increment while shift is held down. newPos.X = (float)Math.Round(newPos.X / 100f) * 100f; newPos.Y = (float)Math.Round(newPos.Y / 100f) * 100f; newPos.Z = (float)Math.Round(newPos.Z / 100f) * 100f; } // Check the new location to see if it's skyrocked off into the distance due to near-plane raytracing issues. Vector3 newPosDirToCamera = (newPos - view.GetCameraPos()).Normalized(); float dot = Math.Abs(Vector3.Dot(planeNormal, newPosDirToCamera)); //Console.WriteLine("hitPos: {0} localOffset: {1} newPos: {2}, dotResult: {3}", hitPos, localOffset, newPos, dot); if (dot < 0.02f) { return(false); } // This is used to set the offset to the gizmo the mouse cursor is from the origin of the gizmo on the first frame // that you click on the gizmo. if (!m_hasSetMouseOffset) { m_translateOffset = m_position - newPos; m_deltaTranslation = Vector3.Zero; m_hasSetMouseOffset = true; return(false); } // Apply Translation m_deltaTranslation = Vector3.Transform(newPos - m_position + m_translateOffset, m_rotation.Inverted()); if (!ContainsAxis(m_selectedAxes, FSelectedAxes.X)) { m_deltaTranslation.X = 0f; } if (!ContainsAxis(m_selectedAxes, FSelectedAxes.Y)) { m_deltaTranslation.Y = 0f; } if (!ContainsAxis(m_selectedAxes, FSelectedAxes.Z)) { m_deltaTranslation.Z = 0f; } m_totalTranslation += m_deltaTranslation; m_position += Vector3.Transform(m_deltaTranslation, m_rotation); if (!m_hasTransformed && (m_deltaTranslation != Vector3.Zero)) { m_hasTransformed = true; } return(m_hasTransformed); } else { // Our raycast missed the plane m_deltaTranslation = Vector3.Zero; return(false); } } else if (m_mode == FTransformMode.Rotation) { Vector3 rotationAxis; if (m_selectedAxes == FSelectedAxes.X) { rotationAxis = Vector3.UnitX; } else if (m_selectedAxes == FSelectedAxes.Y) { rotationAxis = Vector3.UnitY; } else { rotationAxis = Vector3.UnitZ; } // Convert these from [0-1] to [-1, 1] to match our mouse coords. Vector2 lineOrigin = (view.UnprojectWorldToViewport(m_hitPoint) * 2) - Vector2.One; Vector2 lineEnd = (view.UnprojectWorldToViewport(m_hitPoint + m_moveDir) * 2) - Vector2.One; lineOrigin.Y = -lineOrigin.Y; lineEnd.Y = -lineEnd.Y; Vector2 lineDir = (lineEnd - lineOrigin).Normalized(); float rotAmount = Vector2.Dot(lineDir, mouseCoords + m_wrapOffset - lineOrigin) * 180f; if (float.IsNaN(rotAmount)) { Console.WriteLine("rotAmountNaN!"); return(false); } if (!m_hasSetMouseOffset) { m_rotateOffset = -rotAmount; m_deltaRotation = Quaternion.Identity; m_hasSetMouseOffset = true; return(false); } // Apply Rotation rotAmount += m_rotateOffset; if (shiftPressed) { // Round to nearest 45 degree increment while shift is held down. rotAmount = (float)Math.Round(rotAmount / 45f) * 45f; } Quaternion oldRot = m_currentRotation; m_currentRotation = Quaternion.FromAxisAngle(rotationAxis, WMath.DegreesToRadians(rotAmount)); m_deltaRotation = m_currentRotation * oldRot.Inverted(); if (m_transformSpace == FTransformSpace.Local) { m_rotation *= m_deltaRotation; } // Add to Total Rotation recorded for UI. if (m_selectedAxes == FSelectedAxes.X) { m_totalRotation.X = rotAmount; } else if (m_selectedAxes == FSelectedAxes.Y) { m_totalRotation.Y = rotAmount; } else { m_totalRotation.Z = rotAmount; } if (!m_hasTransformed && rotAmount != 0f) { m_hasTransformed = true; } return(m_hasTransformed); } else if (m_mode == FTransformMode.Scale) { // Create a line in screen space. // Convert these from [0-1] to [-1, 1] to match our mouse coords. Vector2 lineOrigin = (view.UnprojectWorldToViewport(m_position) * 2) - Vector2.One; lineOrigin.Y = -lineOrigin.Y; // Determine the appropriate world space directoin using the selected axes and then conver this for use with // screen-space controlls. This has to be done every frame because the axes can be flipped while the gizmo // is transforming, so we can't pre-calculate this. Vector3 dirX = Vector3.Transform(mFlipScaleX ? -Vector3.UnitX : Vector3.UnitX, m_rotation); Vector3 dirY = Vector3.Transform(mFlipScaleY ? -Vector3.UnitY : Vector3.UnitY, m_rotation); Vector3 dirZ = Vector3.Transform(mFlipScaleZ ? -Vector3.UnitZ : Vector3.UnitZ, m_rotation); Vector2 lineDir; // If there is only one axis, then the world space direction is the selected axis. if (GetNumSelectedAxes() == 1) { Vector3 worldDir; if (ContainsAxis(m_selectedAxes, FSelectedAxes.X)) { worldDir = dirX; } if (ContainsAxis(m_selectedAxes, FSelectedAxes.Y)) { worldDir = dirY; } else { worldDir = dirZ; } Vector2 worldPoint = (view.UnprojectWorldToViewport(m_position + worldDir) * 2) - Vector2.One; worldPoint.Y = -lineOrigin.Y; lineDir = (worldPoint - lineOrigin).Normalized(); } // If there's two axii selected, then convert both to screen space and average them out to get the line direction. else if (GetNumSelectedAxes() == 2) { Vector3 axisA = ContainsAxis(m_selectedAxes, FSelectedAxes.X) ? dirX : dirY; Vector3 axisB = ContainsAxis(m_selectedAxes, FSelectedAxes.Z) ? dirZ : dirY; Vector2 screenA = (view.UnprojectWorldToViewport(m_position + axisA) * 2) - Vector2.One; screenA.Y = -screenA.Y; Vector2 screenB = (view.UnprojectWorldToViewport(m_position + axisB) * 2) - Vector2.One; screenB.Y = -screenB.Y; screenA = (screenA - lineOrigin).Normalized(); screenB = (screenB - lineOrigin).Normalized(); lineDir = ((screenA + screenB) / 2f).Normalized(); } // There's three axis, just use up. else { lineDir = Vector2.UnitY; } float scaleAmount = Vector2.Dot(lineDir, mouseCoords + m_wrapOffset - lineOrigin) * 5f; if (shiftPressed) { // Round to nearest whole number scale while shift is held down. scaleAmount = (float)Math.Round(scaleAmount); } // Set their initial offset if we haven't already if (!m_hasSetMouseOffset) { m_scaleOffset = -scaleAmount; m_deltaScale = Vector3.One; m_hasSetMouseOffset = true; return(false); } // Apply the scale scaleAmount = scaleAmount + m_scaleOffset + 1f; // A multiplier is applied to the scale amount if it's less than one to prevent it dropping into the negatives. // ??? if (scaleAmount < 1f) { scaleAmount = 1f / (-(scaleAmount - 1f) + 1f); } Vector3 oldScale = m_totalScale; m_totalScale = Vector3.One; if (ContainsAxis(m_selectedAxes, FSelectedAxes.X)) { m_totalScale.X = scaleAmount; } if (ContainsAxis(m_selectedAxes, FSelectedAxes.Y)) { m_totalScale.Y = scaleAmount; } if (ContainsAxis(m_selectedAxes, FSelectedAxes.Z)) { m_totalScale.Z = scaleAmount; } m_deltaScale = new Vector3(m_totalScale.X / oldScale.X, m_totalScale.Y / oldScale.Y, m_totalScale.Z / oldScale.Z); if (!m_hasTransformed && (scaleAmount != 1f)) { m_hasTransformed = true; } return(m_hasTransformed); } return(false); }