Beispiel #1
0
        private static bool ConstructPlaneIntersection(Vector3 Position, Matrix4x4 viewProjection, Ray ray, Vector3 perpendicularVector0, Vector3 perpendicularVector1, out Vector3 intersection)
        {
            // Choose the perpendicular plane that is more parallel to the camera plane to
            // maximize the available accuracy in the view space.
            Vector3 viewDirection           = new Vector3(viewProjection.M31, viewProjection.M32, viewProjection.M33);
            float   perpendicularVector0Dot = Math.Abs(Vector3.Dot(viewDirection, perpendicularVector0));
            float   perpendicularVector1Dot = Math.Abs(Vector3.Dot(viewDirection, perpendicularVector1));
            Plane   plane = MathC.CreatePlaneAtPoint(Position, perpendicularVector0Dot > perpendicularVector1Dot ? perpendicularVector0 : perpendicularVector1);

            // Construct intersection
            return(Collision.RayIntersectsPlane(ray, plane, out intersection));
        }
Beispiel #2
0
        public PickingResultGizmo DoPicking(Ray ray)
        {
            if (!DrawGizmo)
            {
                return(null);
            }

            bool upside = Orientation == GizmoOrientation.UpsideDown;

            // Check for translation
            if (SupportTranslateX)
            {
                float          unused;
                BoundingSphere sphereX = new BoundingSphere(Position + Vector3.UnitX * (upside ? -Size : Size) * _arrowHeadOffsetMultiplier, TranslationConeSize / 1.5f);
                if (Collision.RayIntersectsSphere(ray, sphereX, out unused))
                {
                    return(new PickingResultGizmo(GizmoMode.TranslateX));
                }
            }
            if (SupportTranslateY)
            {
                float          unused;
                BoundingSphere sphereY = new BoundingSphere(Position + Vector3.UnitY * (upside ? -Size : Size) * _arrowHeadOffsetMultiplier, TranslationConeSize / 1.5f);
                if (Collision.RayIntersectsSphere(ray, sphereY, out unused))
                {
                    return(new PickingResultGizmo(GizmoMode.TranslateY));
                }
            }
            if (SupportTranslateZ)
            {
                float          unused;
                BoundingSphere sphereZ = new BoundingSphere(Position - Vector3.UnitZ * (upside ? -Size : Size) * _arrowHeadOffsetMultiplier, TranslationConeSize / 1.5f);
                if (Collision.RayIntersectsSphere(ray, sphereZ, out unused))
                {
                    return(new PickingResultGizmo(GizmoMode.TranslateZ));
                }
            }

            // Check for scale
            if (SupportScale)
            {
                float       unused;
                BoundingBox scaleX = new BoundingBox(Position + Vector3.UnitX * (upside ? -Size : Size) / 2.0f - new Vector3(ScaleCubeSize / 2.0f),
                                                     Position + Vector3.UnitX * (upside ? -Size : Size) / 2.0f + new Vector3(ScaleCubeSize / 2.0f));
                if (Collision.RayIntersectsBox(ray, scaleX, out unused))
                {
                    return(new PickingResultGizmo(GizmoMode.ScaleX));
                }

                BoundingBox scaleY = new BoundingBox(Position + Vector3.UnitY * (upside ? -Size : Size) / 2.0f - new Vector3(ScaleCubeSize / 2.0f),
                                                     Position + Vector3.UnitY * (upside ? -Size : Size) / 2.0f + new Vector3(ScaleCubeSize / 2.0f));
                if (Collision.RayIntersectsBox(ray, scaleY, out unused))
                {
                    return(new PickingResultGizmo(GizmoMode.ScaleY));
                }

                BoundingBox scaleZ = new BoundingBox(Position - Vector3.UnitZ * (upside ? -Size : Size) / 2.0f - new Vector3(ScaleCubeSize / 2.0f),
                                                     Position - Vector3.UnitZ * (upside ? -Size : Size) / 2.0f + new Vector3(ScaleCubeSize / 2.0f));
                if (Collision.RayIntersectsBox(ray, scaleZ, out unused))
                {
                    return(new PickingResultGizmo(GizmoMode.ScaleZ));
                }
            }

            // Check for rotation
            float pickRadius = LineThickness / 2 + (Size * 0.045f);

            if (SupportRotationZ)
            {
                Plane   planeZ = MathC.CreatePlaneAtPoint(Position, MathC.HomogenousTransform(Vector3.UnitZ, RotateMatrixZ));
                Vector3 intersectionPoint;
                if (Collision.RayIntersectsPlane(ray, planeZ, out intersectionPoint))
                {
                    var distance = (intersectionPoint - Position).Length();
                    if (distance >= Size - pickRadius && distance <= Size + pickRadius)
                    {
                        Vector3 startDirection = Vector3.Normalize(intersectionPoint - Position);

                        float sin = Vector3.Dot(Vector3.UnitY, startDirection);
                        float cos = Vector3.Dot(planeZ.Normal, Vector3.Cross(Vector3.UnitY, startDirection));
                        return(new PickingResultGizmo(GizmoMode.RotateZ, (float)Math.Atan2(-sin, cos), distance));
                    }
                }
            }

            if (SupportRotationX)
            {
                Plane   planeX = MathC.CreatePlaneAtPoint(Position, MathC.HomogenousTransform(Vector3.UnitX, RotateMatrixX));
                Vector3 intersectionPoint;
                if (Collision.RayIntersectsPlane(ray, planeX, out intersectionPoint))
                {
                    var distance = (intersectionPoint - Position).Length();
                    if (distance >= Size - pickRadius && distance <= Size + pickRadius)
                    {
                        Vector3 startDirection = Vector3.Normalize(intersectionPoint - Position);

                        float sin = Vector3.Dot(Vector3.UnitY, startDirection);
                        float cos = Vector3.Dot(planeX.Normal, Vector3.Cross(Vector3.UnitY, startDirection));
                        return(new PickingResultGizmo(GizmoMode.RotateX, (float)Math.Atan2(-sin, cos), distance));
                    }
                }
            }

            if (SupportRotationY)
            {
                Plane   planeY = MathC.CreatePlaneAtPoint(Position, MathC.HomogenousTransform(Vector3.UnitY, RotateMatrixY));
                Vector3 intersectionPoint;
                if (Collision.RayIntersectsPlane(ray, planeY, out intersectionPoint))
                {
                    var distance = (intersectionPoint - Position).Length();
                    if (distance >= Size - pickRadius && distance <= Size + pickRadius)
                    {
                        Vector3 startDirection = Vector3.Normalize(intersectionPoint - Position);

                        float sin = Vector3.Dot(Vector3.UnitZ, startDirection);
                        float cos = Vector3.Dot(planeY.Normal, Vector3.Cross(Vector3.UnitZ, startDirection));
                        return(new PickingResultGizmo(GizmoMode.RotateY, (float)Math.Atan2(-sin, cos), distance));
                    }
                }
            }

            return(null);
        }
Beispiel #3
0
        /// <returns>true, if an iteraction with the gizmo is happening</returns>
        public bool MouseMoved(Matrix4x4 viewProjection, Ray ray)
        {
            if (!DrawGizmo || _mode == GizmoMode.None)
            {
                return(false);
            }

            bool upside       = Orientation == GizmoOrientation.UpsideDown;
            bool flippedScale = false;

            // Flip sizing dimensions if object is rotateable on Y axis
            if ((_mode == GizmoMode.ScaleX || _mode == GizmoMode.ScaleZ) && SupportRotationY)
            {
                flippedScale = MathC.RadToDeg(RotationY) % 180.0f >= 45.0f;
            }

            // First get the ray in 3D space from X, Y mouse coordinates
            switch (_mode)
            {
            case GizmoMode.TranslateX:
            {
                Vector3 intersection;
                if (ConstructPlaneIntersection(Position, viewProjection, ray, Vector3.UnitY, Vector3.UnitZ, out intersection))
                {
                    GizmoMove(new Vector3(intersection.X - (upside ? -Size : Size) * _arrowHeadOffsetMultiplier, Position.Y, Position.Z));
                    GizmoMoveDelta(new Vector3(intersection.X - (upside ? -Size : Size) * _arrowHeadOffsetMultiplier - Position.X, 0.0f, 0.0f));
                }
            }
            break;

            case GizmoMode.TranslateY:
            {
                Vector3 intersection;
                if (ConstructPlaneIntersection(Position, viewProjection, ray, Vector3.UnitX, Vector3.UnitZ, out intersection))
                {
                    GizmoMove(new Vector3(Position.X, intersection.Y - (upside ? -Size : Size) * _arrowHeadOffsetMultiplier, Position.Z));
                    GizmoMoveDelta(new Vector3(0.0f, intersection.Y - (upside ? -Size : Size) * _arrowHeadOffsetMultiplier - Position.Y, 0.0f));
                }
            }
            break;

            case GizmoMode.TranslateZ:
            {
                Vector3 intersection;
                if (ConstructPlaneIntersection(Position, viewProjection, ray, Vector3.UnitX, Vector3.UnitY, out intersection))
                {
                    GizmoMove(new Vector3(Position.X, Position.Y, intersection.Z + (upside ? -Size : Size) * _arrowHeadOffsetMultiplier));
                    GizmoMoveDelta(new Vector3(0.0f, 0.0f, intersection.Z + (upside ? -Size : Size) * _arrowHeadOffsetMultiplier - Position.Z));
                }
            }
            break;

            case GizmoMode.ScaleX:
            {
                Vector3 intersection;
                if (ConstructPlaneIntersection(Position, viewProjection, ray, Vector3.UnitY, Vector3.UnitZ, out intersection))
                {
                    if (flippedScale)
                    {
                        GizmoScaleZ(_scaleBase.Z * (float)Math.Exp(_scaleSpeed * (intersection.X - Position.X)));
                    }
                    else
                    {
                        GizmoScaleX(_scaleBase.X * (float)Math.Exp(_scaleSpeed * (intersection.X - Position.X)));
                    }
                }
            }
            break;

            case GizmoMode.ScaleY:
            {
                Vector3 intersection;
                if (ConstructPlaneIntersection(Position, viewProjection, ray, Vector3.UnitX, Vector3.UnitZ, out intersection))
                {
                    GizmoScaleY(_scaleBase.Y * (float)Math.Exp(_scaleSpeed * (intersection.Y - Position.Y)));
                }
            }
            break;

            case GizmoMode.ScaleZ:
            {
                Vector3 intersection;
                if (ConstructPlaneIntersection(Position, viewProjection, ray, Vector3.UnitX, Vector3.UnitY, out intersection))
                {
                    if (flippedScale)
                    {
                        GizmoScaleX(_scaleBase.X * (float)Math.Exp(_scaleSpeed * -(intersection.Z - Position.Z)));
                    }
                    else
                    {
                        GizmoScaleZ(_scaleBase.Z * (float)Math.Exp(_scaleSpeed * -(intersection.Z - Position.Z)));
                    }
                }
            }
            break;

            case GizmoMode.RotateY:
            {
                Plane   rotationPlane = MathC.CreatePlaneAtPoint(Position, MathC.HomogenousTransform(Vector3.UnitY, RotateMatrixY));
                Vector3 rotationIntersection;
                if (Collision.RayIntersectsPlane(ray, rotationPlane, out rotationIntersection))
                {
                    Vector3 direction = rotationIntersection - Position;
                    _rotationLastMouseRadius = direction.Length();
                    direction = Vector3.Normalize(direction);

                    float sin = Vector3.Dot(Vector3.UnitZ, direction);
                    float cos = Vector3.Dot(rotationPlane.Normal, Vector3.Cross(Vector3.UnitZ, direction));
                    _rotationLastMouseAngle = (float)Math.Atan2(-sin, cos);
                    GizmoRotateY(SimplifyAngle(_rotationPickAngleOffset + _rotationLastMouseAngle));
                }
            }
            break;

            case GizmoMode.RotateX:
            {
                Plane   rotationPlane = MathC.CreatePlaneAtPoint(Position, MathC.HomogenousTransform(Vector3.UnitX, RotateMatrixX));
                Vector3 rotationIntersection;
                if (Collision.RayIntersectsPlane(ray, rotationPlane, out rotationIntersection))
                {
                    Vector3 direction = rotationIntersection - Position;
                    _rotationLastMouseRadius = direction.Length();
                    direction = Vector3.Normalize(direction);

                    float sin = Vector3.Dot(Vector3.UnitY, direction);
                    float cos = Vector3.Dot(rotationPlane.Normal, Vector3.Cross(Vector3.UnitY, direction));
                    _rotationLastMouseAngle = (float)Math.Atan2(-sin, cos);
                    GizmoRotateX(SimplifyAngle(_rotationPickAngleOffset + _rotationLastMouseAngle));
                }
            }
            break;

            case GizmoMode.RotateZ:
            {
                Plane   rotationPlane = MathC.CreatePlaneAtPoint(Position, MathC.HomogenousTransform(Vector3.UnitZ, RotateMatrixZ));
                Vector3 rotationIntersection;
                if (Collision.RayIntersectsPlane(ray, rotationPlane, out rotationIntersection))
                {
                    Vector3 direction = rotationIntersection - Position;
                    _rotationLastMouseRadius = direction.Length();
                    direction = Vector3.Normalize(direction);

                    float sin = Vector3.Dot(Vector3.UnitY, direction);
                    float cos = Vector3.Dot(rotationPlane.Normal, Vector3.Cross(Vector3.UnitY, direction));
                    _rotationLastMouseAngle = (float)Math.Atan2(-sin, cos);
                    GizmoRotateZ(SimplifyAngle(_rotationPickAngleOffset + _rotationLastMouseAngle));
                }
            }
            break;
            }

            return(true);
        }