Exemplo n.º 1
0
        private bool CanManipulate(ITransformable node)
        {
            bool result = node != null &&
                          (node.TransformationType & TransformationTypes.Pivot) != 0 &&
                          node.Cast <IVisible>().Visible &&
                          node.Cast <ILockable>().IsLocked == false;

            return(result);
        }
Exemplo n.º 2
0
        private bool CanManipulate(ITransformable node, FilterDelegate filter)
        {
            bool result = node != null &&
                          node.Cast <IVisible>().Visible &&
                          node.Cast <ILockable>().IsLocked == false &&
                          filter(node);

            return(result);
        }
Exemplo n.º 3
0
        /// <summary>
        /// For an object 'node' that is being manipulated, this function returns
        /// the offset (in world space) from the object's origin to to the point that is being
        /// "snapped from". This calculation is determined by the snapping modes.</summary>
        /// <param name="node">The object that is being snapped-to some other object</param>
        /// <param name="snapFromMode">The "snap from" mode, as an enum</param>
        /// <param name="axisType">Axis system type (y or z is up)</param>
        /// <param name="pivot">Pass in either node.RotatePivot or node.ScalePivot</param>
        /// <returns>Offset from this object's origin to the "snap from" point, in world space</returns>
        /// <remarks>Must be kept in sync with SnapFromModes property.</remarks>
        public static Vec3F CalcSnapFromOffset(
            ITransformable node,
            SnapFromMode snapFromMode,
            AxisSystemType axisType, Vec3F pivot)
        {
            switch (snapFromMode)
            {
            case SnapFromMode.Pivot:
            {
                Vec3F          offset;
                Path <DomNode> path          = new Path <DomNode>(node.Cast <DomNode>().Ancestry);
                Matrix4F       parentToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2);
                node.Transform.TransformVector(pivot, out offset); //local-to-parent
                parentToWorld.TransformVector(offset, out offset); //parent-to-world
                return(offset);                                    //world
            }

            case SnapFromMode.Origin:
                return(new Vec3F(0, 0, 0));

            case SnapFromMode.BottomCenter:
            {
                Box   box = node.BoundingBox;
                Vec3F btmWorld;
                if (axisType == AxisSystemType.YIsUp)
                {
                    btmWorld = new Vec3F(
                        (box.Min.X + box.Max.X) * 0.5f,
                        box.Min.Y,
                        (box.Min.Z + box.Max.Z) * 0.5f);
                }
                else
                {
                    btmWorld = new Vec3F(
                        (box.Min.X + box.Max.X) * 0.5f,
                        (box.Min.Y + box.Max.Y) * 0.5f,
                        box.Min.Z);
                }
                Vec3F origin = node.Transform.Translation;
                Vec3F offset = btmWorld - origin;         //local space offset

                Path <DomNode> path          = new Path <DomNode>(node.Cast <DomNode>().GetPath());
                Matrix4F       parentToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2);
                parentToWorld.TransformVector(offset, out offset);

                return(offset);
            }

            default:
                throw new ArgumentException("Invalid snap-from node");
            }
        }
        protected override Matrix4F GetManipulatorMatrix()
        {
            ITransformable node = GetManipulatorNode(TransformationTypes.Translation);

            if (node == null)
            {
                return(null);
            }

            ISnapSettings  snapSettings = (ISnapSettings)DesignView;
            Path <DomNode> path         = new Path <DomNode>(node.Cast <DomNode>().GetPath());
            Matrix4F       localToWorld = TransformUtils.CalcPathTransform(path, path.Count - 1);

            Matrix4F toworld = new Matrix4F();

            if (snapSettings.ManipulateLocalAxis)
            {
                toworld.Set(localToWorld);
                toworld.Normalize(toworld);
            }
            else
            {
                toworld.Translation = localToWorld.Translation;
            }

            Vec3F offset = TransformUtils.CalcSnapFromOffset(node, snapSettings.SnapFrom);

            // Offset by pivot
            Matrix4F P = new Matrix4F();

            P.Translation = offset;
            toworld.Mul(toworld, P);

            return(toworld);
        }
Exemplo n.º 5
0
        protected override Matrix4F GetManipulatorMatrix()
        {
            ITransformable node = GetManipulatorNode(TransformationTypes.Scale);

            if (node == null)
            {
                return(null);
            }

            Path <DomNode> path         = new Path <DomNode>(node.Cast <DomNode>().GetPath());
            Matrix4F       localToWorld = TransformUtils.CalcPathTransform(path, path.Count - 1);

            // local transform
            Matrix4F toworld = new Matrix4F(localToWorld);

            // Offset by pivot
            Matrix4F P = new Matrix4F();

            P.Translation = node.Pivot;
            toworld.Mul(P, toworld);

            // Normalize
            toworld.Normalize(toworld);

            return(toworld);
        }
Exemplo n.º 6
0
        public static Vec3F CalcSnapFromOffset(ITransformable node, SnapFromMode snapFrom)
        {
            // AABB in local space.
            AABB box = node.As <IBoundable>().LocalBoundingBox;

            Vec3F offsetLocal = box.Center;

            switch (snapFrom)
            {
            case SnapFromMode.Pivot:
                offsetLocal = node.Pivot;
                break;

            case SnapFromMode.Origin:
                offsetLocal = box.Center;
                break;

            case SnapFromMode.TopCenter:
                offsetLocal.Y = box.Max.Y;
                break;

            case SnapFromMode.BottomCenter:
                offsetLocal.Y = box.Min.Y;
                break;

            case SnapFromMode.FrontCenter:
                offsetLocal.Z = box.Max.Z;
                break;

            case SnapFromMode.BackCenter:
                offsetLocal.Z = box.Min.Z;
                break;

            case SnapFromMode.LeftCenter:
                offsetLocal.X = box.Min.X;
                break;

            case SnapFromMode.RightCenter:
                offsetLocal.X = box.Max.X;
                break;

            default:
                throw new ArgumentOutOfRangeException("Invalid snap-from node");
            }

            Path <DomNode> path    = new Path <DomNode>(node.Cast <DomNode>().GetPath());
            Matrix4F       toWorld = TransformUtils.CalcPathTransform(path, path.Count - 1);

            Vec3F offset;

            toWorld.TransformVector(offsetLocal, out offset); //local-to-world
            return(offset);                                   //world
        }
Exemplo n.º 7
0
        /// <summary>
        /// Adjusts child transform, making it the concatenation with its parent's transform.
        /// Is recursive, looking for parents that also implement IRenderableNode.</summary>
        /// <param name="parent">Parent node</param>
        /// <param name="child">Child node</param>
        public static void RemoveChild(ITransformable parent, ITransformable child)
        {
            Path <DomNode> path         = new Path <DomNode>(parent.Cast <DomNode>().GetPath());
            Matrix4F       parentMatrix = TransformUtils.CalcPathTransform(path, path.Count - 1);

            Matrix4F childMatrix    = child.Transform;
            Matrix4F newChildMatrix = Matrix4F.Multiply(childMatrix, parentMatrix);

            Vec3F newTranslation = child.Translation;

            parentMatrix.Transform(ref newTranslation);

            Vec3F newRotation = new Vec3F();

            newChildMatrix.GetEulerAngles(out newRotation.X, out newRotation.Y, out newRotation.Z);
            child.Rotation = newRotation;

            Vec3F newScale = newChildMatrix.GetScale();

            child.Scale = newScale;

            // We can compose together all of the separate transformations now.
            Matrix4F newTransform = CalcTransform(
                newTranslation,
                newRotation,
                newScale,
                child.ScalePivot,
                child.ScalePivotTranslation,
                child.RotatePivot,
                child.RotatePivotTranslation);

            // However, the composed matrix may not equal newChildMatrix due to rotating
            //  or scaling around a pivot. In the general case, it may be impossible to
            //  decompose newChildMatrix into all of these separate components. For example,
            //  a sheer transformation cannot be reproduced by a single rotation and scale.
            //  But for common cases, only the translation is out-of-sync now, so apply a fix.
            Vec3F    desiredTranslation = newChildMatrix.Translation;
            Vec3F    currentTranslation = newTransform.Translation;
            Vec3F    fixupTranslation   = desiredTranslation - currentTranslation;
            Matrix4F fixupTransform     = new Matrix4F(fixupTranslation);

            newTransform.Mul(newTransform, fixupTransform);

            // Save the fix and the final transform.
            child.Translation = newTranslation + fixupTranslation;
            child.Transform   = newTransform;
        }
Exemplo n.º 8
0
        protected override Matrix4F GetManipulatorMatrix()
        {
            ITransformable node = GetManipulatorNode(TransformationTypes.Pivot);

            if (node == null)
            {
                return(null);
            }

            Path <DomNode> path         = new Path <DomNode>(node.Cast <DomNode>().GetPath());
            Matrix4F       localToWorld = TransformUtils.CalcPathTransform(path, path.Count - 1);

            // Offset by pivot
            Matrix4F Pv = new Matrix4F();

            Pv.Set(node.Pivot);
            localToWorld.Mul(Pv, localToWorld);
            localToWorld.OrthoNormalize(localToWorld);
            return(new Matrix4F(localToWorld.Translation));
        }
Exemplo n.º 9
0
        protected override Matrix4F GetManipulatorMatrix()
        {
            ITransformable node = GetManipulatorNode(TransformationTypes.Translation);

            if (node == null)
            {
                return(null);
            }

            ISnapSettings  snapSettings = (ISnapSettings)DesignView;
            Path <DomNode> path         = new Path <DomNode>(node.Cast <DomNode>().GetPath());
            Matrix4F       localToWorld = TransformUtils.CalcPathTransform(path, path.Count - 1);

            Matrix4F toworld = new Matrix4F();

            if (snapSettings.ManipulateLocalAxis)
            {
                toworld.Set(localToWorld);
                toworld.Normalize(toworld);
            }
            else
            {
                toworld.Translation = localToWorld.Translation;
            }

            //  DavidJ --   note -- this "pivot" behaviour was inherited from another manipulator
            //                  but appears to be broken! Check coordinate space of value returned from CalcSnapFromOffset
            // Vec3F offset = TransformUtils.CalcSnapFromOffset(node, snapSettings.SnapFrom);
            //
            // // Offset by pivot
            // Matrix4F P = new Matrix4F();
            // P.Translation = offset;
            // toworld.Mul(toworld,P);

            return(toworld);
        }
Exemplo n.º 10
0
        public static Vec3F CalcSnapFromOffset(ITransformable node, SnapFromMode snapFrom)
        {
            // AABB in local space.
            AABB box = node.As<IBoundable>().LocalBoundingBox;

            Vec3F offsetLocal = box.Center;
            switch (snapFrom)
            {
                case SnapFromMode.Pivot:
                    offsetLocal = node.Pivot;
                    break;
                case SnapFromMode.Origin:
                    offsetLocal = box.Center;
                    break;
                case SnapFromMode.TopCenter:
                    offsetLocal.Y = box.Max.Y;
                    break;
                case SnapFromMode.BottomCenter:
                    offsetLocal.Y = box.Min.Y;
                    break;
                case SnapFromMode.FrontCenter:
                    offsetLocal.Z = box.Max.Z;
                    break;
                case SnapFromMode.BackCenter:
                    offsetLocal.Z = box.Min.Z;
                    break;
                case SnapFromMode.LeftCenter:
                    offsetLocal.X = box.Min.X;
                    break;
                case SnapFromMode.RightCenter:
                    offsetLocal.X = box.Max.X;
                    break;
                default:
                    throw new ArgumentOutOfRangeException("Invalid snap-from node");
            }

            Path<DomNode> path = new Path<DomNode>(node.Cast<DomNode>().GetPath());
            Matrix4F toWorld = TransformUtils.CalcPathTransform(path, path.Count - 1);

            Vec3F offset;
            toWorld.TransformVector(offsetLocal, out offset); //local-to-world
            return offset; //world
        }
Exemplo n.º 11
0
        /// <summary>
        /// Adjusts child transform, making it the concatenation with its parent's transform.
        /// Is recursive, looking for parents that also implement IRenderableNode.</summary>
        /// <param name="parent">Parent node</param>
        /// <param name="child">Child node</param>
        public static void RemoveChild(ITransformable parent, ITransformable child)
        {
            Path<DomNode> path = new Path<DomNode>(parent.Cast<DomNode>().GetPath());
            Matrix4F parentMatrix = TransformUtils.CalcPathTransform(path, path.Count - 1);

            Matrix4F childMatrix = child.Transform;
            Matrix4F newChildMatrix = Matrix4F.Multiply(childMatrix, parentMatrix);

            Vec3F newTranslation = child.Translation;
            parentMatrix.Transform(ref newTranslation);

            Vec3F newRotation = new Vec3F();
            newChildMatrix.GetEulerAngles(out newRotation.X, out newRotation.Y, out newRotation.Z);
            child.Rotation = newRotation;

            Vec3F newScale = newChildMatrix.GetScale();
            child.Scale = newScale;

            // We can compose together all of the separate transformations now.
            Matrix4F newTransform = CalcTransform(
                newTranslation,
                newRotation,
                newScale,
                child.ScalePivot,
                child.ScalePivotTranslation,
                child.RotatePivot,
                child.RotatePivotTranslation);

            // However, the composed matrix may not equal newChildMatrix due to rotating
            //  or scaling around a pivot. In the general case, it may be impossible to
            //  decompose newChildMatrix into all of these separate components. For example,
            //  a sheer transformation cannot be reproduced by a single rotation and scale.
            //  But for common cases, only the translation is out-of-sync now, so apply a fix.
            Vec3F desiredTranslation = newChildMatrix.Translation;
            Vec3F currentTranslation = newTransform.Translation;
            Vec3F fixupTranslation = desiredTranslation - currentTranslation;
            Matrix4F fixupTransform = new Matrix4F(fixupTranslation);
            newTransform.Mul(newTransform, fixupTransform);

            // Save the fix and the final transform.
            child.Translation = newTranslation + fixupTranslation;
            child.Transform = newTransform;
        }
Exemplo n.º 12
0
        /// <summary>
        /// Adjusts child transform, making it relative to new parent node's transform.
        /// Is recursive, looking for parents that also implement IRenderableNode.</summary>
        /// <param name="parent">Parent node</param>
        /// <param name="child">Child node</param>
        public static void AddChild(ITransformable parent, ITransformable child)
        {
            Path <DomNode> path          = new Path <DomNode>(parent.Cast <DomNode>().GetPath());
            Matrix4F       parentToWorld = TransformUtils.CalcPathTransform(path, path.Count - 1);

            // We want 'child' to appear in the same place in the world after adding to 'parent'.
            // local-point * original-local-to-world = world-point
            // new-local-point * new-local-to-parent * parent-to-world = world-point
            // ==> new-local-to-parent * parent-to-world = original-local-to-world
            // (multiply both sides by inverse of parent-to-world; call it world-to-parent)
            // ==> new-local-to-parent = original-local-to-world * world-to-parent
            Matrix4F worldToParent = new Matrix4F();

            worldToParent.Invert(parentToWorld);
            Matrix4F originalLocalToWorld = child.Transform;
            Matrix4F newLocalToParent     = Matrix4F.Multiply(originalLocalToWorld, worldToParent);

            // The translation component of newLocalToParent consists of pivot translation
            //  as well as the child.Translation. So, start with the original child.Translation
            //  and transform it into our new space.
            Vec3F newTranslation = child.Translation;

            worldToParent.Transform(ref newTranslation);

            // There's only one way of getting rotation info, so get it straight from matrix.
            Vec3F newRotation = new Vec3F();

            newLocalToParent.GetEulerAngles(out newRotation.X, out newRotation.Y, out newRotation.Z);
            child.Rotation = newRotation;

            // Likewise with scale.
            Vec3F newScale = newLocalToParent.GetScale();

            child.Scale = newScale;

            // We can compose together all of the separate transformations now.
            Matrix4F newTransform = CalcTransform(
                newTranslation,
                newRotation,
                newScale,
                child.ScalePivot,
                child.ScalePivotTranslation,
                child.RotatePivot,
                child.RotatePivotTranslation);

            // However, the composed matrix may not equal newLocalToParent due to rotating
            //  or scaling around a pivot. In the general case, it may be impossible to
            //  decompose newLocalToParent into all of these separate components. For example,
            //  a sheer transformation cannot be reproduced by a single rotation and scale.
            //  But for common cases, only the translation is out-of-sync now, so apply a fix.
            Vec3F    desiredTranslation = newLocalToParent.Translation;
            Vec3F    currentTranslation = newTransform.Translation;
            Vec3F    fixupTranslation   = desiredTranslation - currentTranslation;
            Matrix4F fixupTransform     = new Matrix4F(fixupTranslation);

            newTransform.Mul(newTransform, fixupTransform);

            // Save the fix and the final transform. Storing the fix in RotatePivotTranslation
            //  is done elsewhere, as well.
            child.Translation = newTranslation + fixupTranslation;
            child.Transform   = newTransform;
        }
Exemplo n.º 13
0
        /// <summary>
        /// For an object 'node' that is being manipulated, this function returns
        /// the offset (in world space) from the object's origin to to the point that is being
        /// "snapped from". This calculation is determined by the snapping modes.</summary>
        /// <param name="node">The object that is being snapped-to some other object</param>
        /// <param name="snapFromMode">The "snap from" mode, as an enum</param>
        /// <param name="axisType">Axis system type (y or z is up)</param>
        /// <param name="pivot">Pass in either node.RotatePivot or node.ScalePivot</param>
        /// <returns>Offset from this object's origin to the "snap from" point, in world space</returns>
        /// <remarks>Must be kept in sync with SnapFromModes property.</remarks>
        public static Vec3F CalcSnapFromOffset(
            ITransformable node,
            SnapFromMode snapFromMode,
            AxisSystemType axisType, Vec3F pivot)
        {
            switch (snapFromMode)
            {
                case SnapFromMode.Pivot:
                    {
                        Vec3F offset;
                        Path<DomNode> path = new Path<DomNode>(node.Cast<DomNode>().Ancestry);
                        Matrix4F parentToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2);
                        node.Transform.TransformVector(pivot, out offset); //local-to-parent
                        parentToWorld.TransformVector(offset, out offset); //parent-to-world
                        return offset; //world
                    }
                case SnapFromMode.Origin:
                    return new Vec3F(0, 0, 0);
                case SnapFromMode.BottomCenter:
                    {
                        Box box = node.BoundingBox;
                        Vec3F btmWorld;
                        if (axisType == AxisSystemType.YIsUp)
                        {
                            btmWorld = new Vec3F(
                                (box.Min.X + box.Max.X) * 0.5f,
                                box.Min.Y,
                                (box.Min.Z + box.Max.Z) * 0.5f);
                        }
                        else
                        {
                            btmWorld = new Vec3F(
                                (box.Min.X + box.Max.X) * 0.5f,
                                (box.Min.Y + box.Max.Y) * 0.5f,
                                box.Min.Z);
                        }
                        Vec3F origin = node.Transform.Translation;
                        Vec3F offset = btmWorld - origin; //local space offset

                        Path<DomNode> path = new Path<DomNode>(node.Cast<DomNode>().GetPath());
                        Matrix4F parentToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2);
                        parentToWorld.TransformVector(offset, out offset);

                        return offset;
                    }
                default:
                    throw new ArgumentException("Invalid snap-from node");
            }
        }
 private bool CanManipulate(ITransformable node)
 {
     bool result = node != null
           && (node.TransformationType & TransformationTypes.Pivot) != 0
           && node.Cast<IVisible>().Visible
           && node.Cast<ILockable>().IsLocked == false;
     return result;
 }
Exemplo n.º 15
0
        private void RenderProperties(IEnumerable <object> objects, bool renderCaption, bool renderBound, bool renderPivot)
        {
            bool renderAny = renderCaption || renderBound || renderPivot;

            if (renderAny == false)
            {
                return;
            }

            Util3D.RenderFlag = BasicRendererFlags.WireFrame;
            Matrix4F vp = Camera.ViewMatrix * Camera.ProjectionMatrix;

            foreach (object obj in objects)
            {
                IBoundable bnode = obj.As <IBoundable>();
                if (bnode == null || bnode.BoundingBox.IsEmpty || obj.Is <IGameObjectFolder>())
                {
                    continue;
                }

                INameable      nnode = obj.As <INameable>();
                ITransformable trans = obj.As <ITransformable>();

                if (renderBound)
                {
                    Util3D.DrawAABB(bnode.BoundingBox);
                }
                if (renderCaption && nnode != null)
                {
                    Vec3F topCenter = bnode.BoundingBox.Center;
                    topCenter.Y = bnode.BoundingBox.Max.Y;
                    Point pt = Project(vp, topCenter);
                    GameEngine.DrawText2D(nnode.Name, Util3D.CaptionFont, pt.X, pt.Y, Color.White);
                }
            }

            if (renderPivot)
            {
                Util3D.RenderFlag = BasicRendererFlags.WireFrame
                                    | BasicRendererFlags.DisableDepthTest;

                // create few temp matrics to
                Matrix4F toWorld  = new Matrix4F();
                Matrix4F PV       = new Matrix4F();
                Matrix4F sc       = new Matrix4F();
                Matrix4F bl       = new Matrix4F();
                Matrix4F recXform = new Matrix4F();
                foreach (object obj in objects)
                {
                    ITransformable trans = obj.As <ITransformable>();
                    IBoundable     bnode = obj.As <IBoundable>();
                    if (trans == null || bnode == null || bnode.BoundingBox.IsEmpty || obj.Is <IGameObjectFolder>())
                    {
                        continue;
                    }

                    Path <DomNode> path = new Path <DomNode>(trans.Cast <DomNode>().GetPath());
                    toWorld.Set(Vec3F.ZeroVector);
                    TransformUtils.CalcPathTransform(toWorld, path, path.Count - 1);

                    // Offset by pivot
                    PV.Set(trans.Pivot);
                    toWorld.Mul(PV, toWorld);
                    Vec3F pos = toWorld.Translation;

                    float s;
                    Util.CalcAxisLengths(Camera, pos, out s);
                    s /= 12.0f;
                    sc.Scale(s);
                    Util.CreateBillboard(bl, pos, Camera.WorldEye, Camera.Up, Camera.LookAt);

                    Matrix4F.Multiply(sc, bl, recXform);

                    Util3D.DrawPivot(recXform, Color.Yellow);
                }
            }
        }
Exemplo n.º 16
0
 private bool CanManipulate(ITransformable node, FilterDelegate filter)
 {
     bool result = node != null
         && node.Cast<IVisible>().Visible
         && node.Cast<ILockable>().IsLocked == false
         && filter(node);
     return result;
 }
Exemplo n.º 17
0
        private void RenderProperties(GUILayer.SimpleRenderingContext context, IEnumerable <object> objects, bool renderCaption, bool renderBound, bool renderPivot)
        {
            if (renderCaption || renderBound)
            {
                Util3D.SetRenderFlag(context, BasicRendererFlags.WireFrame);
                Matrix4F vp = Camera.ViewMatrix * Camera.ProjectionMatrix;
                foreach (object obj in objects)
                {
                    IBoundable bnode = obj.As <IBoundable>();
                    if (bnode == null || bnode.BoundingBox.IsEmpty || obj.Is <IGameObjectFolder>())
                    {
                        continue;
                    }

                    INameable      nnode = obj.As <INameable>();
                    ITransformable trans = obj.As <ITransformable>();

                    if (renderBound)
                    {
                        Util3D.DrawAABB(context, bnode.BoundingBox);
                    }
                    if (renderCaption && nnode != null)
                    {
                        Vec3F topCenter = bnode.BoundingBox.Center;
                        topCenter.Y = bnode.BoundingBox.Max.Y;
                        Point pt = Project(vp, topCenter);
                        GameEngine.DrawText2D(nnode.Name, Util3D.CaptionFont, pt.X, pt.Y, Color.White);
                    }
                }
            }

            if (renderPivot)
            {
                Util3D.SetRenderFlag(context, BasicRendererFlags.WireFrame | BasicRendererFlags.DisableDepthTest);

                // create few temp matrics to
                Matrix4F toWorld  = new Matrix4F();
                Matrix4F PV       = new Matrix4F();
                Matrix4F sc       = new Matrix4F();
                Matrix4F bl       = new Matrix4F();
                Matrix4F recXform = new Matrix4F();
                foreach (object obj in objects)
                {
                    ITransformable trans = obj.As <ITransformable>();
                    IBoundable     bnode = obj.As <IBoundable>();
                    if (trans == null || bnode == null || bnode.BoundingBox.IsEmpty || obj.Is <IGameObjectFolder>())
                    {
                        continue;
                    }

                    Path <DomNode> path = new Path <DomNode>(trans.Cast <DomNode>().GetPath());
                    toWorld.Set(Vec3F.ZeroVector);
                    TransformUtils.CalcPathTransform(toWorld, path, path.Count - 1);

                    // Offset by pivot
                    PV.Set(trans.Pivot);
                    toWorld.Mul(PV, toWorld);
                    Vec3F pos = toWorld.Translation;

                    const float pivotDiameter = 16; // in pixels
                    float       s             = Util.CalcAxisScale(Camera, pos, pivotDiameter, Height);
                    sc.Scale(s);
                    Util.CreateBillboard(bl, pos, Camera.WorldEye, Camera.Up, Camera.LookAt);
                    recXform = sc * bl;
                    Util3D.DrawPivot(context, recXform, Color.Yellow);
                }
            }
        }
Exemplo n.º 18
0
        /// <summary>
        /// Adjusts child transform, making it relative to new parent node's transform.
        /// Is recursive, looking for parents that also implement IRenderableNode.</summary>
        /// <param name="parent">Parent node</param>
        /// <param name="child">Child node</param>
        public static void AddChild(ITransformable parent, ITransformable child)
        {
            Path<DomNode> path = new Path<DomNode>(parent.Cast<DomNode>().GetPath());
            Matrix4F parentToWorld = TransformUtils.CalcPathTransform(path, path.Count - 1);

            // We want 'child' to appear in the same place in the world after adding to 'parent'.
            // local-point * original-local-to-world = world-point
            // new-local-point * new-local-to-parent * parent-to-world = world-point
            // ==> new-local-to-parent * parent-to-world = original-local-to-world
            // (multiply both sides by inverse of parent-to-world; call it world-to-parent)
            // ==> new-local-to-parent = original-local-to-world * world-to-parent
            Matrix4F worldToParent = new Matrix4F();
            worldToParent.Invert(parentToWorld);
            Matrix4F originalLocalToWorld = child.Transform;
            Matrix4F newLocalToParent = Matrix4F.Multiply(originalLocalToWorld, worldToParent);

            // The translation component of newLocalToParent consists of pivot translation
            //  as well as the child.Translation. So, start with the original child.Translation
            //  and transform it into our new space.
            Vec3F newTranslation = child.Translation;
            worldToParent.Transform(ref newTranslation);

            // There's only one way of getting rotation info, so get it straight from matrix.
            Vec3F newRotation = new Vec3F();
            newLocalToParent.GetEulerAngles(out newRotation.X, out newRotation.Y, out newRotation.Z);
            child.Rotation = newRotation;

            // Likewise with scale.
            Vec3F newScale = newLocalToParent.GetScale();
            child.Scale = newScale;

            // We can compose together all of the separate transformations now.
            Matrix4F newTransform = CalcTransform(
                newTranslation,
                newRotation,
                newScale,
                child.ScalePivot,
                child.ScalePivotTranslation,
                child.RotatePivot,
                child.RotatePivotTranslation);

            // However, the composed matrix may not equal newLocalToParent due to rotating
            //  or scaling around a pivot. In the general case, it may be impossible to
            //  decompose newLocalToParent into all of these separate components. For example,
            //  a sheer transformation cannot be reproduced by a single rotation and scale.
            //  But for common cases, only the translation is out-of-sync now, so apply a fix.
            Vec3F desiredTranslation = newLocalToParent.Translation;
            Vec3F currentTranslation = newTransform.Translation;
            Vec3F fixupTranslation = desiredTranslation - currentTranslation;
            Matrix4F fixupTransform = new Matrix4F(fixupTranslation);
            newTransform.Mul(newTransform, fixupTransform);

            // Save the fix and the final transform. Storing the fix in RotatePivotTranslation
            //  is done elsewhere, as well.
            child.Translation = newTranslation + fixupTranslation;
            child.Transform = newTransform;
        }