示例#1
0
        private WActorNode Raycast(FRay ray)
        {
            if (m_world.Map == null)
            {
                return(null);
            }

            WActorNode closestResult   = null;
            float      closestDistance = float.MaxValue;

            foreach (var scene in m_world.Map.SceneList)
            {
                List <WActorNode> allActors = scene.GetChildrenOfType <WActorNode>();

                foreach (WActorNode actorNode in allActors)
                {
                    float intersectDistance;
                    bool  hitActor = actorNode.Raycast(ray, out intersectDistance);
                    if (hitActor)
                    {
                        if (intersectDistance >= 0 && intersectDistance < closestDistance)
                        {
                            closestDistance = intersectDistance;
                            closestResult   = actorNode;
                        }
                    }
                }
            }

            return(closestResult);
        }
示例#2
0
        public bool Raycast(FRay ray, out float closestDistance)
        {
            // Convert the ray to local space of this node since all of our raycasts are local.
            FRay localRay = WMath.TransformRay(ray, Transform.Position, Transform.LocalScale, Transform.Rotation.Inverted());
            bool bHit     = false;

            if (m_actorMesh != null)
            {
                bHit = m_actorMesh.Raycast(localRay, out closestDistance, true);
            }
            else
            {
                bHit = WMath.RayIntersectsAABB(localRay, m_objRender.GetAABB().Min, m_objRender.GetAABB().Max, out closestDistance);
            }

            if (bHit)
            {
                // Convert the hit point back to world space...
                Vector3 localHitPoint = localRay.Origin + (localRay.Direction * closestDistance);
                localHitPoint = Vector3.Transform(localHitPoint + Transform.Position, Transform.Rotation);

                // Now get the distance from the original ray origin and the new worldspace hit point.
                closestDistance = (localHitPoint - ray.Origin).Length;
            }

            return(bHit);
        }
示例#3
0
        public static bool RayIntersectsAABB(FRay ray, Vector3 aabbMin, Vector3 aabbMax, out float intersectionDistance)
        {
            Vector3 t_1 = new Vector3(), t_2 = new Vector3();

            float tNear = float.MinValue;
            float tFar  = float.MaxValue;

            // Test infinite planes in each directin.
            for (int i = 0; i < 3; i++)
            {
                // Ray is parallel to planes in this direction.
                if (ray.Direction[i] == 0)
                {
                    if ((ray.Origin[i] < aabbMin[i]) || (ray.Origin[i] > aabbMax[i]))
                    {
                        // Parallel and outside of the box, thus no intersection is possible.
                        intersectionDistance = float.MinValue;
                        return(false);
                    }
                }
                else
                {
                    t_1[i] = (aabbMin[i] - ray.Origin[i]) / ray.Direction[i];
                    t_2[i] = (aabbMax[i] - ray.Origin[i]) / ray.Direction[i];

                    // Ensure T_1 holds values for intersection with near plane.
                    if (t_1[i] > t_2[i])
                    {
                        Vector3 temp = t_2;
                        t_2 = t_1;
                        t_1 = temp;
                    }

                    if (t_1[i] > tNear)
                    {
                        tNear = t_1[i];
                    }

                    if (t_2[i] < tFar)
                    {
                        tFar = t_2[i];
                    }

                    if ((tNear > tFar) || (tFar < 0))
                    {
                        intersectionDistance = float.MinValue;
                        return(false);
                    }
                }
            }

            intersectionDistance = tNear;
            return(true);
        }
示例#4
0
        private void CheckForObjectSelectionChange(WSceneView view)
        {
            // If we have a gizmo and we're transforming it, don't check for selection change.
            if (m_transformGizmo != null && m_transformGizmo.IsTransforming)
            {
                return;
            }
            if (WInput.GetMouseButtonDown(0) && !WInput.GetMouseButton(1))
            {
                FRay       mouseRay   = view.ProjectScreenToWorld(WInput.MousePosition);
                WActorNode addedActor = Raycast(mouseRay);

                // Check the behaviour of this click to determine appropriate selection modification behaviour.
                // Click w/o Modifiers = Clear Selection, add result to selection
                // Click /w Ctrl = Toggle Selection State
                // Click /w Shift = Add to Selection
                bool ctrlPressed  = WInput.GetKey(Key.LeftCtrl) || WInput.GetKey(Key.RightCtrl);
                bool shiftPressed = WInput.GetKey(Key.LeftShift) || WInput.GetKey(Key.RightShift);

                if (!ctrlPressed & !shiftPressed)
                {
                    ModifySelection(SelectionType.Add, addedActor, true);
                    //m_selectionList.Clear();
                    //if (addedActor != null) m_selectionList.Add(addedActor);
                }
                else if (addedActor != null && (ctrlPressed && !shiftPressed))
                {
                    if (m_selectionList.Contains(addedActor))
                    {
                        ModifySelection(SelectionType.Remove, addedActor, false);
                    }
                    //m_selectionList.Remove(addedActor);
                    else
                    {
                        ModifySelection(SelectionType.Add, addedActor, false);
                    }
                    //m_selectionList.Add(addedActor);
                }
                else if (addedActor != null && shiftPressed)
                {
                    if (!m_selectionList.Contains(addedActor))
                    {
                        ModifySelection(SelectionType.Add, addedActor, false);
                    }
                    //m_selectionList.Add(addedActor);
                }

                if (m_transformGizmo != null && m_selectionList.Count > 0)
                {
                    m_transformGizmo.SetPosition(m_selectionList[0].Transform.Position);
                    m_transformGizmo.SetLocalRotation(m_selectionList[0].Transform.Rotation);
                }
            }
        }
示例#5
0
        public bool RayIntersectsPlane(FRay ray, out float intersectDist)
        {
            float a   = Vector3.Dot(ray.Direction, Normal);
            float num = -Vector3.Dot(ray.Origin, Normal) - Distance;

            if (Math.Abs(a) < float.Epsilon)
            {
                intersectDist = 0f;
                return(false);
            }
            intersectDist = num / a;
            return(intersectDist > 0f);
        }
示例#6
0
        public bool Raycast(FRay ray, out float closestDistance)
        {
            // Convert the ray to local space of this node since all of our raycasts are local.
            FRay localRay;

            if (DisableRotationAndScaleForRaycasting)
            {
                localRay = WMath.TransformRay(ray, Transform.Position, Vector3.One, Quaternion.Identity);
            }
            else
            {
                localRay = WMath.TransformRay(ray, Transform.Position, VisualScale, Transform.Rotation.Inverted().ToSinglePrecision());
            }
            closestDistance = float.MaxValue;
            bool bHit = false;

            if (m_actorMeshes.Count > 0)
            {
                foreach (var actor_mesh in m_actorMeshes)
                {
                    bHit = actor_mesh.Raycast(localRay, out closestDistance, true);

                    if (bHit)
                    {
                        break;
                    }
                }
            }
            else if (m_objRender != null)
            {
                if (m_objRender.FaceCullingEnabled && m_objRender.GetAABB().Contains(localRay.Origin))
                {
                    // If the camera is inside an OBJ render that has backface culling on, the actor won't actually be visible, so don't select it.
                    return(false);
                }

                bHit = WMath.RayIntersectsAABB(localRay, m_objRender.GetAABB().Min, m_objRender.GetAABB().Max, out closestDistance);

                if (bHit)
                {
                    // Convert the hit point back to world space...
                    Vector3 localHitPoint  = localRay.Origin + (localRay.Direction * closestDistance);
                    Vector3 globalHitPoint = Transform.Position + Vector3.Transform(localHitPoint, Transform.Rotation.ToSinglePrecision());

                    // Now get the distance from the original ray origin and the new worldspace hit point.
                    closestDistance = (globalHitPoint - ray.Origin).Length;
                }
            }

            return(bHit);
        }
示例#7
0
        private void CheckForObjectSelectionChange(WSceneView view)
        {
            // If we have a gizmo and we're transforming it, don't check for selection change.
            if (m_transformGizmo != null && m_transformGizmo.IsTransforming)
            {
                return;
            }
            if (WInput.GetMouseButtonDown(0) && !WInput.GetMouseButton(1))
            {
                FRay mouseRay   = view.ProjectScreenToWorld(WInput.MousePosition);
                var  addedActor = Raycast(mouseRay);

                // Check the behaviour of this click to determine appropriate selection modification behaviour.
                // Click w/o Modifiers = Clear Selection, add result to selection
                // Click /w Ctrl = Toggle Selection State
                // Click /w Shift = Add to Selection
                bool ctrlPressed  = WInput.GetKey(Key.LeftCtrl) || WInput.GetKey(Key.RightCtrl);
                bool shiftPressed = WInput.GetKey(Key.LeftShift) || WInput.GetKey(Key.RightShift);

                if (!ctrlPressed & !shiftPressed)
                {
                    EditorSelection.ClearSelection();
                    if (addedActor != null)
                    {
                        EditorSelection.AddToSelection(addedActor);
                    }
                }
                else if (addedActor != null && (ctrlPressed && !shiftPressed))
                {
                    if (addedActor.IsSelected)
                    {
                        EditorSelection.RemoveFromSelection(addedActor);
                    }
                    else
                    {
                        EditorSelection.AddToSelection(addedActor);
                    }
                }
                else if (addedActor != null && shiftPressed)
                {
                    if (!EditorSelection.SelectedObjects.Contains(addedActor))
                    {
                        EditorSelection.AddToSelection(addedActor);
                    }
                }

                UpdateGizmoTransform();
            }
        }
        public static FRay TransformRay(FRay ray, Vector3 position, Vector3 scale, Quaternion rotation)
        {
            FRay localRay = new FRay();
            localRay.Direction = Vector3.Transform(ray.Direction, rotation);
            localRay.Origin = Vector3.Transform(ray.Origin - position, rotation);

            // We need to divide the origin and the direction by the scale. If you skip dividing the direction by the
            // scale, then it doesn't work on non-uniformly scaled objects.
            localRay.Origin.X /= scale.X;
            localRay.Origin.Y /= scale.Y;
            localRay.Origin.Z /= scale.Z;

            localRay.Direction.X /= scale.X;
            localRay.Direction.Y /= scale.Y;
            localRay.Direction.Z /= scale.Z;
            localRay.Direction.Normalize();

            return localRay;
        }
示例#9
0
        public static FRay TransformRay(FRay ray, Vector3 position, Vector3 scale, Quaternion rotation)
        {
            FRay localRay = new FRay();

            localRay.Direction = Vector3.Transform(ray.Direction, rotation);
            localRay.Origin    = Vector3.Transform(ray.Origin - position, rotation);

            // We need to divide the origin and the direction by the scale. If you skip dividing the direction by the
            // scale, then it doesn't work on non-uniformly scaled objects.
            localRay.Origin.X /= scale.X;
            localRay.Origin.Y /= scale.Y;
            localRay.Origin.Z /= scale.Z;

            localRay.Direction.X /= scale.X;
            localRay.Direction.Y /= scale.Y;
            localRay.Direction.Z /= scale.Z;
            localRay.Direction.Normalize();

            return(localRay);
        }
示例#10
0
        public static bool RayIntersectsTriangle(FRay ray, Vector3 v1, Vector3 v2, Vector3 v3, bool oneSided, out float intersectionDistance)
        {
            intersectionDistance = float.MinValue;

            // Find Vectors for two edges sharing v1
            Vector3 e1 = v2 - v1;
            Vector3 e2 = v3 - v1;

            // Begin calculating determinant - also used to calculate 'u' parameter
            Vector3 p;

            Vector3.Cross(ref ray.Direction, ref e2, out p);

            // If determinant is near zero, ray lies in plane of triangle/ray is parallel to plane of triangle.
            float det = Vector3.Dot(e1, p);

            if (oneSided)
            {
                Vector3 n;
                Vector3.Cross(ref e2, ref e1, out n);
                n.NormalizeFast();

                float dirToTri;
                Vector3.Dot(ref ray.Direction, ref n, out dirToTri);

                // Back-facing surface, early out.
                if (dirToTri > 0)
                {
                    return(false);
                }
            }

            // No Collision
            if (det > -float.Epsilon && det < float.Epsilon)
            {
                return(false);
            }

            float inv_det = 1f / det;

            // Calculate distance from V1 to ray origin
            Vector3 t;

            Vector3.Subtract(ref ray.Origin, ref v1, out t);

            // Calculate 'u' parameter and test bound
            float u;

            Vector3.Dot(ref t, ref p, out u);
            u *= inv_det;

            // No Collision - Intersection lies outside of the triangle.
            if (u < 0f || u > 1f)
            {
                return(false);
            }

            // Prepare to test v parameter
            Vector3 q;

            Vector3.Cross(ref t, ref e1, out q);

            // Calculate 'v' parameter and test bound
            float v;

            Vector3.Dot(ref ray.Direction, ref q, out v);
            v *= inv_det;

            // No Collision - Intersection lies outside of the triangle.
            if (v < 0f || u + v > 1f)
            {
                return(false);
            }

            float dist;

            Vector3.Dot(ref e2, ref q, out dist);
            dist *= inv_det;

            if (dist > float.Epsilon)
            {
                intersectionDistance = dist;
                return(true);
            }

            // No hit, no win.
            return(false);
        }
示例#11
0
        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);
        }
示例#12
0
        public bool CheckSelectedAxes(FRay ray)
        {
            // Convert the ray into local space so we can use axis-aligned checks, this solves the checking problem
            // when the gizmo is rotated due to being in Local mode.
            FRay localRay = new FRay();

            localRay.Direction = Vector3.Transform(ray.Direction, m_rotation.Inverted());
            localRay.Origin    = Vector3.Transform(ray.Origin - m_position, m_rotation.Inverted());

            //m_lineBatcher.DrawLine(localRay.Origin, localRay.Origin + (localRay.Direction * 10000), WLinearColor.White, 25, 5);
            List <AxisDistanceResult> results = new List <AxisDistanceResult>();

            if (m_mode == FTransformMode.Translation)
            {
                FAABox[] translationAABB = GetAABBBoundsForMode(FTransformMode.Translation);
                for (int i = 0; i < translationAABB.Length; i++)
                {
                    float intersectDist;
                    if (WMath.RayIntersectsAABB(localRay, translationAABB[i].Min, translationAABB[i].Max, out intersectDist))
                    {
                        results.Add(new AxisDistanceResult((FSelectedAxes)(i + 1), intersectDist));
                    }
                }
            }
            else if (m_mode == FTransformMode.Rotation)
            {
                // We'll use a combination of AABB and Distance checks to give us the quarter-circles we need.
                FAABox[] rotationAABB = GetAABBBoundsForMode(FTransformMode.Rotation);

                float screenScale = 0f;
                for (int i = 0; i < 3; i++)
                {
                    screenScale += m_scale[i];
                }
                screenScale /= 3f;

                for (int i = 0; i < rotationAABB.Length; i++)
                {
                    float intersectDist;
                    if (WMath.RayIntersectsAABB(localRay, rotationAABB[i].Min, rotationAABB[i].Max, out intersectDist))
                    {
                        Vector3 intersectPoint = localRay.Origin + (localRay.Direction * intersectDist);
                        // Convert this aabb check into a radius check so we clip it by the semi-circles
                        // that the rotation tool actually is.
                        if (intersectPoint.Length > 105f * screenScale)
                        {
                            continue;
                        }

                        results.Add(new AxisDistanceResult((FSelectedAxes)(i + 1), intersectDist));
                    }
                }
            }
            else if (m_mode == FTransformMode.Scale)
            {
                FAABox[] scaleAABB = GetAABBBoundsForMode(FTransformMode.Scale);
                for (int i = 0; i < scaleAABB.Length; i++)
                {
                    float intersectDist;
                    if (WMath.RayIntersectsAABB(localRay, scaleAABB[i].Min, scaleAABB[i].Max, out intersectDist))
                    {
                        // Special-case here to give the center scale point overriding priority. Because we intersected
                        // it, we can just override its distance to zero to make it clickable through the other bounding boxes.
                        if ((FSelectedAxes)i + 1 == FSelectedAxes.All)
                        {
                            intersectDist = 0f;
                        }

                        results.Add(new AxisDistanceResult((FSelectedAxes)(i + 1), intersectDist));
                    }
                }
            }

            if (results.Count == 0)
            {
                m_selectedAxes = FSelectedAxes.None;
                return(false);
            }

            // If we get an intersection, sort them by the closest intersection distance.
            results.Sort((x, y) => x.Distance.CompareTo(y.Distance));
            m_selectedAxes = results[0].Axis;

            // Store where the mouse hit on the first frame in world space. This means converting the ray back to worldspace.
            Vector3 localHitPoint = localRay.Origin + (localRay.Direction * results[0].Distance);

            m_hitPoint = Vector3.Transform(localHitPoint, m_rotation) + m_position;
            return(true);
        }
示例#13
0
        private void UpdateSelectionGizmo(WSceneView view)
        {
            if (!m_transformGizmo.Enabled && m_selectionList.Count > 0)
            {
                // Show the Transform Gizmo.
                m_transformGizmo.Enabled = true;

                m_transformGizmo.SetPosition(m_selectionList[0].Transform.Position);
                m_transformGizmo.SetLocalRotation(m_selectionList[0].Transform.Rotation);
            }
            else if (m_transformGizmo.Enabled && m_selectionList.Count == 0)
            {
                // Hide the Transform Gizmo.
                m_transformGizmo.Enabled = false;
            }

            if (!m_transformGizmo.Enabled)
            {
                return;
            }

            if (WInput.GetKeyDown(Key.Q) && !WInput.GetMouseButton(1))
            {
                m_transformGizmo.SetMode(FTransformMode.None);
            }
            if (WInput.GetKeyDown(Key.W) && !WInput.GetMouseButton(1))
            {
                m_transformGizmo.SetMode(FTransformMode.Translation);
            }
            if (WInput.GetKeyDown(Key.E) && !WInput.GetMouseButton(1))
            {
                m_transformGizmo.SetMode(FTransformMode.Rotation);
            }
            if (WInput.GetKeyDown(Key.R) && !WInput.GetMouseButton(1))
            {
                m_transformGizmo.SetMode(FTransformMode.Scale);
            }

            if (WInput.GetKeyDown(Key.OemOpenBrackets))
            {
                m_transformGizmo.DecrementSize();
            }

            if (WInput.GetKeyDown(Key.OemCloseBrackets))
            {
                m_transformGizmo.IncrementSize();
            }

            if (WInput.GetKeyDown(Key.OemTilde))
            {
                if (m_transformGizmo.TransformSpace == FTransformSpace.World)
                {
                    m_transformGizmo.SetTransformSpace(FTransformSpace.Local);
                }
                else
                {
                    m_transformGizmo.SetTransformSpace(FTransformSpace.World);
                }

                UpdateGizmoTransform();
            }

            if (WInput.GetMouseButtonDown(0))
            {
                FRay mouseRay = view.ProjectScreenToWorld(WInput.MousePosition);
                if (m_transformGizmo.CheckSelectedAxes(mouseRay))
                {
                    m_transformGizmo.StartTransform();
                }
            }

            if (WInput.GetMouseButtonUp(0))
            {
                if (m_transformGizmo.IsTransforming)
                {
                    // When we end let go of the gizmo, we want to make one last action which specifies that it is done,
                    // so that the next gizmo move doesn't merge with the previous.
                    WUndoCommand undoAction = CreateUndoActionForGizmo(true);
                    if (undoAction != null)
                    {
                        m_world.UndoStack.Push(undoAction);
                    }

                    m_transformGizmo.EndTransform();
                }
            }

            if (m_transformGizmo.IsTransforming)
            {
                FRay mouseRay = view.ProjectScreenToWorld(WInput.MousePosition);
                if (m_transformGizmo.TransformFromInput(mouseRay, view))
                {
                    WUndoCommand undoAction = CreateUndoActionForGizmo(false);
                    if (undoAction != null)
                    {
                        m_world.UndoStack.Push(undoAction);
                    }
                }
            }

            m_transformGizmo.UpdateForSceneView(view);
        }
        public static bool RayIntersectsAABB(FRay ray, Vector3 aabbMin, Vector3 aabbMax, out float intersectionDistance)
        {
            Vector3 t_1 = new Vector3(), t_2 = new Vector3();

            float tNear = float.MinValue;
            float tFar = float.MaxValue;

            // Test infinite planes in each directin.
            for (int i = 0; i < 3; i++)
            {
                // Ray is parallel to planes in this direction.
                if (ray.Direction[i] == 0)
                {
                    if ((ray.Origin[i] < aabbMin[i]) || (ray.Origin[i] > aabbMax[i]))
                    {
                        // Parallel and outside of the box, thus no intersection is possible.
                        intersectionDistance = float.MinValue;
                        return false;
                    }
                }
                else
                {
                    t_1[i] = (aabbMin[i] - ray.Origin[i]) / ray.Direction[i];
                    t_2[i] = (aabbMax[i] - ray.Origin[i]) / ray.Direction[i];

                    // Ensure T_1 holds values for intersection with near plane.
                    if (t_1[i] > t_2[i])
                    {
                        Vector3 temp = t_2;
                        t_2 = t_1;
                        t_1 = temp;
                    }

                    if (t_1[i] > tNear)
                        tNear = t_1[i];

                    if (t_2[i] < tFar)
                        tFar = t_2[i];

                    if ((tNear > tFar) || (tFar < 0))
                    {
                        intersectionDistance = float.MinValue;
                        return false;
                    }
                }
            }

            intersectionDistance = tNear;
            return true;
        }
        public static bool RayIntersectsTriangle(FRay ray, Vector3 v1, Vector3 v2, Vector3 v3, bool oneSided, out float intersectionDistance)
        {
            intersectionDistance = float.MinValue;

            // Find Vectors for two edges sharing v1
            Vector3 e1 = v2 - v1;
            Vector3 e2 = v3 - v1;

            // Begin calculating determinant - also used to calculate 'u' parameter
            Vector3 p;
            Vector3.Cross(ref ray.Direction, ref e2, out p);

            // If determinant is near zero, ray lies in plane of triangle/ray is parallel to plane of triangle.
            float det = Vector3.Dot(e1, p);

            if (oneSided)
            {
                Vector3 n;
                Vector3.Cross(ref e2, ref e1, out n);
                n.NormalizeFast();

                float dirToTri;
                Vector3.Dot(ref ray.Direction, ref n, out dirToTri);

                // Back-facing surface, early out.
                if (dirToTri > 0)
                    return false;
            }

            // No Collision
            if (det > -float.Epsilon && det < float.Epsilon)
                return false;

            float inv_det = 1f / det;

            // Calculate distance from V1 to ray origin
            Vector3 t;
            Vector3.Subtract(ref ray.Origin, ref v1, out t);

            // Calculate 'u' parameter and test bound
            float u;
            Vector3.Dot(ref t, ref p, out u);
            u *= inv_det;

            // No Collision - Intersection lies outside of the triangle.
            if (u < 0f || u > 1f)
                return false;

            // Prepare to test v parameter
            Vector3 q;
            Vector3.Cross(ref t, ref e1, out q);

            // Calculate 'v' parameter and test bound
            float v;
            Vector3.Dot(ref ray.Direction, ref q, out v);
            v *= inv_det;

            // No Collision - Intersection lies outside of the triangle.
            if (v < 0f || u + v > 1f)
                return false;

            float dist;
            Vector3.Dot(ref e2, ref q, out dist);
            dist *= inv_det;

            if (dist > float.Epsilon)
            {
                intersectionDistance = dist;
                return true;
            }

            // No hit, no win.
            return false;
        }