Пример #1
0
        private MagmaModelContent ProcessFileWithSeparateCollisionMesh(
            NodeContent input,
            ContentProcessorContext context,
            string collisionMeshFilename
            )
        {
#if DEBUG
            context.Logger.LogImportantMessage("  processing file using a separate collision mesh");
            context.Logger.LogImportantMessage("  using '" + collisionMeshFilename + "' as collision mesh");
#endif

            NodeContent collisionMeshContent = collisionMeshContent = context.BuildAndLoadAsset <NodeContent, NodeContent>(
                new ExternalReference <NodeContent>(collisionMeshFilename), null);

            // calculate bounds because changes are based on the bounding box
            AlignedBox3 boundingBox = CalculateAlignedBox3(input, context, true);

            TransformMeshes(new NodeContent[] { input, collisionMeshContent }, context, ref boundingBox);

            // let the base class process the model
            MagmaModelContent modelContent = BaseProcessing(input, context);

            // add bounding volumes to the model
            modelContent.VolumeCollection = CalculateCollisionVolumes(new NodeContent[] { collisionMeshContent }, context);

            return(modelContent);
        }
Пример #2
0
        private void TransformMeshes(
            NodeContent[] inputNodes,
            ContentProcessorContext context,
            ref AlignedBox3 boundingBox
            )
        {
            if (!TransformMeshesAllowed)
            {
                return;
            }

            foreach (NodeContent input in inputNodes)
            {
                RemoveTextureReferences(input, context);
                CalculateTangentFrames(input, context);
            }

            // first center the models (I think they are actually already centered...
            Vector3 diff = Vector3.Zero - (boundingBox.Min + ((boundingBox.Max - boundingBox.Min) / 2.0f));

            foreach (NodeContent input in inputNodes)
            {
                MoveModel(input, context, diff);
            }
            boundingBox.Max += diff;
            boundingBox.Min += diff;

            // now that the models are centered scale them
            float scaleFactor = boundingBox.Max.X;

            if (boundingBox.Max.Y > scaleFactor)
            {
                scaleFactor = boundingBox.Max.Y;
            }
            if (boundingBox.Max.Z > scaleFactor)
            {
                scaleFactor = boundingBox.Max.Z;
            }
            scaleFactor = 1.0f / scaleFactor;
            foreach (NodeContent input in inputNodes)
            {
                ScaleModel(input, context, scaleFactor);
            }
            boundingBox.Max *= scaleFactor;
            boundingBox.Min *= scaleFactor;

            // now let the subclass decide on how to modify the position
            Vector3 scaledOrigDiff = diff * scaleFactor;
            Vector3 diffCorrector  = CalculateDiff(ref scaledOrigDiff, ref boundingBox);

            foreach (NodeContent input in inputNodes)
            {
                MoveModel(input, context, diffCorrector);
            }
            boundingBox.Min += diffCorrector;
            boundingBox.Max += diffCorrector;
        }
Пример #3
0
        public override void OnAttached(
            AbstractEntity entity
            )
        {
            bool needAllContacts = entity.HasBool("need_all_contacts") && entity.GetBool("need_all_contacts");

            string modelName = entity.GetString(CommonNames.Mesh);

            VolumeCollection[] collisionVolumes = Game.Instance.ContentManager.Load <MagmaModel>(modelName).VolumeCollection;
            if (collisionVolumes == null)
            {
                throw new System.Exception(string.Format("model {0} has no collision volumes!", modelName));
            }

            if (entity.HasString("bv_type"))
            {
                string bv_type = entity.GetString("bv_type");
                if (bv_type == "cylinder")
                {
                    object[] bvCylinders = new object[collisionVolumes.Length];
                    for (int i = 0; i < collisionVolumes.Length; ++i)
                    {
                        bvCylinders[i] = collisionVolumes[i].GetVolume(VolumeType.Cylinder3);
                    }
                    Game.Instance.Simulation.CollisionManager.AddCylinderCollisionEntity(entity as Entity, this, bvCylinders, needAllContacts);
                }
                else if (bv_type == "alignedbox3tree")
                {
                    object[] bvTrees = new object[collisionVolumes.Length];
                    for (int i = 0; i < collisionVolumes.Length; ++i)
                    {
                        bvTrees[i] = collisionVolumes[i].GetVolume(VolumeType.AlignedBox3Tree);
                    }
                    Game.Instance.Simulation.CollisionManager.AddAlignedBox3TreeCollisionEntity(entity as Entity, this, bvTrees, needAllContacts);
                }
                else if (bv_type == "sphere")
                {
                    object[] bvSpheres = new object[collisionVolumes.Length];
                    for (int i = 0; i < collisionVolumes.Length; ++i)
                    {
                        bvSpheres[i] = collisionVolumes[i].GetVolume(VolumeType.Sphere3);
                    }
                    Game.Instance.Simulation.CollisionManager.AddSphereCollisionEntity(entity as Entity, this, bvSpheres, needAllContacts);
                }
                else if (bv_type == "alignedbox3")
                {
                    AlignedBox3[] bvBoxes = new AlignedBox3[collisionVolumes.Length];
                    for (int i = 0; i < collisionVolumes.Length; ++i)
                    {
                        bvBoxes[i] = (AlignedBox3)collisionVolumes[i].GetVolume(VolumeType.AlignedBox3);
                    }
                    throw new System.Exception("bounding boxes not yet supported!");
                }
            }
        }
Пример #4
0
        private void CalculateAlignedBox3(
            NodeContent input,
            ContentProcessorContext context,
            bool ignoreCollisionNodes,
            ref AlignedBox3 box
            )
        {
            if (ignoreCollisionNodes && IsCollisionNode(input))
            {
                return;
            }

            MeshContent mesh = input as MeshContent;

            if (mesh != null)
            {
                foreach (Vector3 pos in mesh.Positions)
                {
                    Vector3 transformed = Vector3.Transform(pos, mesh.AbsoluteTransform);
                    if (transformed.X < box.Min.X)
                    {
                        box.Min.X = transformed.X;
                    }
                    if (transformed.Y < box.Min.Y)
                    {
                        box.Min.Y = transformed.Y;
                    }
                    if (transformed.Z < box.Min.Z)
                    {
                        box.Min.Z = transformed.Z;
                    }
                    if (transformed.X > box.Max.X)
                    {
                        box.Max.X = transformed.X;
                    }
                    if (transformed.Y > box.Max.Y)
                    {
                        box.Max.Y = transformed.Y;
                    }
                    if (transformed.Z > box.Max.Z)
                    {
                        box.Max.Z = transformed.Z;
                    }
                }
            }

            // Go through all children
            foreach (NodeContent child in input.Children)
            {
                CalculateAlignedBox3(child, context, ignoreCollisionNodes, ref box);
            }
        }
Пример #5
0
        private AlignedBox3 CalculateAlignedBox3(
            NodeContent input,
            ContentProcessorContext context,
            bool ignoreCollisionNodes
            )
        {
            AlignedBox3 alignedBox = new AlignedBox3();

            alignedBox.Min = new Vector3(Single.MaxValue, Single.MaxValue, Single.MaxValue);
            alignedBox.Max = new Vector3(Single.MinValue, Single.MinValue, Single.MinValue);
            CalculateAlignedBox3(input, context, ignoreCollisionNodes, ref alignedBox);
            return(alignedBox);
        }
Пример #6
0
        private Sphere3 CalculateSphere3(
            NodeContent input,
            ContentProcessorContext context,
            bool ignoreCollisionNodes
            )
        {
            // calculate center
            AlignedBox3 bb     = CalculateAlignedBox3(input, context, ignoreCollisionNodes);
            Vector3     center = (bb.Min + bb.Max) / 2;

            float maxDist = bb.Max.X - bb.Min.X;

            maxDist = System.Math.Max(maxDist, bb.Max.Y - bb.Min.Y);
            maxDist = System.Math.Max(maxDist, bb.Max.Z - bb.Min.Z);

            float radius = maxDist / 2;

            return(new Sphere3(center, radius));
        }
Пример #7
0
        private MagmaModelContent ProcessLegacyFile(
            NodeContent input,
            ContentProcessorContext context
            )
        {
            context.Logger.LogWarning(null, input.Identity, "processing legacy file using the graphical mesh as collision mesh");

            // calculate bounds because changes are based on the bounding box
            AlignedBox3 bb = CalculateAlignedBox3(input, context, false);

            TransformMeshes(new NodeContent[] { input }, context, ref bb);

            // let the base class process the model
            MagmaModelContent modelContent = BaseProcessing(input, context);

            // add bounding volumes to the model
            modelContent.VolumeCollection = CalculateCollisionVolumes(new NodeContent[] { input }, context);

            return(modelContent);
        }
Пример #8
0
        // calculates y-axis aligned bounding cylinder
        private Cylinder3 CalculateCylinder3(
            NodeContent input,
            ContentProcessorContext context,
            bool ignoreCollisionNodes
            )
        {
            // calculate center
            AlignedBox3 bb     = CalculateAlignedBox3(input, context, ignoreCollisionNodes);
            Vector3     center = (bb.Min + bb.Max) / 2;

            float top    = bb.Max.Y;
            float bottom = bb.Min.Y;

            // calculate radius
            // a valid cylinder here is an extruded circle (not an oval) therefore extents in
            // x- and z-direction should be equal.
            float radius = bb.Max.X - center.X;

            return(new Cylinder3(new Vector3(center.X, top, center.Z),
                                 new Vector3(center.X, bottom, center.Z),
                                 radius));
        }
Пример #9
0
 protected override Vector3 CalculateDiff(ref Vector3 origDiff, ref AlignedBox3 bb)
 {
     return(new Vector3(0, 0.0f - bb.Min.Y, 0));
 }
Пример #10
0
        private bool GetIntersectionPoint(
            ref Ray3 ray,
            AlignedBox3TreeNode node,
            Vector3[] positions,
            out float t
            )
        {
            AlignedBox3 boundingBox = node.BoundingBox;

            if (!Intersection.IntersectRay3AlignedBox3(ref ray, ref boundingBox))
            {
                t = 0.0f;
                return(false);
            }

            if (node.HasChildren)
            {
                float t1, t2;
                bool  isect1 = GetIntersectionPoint(ref ray, node.Left, positions, out t1);
                bool  isect2 = GetIntersectionPoint(ref ray, node.Right, positions, out t2);

                if (isect1 && isect2)
                {
                    t = t1 < t2 ? t1 : t2;
                    return(true);
                }
                else if (isect1)
                {
                    t = t1;
                    return(true);
                }
                else if (isect2)
                {
                    t = t2;
                    return(true);
                }
                else
                {
                    t = 0.0f;
                    return(false);
                }
            }
            else
            {
                bool  intersection = false;
                float smallestT    = float.MaxValue;
                for (int i = 0; i < node.NumTriangles; ++i)
                {
                    float     currentT = 0.0f;
                    Vector3   isectPt  = Vector3.Zero;
                    Triangle3 tri      = node.GetTriangle(positions, i);
                    if (Intersection.IntersectRay3Triangle3(ref ray, ref tri, out currentT, out isectPt))
                    {
                        if (currentT < smallestT)
                        {
                            smallestT = currentT;
                        }

                        if (!intersection)
                        {
                            intersection = true;
                        }
                    }
                }

                if (intersection)
                {
                    t = smallestT;
                    return(true);
                }
                else
                {
                    t = 0.0f;
                    return(false);
                }
            }
        }
Пример #11
0
        //-----------------------------------------------------------------------------------------------------------
        public static bool IntersectRay3AlignedBox3(
            ref Ray3 ray,
            ref AlignedBox3 box
            )
        {
            float   t_near = float.MinValue;
            float   t_far = float.MaxValue;
            float   t0, t1;
            Vector3 min = box.Min;
            Vector3 max = box.Max;

            // check for ray parallel to planes
            if (System.Math.Abs(ray.Direction.X) < 1e-06)
            {
                if (ray.Origin.X < min.X || ray.Origin.X > max.X)
                {
                    return(false);
                }
            }
            if (System.Math.Abs(ray.Direction.Y) < 1e-06)
            {
                if (ray.Origin.Y < min.Y || ray.Origin.Y > max.Y)
                {
                    return(false);
                }
            }
            if (System.Math.Abs(ray.Direction.Z) < 1e-06)
            {
                if (ray.Origin.Z < min.Z || ray.Origin.Z > max.Z)
                {
                    return(false);
                }
            }

            // ray not parallel to planes, so find parameters of intersections for the Y/Z-Plane
            float divx = 1 / ray.Direction.X;

            t0 = (min.X - ray.Origin.X) * divx;
            t1 = (max.X - ray.Origin.X) * divx;
            if (t0 > t1)
            {
                float tmp = t0;
                t0 = t1;
                t1 = tmp;
            }
            if (t0 > t_near)
            {
                t_near = t0;
            }
            if (t1 < t_far)
            {
                t_far = t1;
            }
            if (t_near > t_far)
            {
                return(false);
            }
            if (t_far < 0)
            {
                return(false);
            }

            // for the X/Z-Plane
            float divy = 1 / ray.Direction.Y;

            t0 = (min.Y - ray.Origin.Y) * divy;
            t1 = (max.Y - ray.Origin.Y) * divy;
            if (t0 > t1)
            {
                float tmp = t0;
                t0 = t1;
                t1 = tmp;
            }
            if (t0 > t_near)
            {
                t_near = t0;
            }
            if (t1 < t_far)
            {
                t_far = t1;
            }
            if (t_near > t_far)
            {
                return(false);
            }
            if (t_far < 0)
            {
                return(false);
            }

            // for the X/Y-Plane
            float divz = 1 / ray.Direction.Z;

            t0 = (min.Z - ray.Origin.Z) * divz;
            t1 = (max.Z - ray.Origin.Z) * divz;
            if (t0 > t1)
            {
                float tmp = t0;
                t0 = t1;
                t1 = tmp;
            }
            if (t0 > t_near)
            {
                t_near = t0;
            }
            if (t1 < t_far)
            {
                t_far = t1;
            }
            if (t_near > t_far)
            {
                return(false);
            }
            if (t_far < 0)
            {
                return(false);
            }

            // if we reach this point we've got an intersection
            return(true);
        }
Пример #12
0
 protected override Vector3 CalculateDiff(ref Vector3 origDiff, ref AlignedBox3 bb)
 {
     return(-origDiff);
 }
Пример #13
0
 protected virtual Vector3 CalculateDiff(ref Vector3 origDiff, ref AlignedBox3 bb)
 {
     return(Vector3.Zero);
 }
Пример #14
0
        private MagmaModelContent ProcessContainerGroup(
            NodeContent input,
            ContentProcessorContext context
            )
        {
#if DEBUG
            context.Logger.LogImportantMessage("  processing one group contained in a model container");
#endif

            // find the child to process!
            NodeContent currentGroupNode = GetChild(input, CurrentGroup);
            Debug.Assert(currentGroupNode != null);
            if (currentGroupNode == null)
            {
                throw new ArgumentException(string.Format("unable to find referenced child ({0})!", CurrentGroup));
            }

            input.Children.Clear();
            input.Children.Add(currentGroupNode);

            // copy the identity
            //currentGroupNode.Identity = input.Identity;

            // calculate bounds because changes are based on the bounding box
            AlignedBox3 bb = CalculateAlignedBox3(input, context, true);

            // transform the graphical mesh and the collision meshes in one step!
            TransformMeshes(new NodeContent[] { input }, context, ref bb);

            // extract all collision meshes
            List <NodeContent> collisionNodes = new List <NodeContent>();
            foreach (NodeContent child in currentGroupNode.Children)
            {
                if (IsCollisionNode(child))
                {
                    collisionNodes.Add(child);
                }
            }
            foreach (NodeContent collisionMesh in collisionNodes)
            {
#if DEBUG
                context.Logger.LogImportantMessage("  using {0} as a collision fragment", collisionMesh.Name);
#endif
                currentGroupNode.Children.Remove(collisionMesh);
            }

            // let the base class process the graphical model
            MagmaModelContent modelContent = BaseProcessing(input, context);

            // now we process our collision meshes...
            // TODO: take all collision meshes not only the first one!
            VolumeCollection collection = new VolumeCollection();

            if (collisionNodes.Count == 0)
            {
                context.Logger.LogWarning(null, input.Identity, "unable to find a collision mesh in group {0}", CurrentGroup);
                modelContent.VolumeCollection = CalculateCollisionVolumes(new NodeContent[] { input }, context);
            }
            else
            {
                NodeContent[] collisionNodesArray = new NodeContent[collisionNodes.Count];
                for (int i = 0; i < collisionNodes.Count; ++i)
                {
                    collisionNodesArray[i] = collisionNodes[i];
                }
                modelContent.VolumeCollection = CalculateCollisionVolumes(collisionNodesArray, context);
            }

            return(modelContent);
        }