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); }
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; }
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!"); } } }
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); } }
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); }
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)); }
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); }
// 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)); }
protected override Vector3 CalculateDiff(ref Vector3 origDiff, ref AlignedBox3 bb) { return(new Vector3(0, 0.0f - bb.Min.Y, 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); } } }
//----------------------------------------------------------------------------------------------------------- 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); }
protected override Vector3 CalculateDiff(ref Vector3 origDiff, ref AlignedBox3 bb) { return(-origDiff); }
protected virtual Vector3 CalculateDiff(ref Vector3 origDiff, ref AlignedBox3 bb) { return(Vector3.Zero); }
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); }