public ModelNode(
     ModelManager.ModelData model)
     : base()
 {
     this.model       = model;
     this.LocalBounds = model.BoundingSphere;
 }
Пример #2
0
        /// <summary>
        /// Tests if a sphere intersects DFMesh geometry.
        /// </summary>
        /// <param name="position">Position in world space.</param>
        /// <param name="radius">Radius of sphere.</param>
        /// <param name="modelTransform">World space transform.</param>
        /// <param name="model">ModelManager.ModelData.</param>
        /// <returns>CollisionResult.</returns>
        public CollisionResult SphereIntersectDFMesh(Vector3 position,
                                                     float radius,
                                                     Matrix modelTransform,
                                                     ModelManager.ModelData model)
        {
            // Transform sphere position back to object space
            Matrix inverseTransform = Matrix.Invert(modelTransform);

            position = Vector3.Transform(position, inverseTransform);

            // Test each submesh
            CollisionResult result = CollisionResult.Nothing;
            Vector3         normal, vertex1, vertex2, vertex3;
            int             subMeshIndex = 0;

            foreach (var subMesh in model.DFMesh.SubMeshes)
            {
                // Test each plane of this submesh
                int planeIndex = 0;
                foreach (var plane in subMesh.Planes)
                {
                    // Get plane normal (all points in plane have same normal)
                    normal.X = plane.Points[0].NX;
                    normal.Y = -plane.Points[0].NY;
                    normal.Z = -plane.Points[0].NZ;

                    // Get shared point (vertex1)
                    vertex1.X = plane.Points[0].X;
                    vertex1.Y = -plane.Points[0].Y;
                    vertex1.Z = -plane.Points[0].Z;

                    // Walk through triangle fan
                    for (int p = 0; p < plane.Points.Length - 2; p++)
                    {
                        // Get second point (vertex2)
                        vertex2.X = plane.Points[p + 1].X;
                        vertex2.Y = -plane.Points[p + 1].Y;
                        vertex2.Z = -plane.Points[p + 1].Z;

                        // Get third point (vertex3)
                        vertex3.X = plane.Points[p + 2].X;
                        vertex3.Y = -plane.Points[p + 2].Y;
                        vertex3.Z = -plane.Points[p + 2].Z;

                        // Test intersection.
                        // Changing winding order to suit algorithm.
                        SetCollisionTriangle(vertex1, vertex3, vertex2, normal);
                        TestSphereCollision(ref position, radius, ref result);
                    }

                    // Increment planeIndex
                    planeIndex++;
                }

                // Increment subMeshIndex
                subMeshIndex++;
            }

            return(result);
        }
Пример #3
0
        /// <summary>
        /// Tests pointer against model intersections to
        ///  resolve actual model intersection at face level.
        /// </summary>
        private void PointerModelIntersectionsTest()
        {
            // Nothing to do if no intersections
            if (pointerNodeIntersections.Count == 0)
            {
                return;
            }

            // Sort intersections by distance
            pointerNodeIntersections.Sort();

            // Iterate intersections
            float?intersection        = null;
            float?closestIntersection = null;

            Intersection.NodeIntersection closestModelIntersection = null;
            foreach (var ni in pointerNodeIntersections)
            {
                // Ensure node is a ModelNode
                if (false == (ni.Node is ModelNode))
                {
                    continue;
                }

                // Get model
                ModelNode node = (ModelNode)ni.Node;
                ModelManager.ModelData model = node.Model;

                // Test model
                bool insideBoundingSphere;
                int  subMeshResult, planeResult;
                intersection = Intersection.RayIntersectsDFMesh(
                    pointerRay,
                    node.Matrix,
                    ref model,
                    out insideBoundingSphere,
                    out subMeshResult,
                    out planeResult);

                if (intersection != null)
                {
                    if (closestIntersection == null || intersection < closestIntersection)
                    {
                        closestIntersection      = intersection;
                        closestModelIntersection = ni;
                    }
                }
            }

            // Store closest intersection
            if (closestModelIntersection != null)
            {
                pointerOverModelNode = (ModelNode)closestModelIntersection.Node;
            }
            else
            {
                pointerOverModelNode = null;
            }
        }
Пример #4
0
        /// <summary>
        /// Highlights an action chain.
        /// </summary>
        /// <param name="start">Start node.</param>
        private void HighlightActionChain(ModelNode start)
        {
            // Link back to start node if there is a parent
            while (start.Action.PreviousNode != null)
            {
                start = (ModelNode)start.Action.PreviousNode;
            }

            // Link through chain from start
            int       lineCount = 0;
            ModelNode node      = start;

            while (node != null)
            {
                // Highlight model
                ModelManager.ModelData model = node.Model;
                DrawNativeMesh(actionHighlightColor, ref model, node.Matrix);

                // Get line start
                actionLines[lineCount].Color      = Color.Red;
                actionLines[lineCount++].Position = node.TransformedBounds.Center;

                // Get next node
                node = (ModelNode)node.Action.NextNode;

                // Store end point of line if there is another node in chain
                if (node != null)
                {
                    actionLines[lineCount].Color      = Color.Red;
                    actionLines[lineCount++].Position = node.TransformedBounds.Center;
                }
                else
                {
                    lineCount--;
                }
            }

            // Draw action connection lines
            if (lineCount >= 2)
            {
                // Set render states
                graphicsDevice.DepthStencilState = DepthStencilState.None;

                // Set view and projection matrices
                lineEffect.View       = camera.View;
                lineEffect.Projection = camera.Projection;
                lineEffect.World      = Matrix.Identity;

                // Draw lines
                lineEffect.CurrentTechnique.Passes[0].Apply();
                graphicsDevice.DrawUserPrimitives(PrimitiveType.LineList, actionLines, 0, lineCount / 2);
            }
        }
Пример #5
0
 /// <summary>
 /// Highlights model under pointer.
 /// </summary>
 private void HighlightModelUnderPointer()
 {
     if (pointerOverModelNode != null)
     {
         if (pointerOverModelNode.Action.Enabled)
         {
             // Handle action-enabled nodes
             HighlightActionChain(pointerOverModelNode);
         }
         else
         {
             // Just highlight model
             ModelManager.ModelData model = pointerOverModelNode.Model;
             DrawNativeMesh(modelHighlightColor, ref model, pointerOverModelNode.Matrix);
         }
     }
 }
Пример #6
0
        /// <summary>
        /// Draw native mesh as wireframe lines.
        /// </summary>
        /// <param name="color">Line color.</param>
        /// <param name="model">ModelManager.Model.</param>
        /// <param name="matrix">Matrix.</param>
        protected void DrawNativeMesh(Color color, ref ModelManager.ModelData model, Matrix matrix)
        {
            // Scale up just a little to make outline visually pop
            matrix = Matrix.CreateScale(1.015f) * matrix;

            // Set view and projection matrices
            lineEffect.View       = camera.View;
            lineEffect.Projection = camera.Projection;
            lineEffect.World      = matrix;

            // Draw faces
            foreach (var subMesh in model.DFMesh.SubMeshes)
            {
                foreach (var plane in subMesh.Planes)
                {
                    DrawNativeFace(color, plane.Points, matrix);
                }
            }
        }
        /// <summary>
        /// Loads a Daggerfall model and any textures required.
        ///  Will use whatever climate is currently set in texture manager.
        /// </summary>
        /// <param name="id">ID of model.</param>
        /// <param name="model">ModelManager.ModelData.</param>
        /// <returns>True if successful.</returns>
        private bool LoadDaggerfallModel(uint id, out ModelManager.ModelData model)
        {
            try
            {
                // Load model and textures
                model = modelManager.GetModelData(id);
                for (int i = 0; i < model.SubMeshes.Length; i++)
                {
                    // Set flags
                    TextureManager.TextureCreateFlags flags =
                        TextureManager.TextureCreateFlags.ApplyClimate |
                        TextureManager.TextureCreateFlags.MipMaps |
                        TextureManager.TextureCreateFlags.PowerOfTwo;

                    // Set HiDef flags
                    if (Core.GraphicsProfile == GraphicsProfile.HiDef)
                    {
                        flags |= TextureManager.TextureCreateFlags.ExtendedAlpha;
                    }

                    // Load texture
                    model.SubMeshes[i].TextureKey = textureManager.LoadTexture(
                        model.DFMesh.SubMeshes[i].TextureArchive,
                        model.DFMesh.SubMeshes[i].TextureRecord,
                        flags);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                model = null;
                return(false);
            }

            return(true);
        }
 // Constructors
 public ModelNode()
     : base()
 {
     this.model = null;
 }
Пример #9
0
        /// <summary>
        /// Tests if ray intersects DFMesh geometry. Performs bounding sphere
        ///  test first. Use this method for model picking from an
        ///  unprojected ray.
        /// </summary>
        /// <param name="ray">Ray in world space.</param>
        /// <param name="modelTransform">World space transform.</param>
        /// <param name="model">ModelManager.Model.</param>
        /// <param name="insideBoundingSphere">True if ray intersects model bounding sphere.</param>
        /// <param name="subMeshResult">Index of DFSubMesh intersected by ray, or -1 on miss.</param>
        /// <param name="planeResult">Index of DFPlane interested by ray, or -1 on miss.</param>
        /// <returns>Distance to intersection, or NULL if miss.</returns>
        public static float?RayIntersectsDFMesh(Ray ray,
                                                Matrix modelTransform,
                                                ref ModelManager.ModelData model,
                                                out bool insideBoundingSphere,
                                                out int subMeshResult,
                                                out int planeResult)
        {
            // Reset results
            insideBoundingSphere = false;
            subMeshResult        = -1;
            planeResult          = -1;

            // Transform ray back to object space
            Matrix inverseTransform = Matrix.Invert(modelTransform);

            ray.Position  = Vector3.Transform(ray.Position, inverseTransform);
            ray.Direction = Vector3.TransformNormal(ray.Direction, inverseTransform);

            // Test against bounding sphere
            if (ray.Intersects(model.BoundingSphere) == null)
            {
                // No intersection possible
                return(null);
            }
            else
            {
                // Ray is inside model bounding sphere
                insideBoundingSphere = true;
            }

            // Test each submesh
            float   dot;
            float?  intersection = null;
            float?  closestIntersection = null;
            Vector3 normal, vertex1, vertex2, vertex3;
            int     subMeshIndex = 0;

            foreach (var subMesh in model.DFMesh.SubMeshes)
            {
                // Test each plane of this submesh
                int planeIndex = 0;
                foreach (var plane in subMesh.Planes)
                {
                    // Get plane normal (all points in plane have same normal)
                    normal.X = plane.Points[0].NX;
                    normal.Y = -plane.Points[0].NY;
                    normal.Z = -plane.Points[0].NZ;

                    // Cull planes facing away from ray
                    dot = Vector3.Dot(normal, ray.Direction);
                    if (dot > 0f)
                    {
                        planeIndex++;
                        continue;
                    }

                    // Get shared point (vertex1)
                    vertex1.X = plane.Points[0].X;
                    vertex1.Y = -plane.Points[0].Y;
                    vertex1.Z = -plane.Points[0].Z;

                    // Walk through triangle fan
                    for (int p = 0; p < plane.Points.Length - 2; p++)
                    {
                        // Get second point (vertex2)
                        vertex2.X = plane.Points[p + 1].X;
                        vertex2.Y = -plane.Points[p + 1].Y;
                        vertex2.Z = -plane.Points[p + 1].Z;

                        // Get third point (vertex3)
                        vertex3.X = plane.Points[p + 2].X;
                        vertex3.Y = -plane.Points[p + 2].Y;
                        vertex3.Z = -plane.Points[p + 2].Z;

                        // Test intersection
                        RayIntersectsTriangle(ref ray, ref vertex1, ref vertex2, ref vertex3, out intersection);
                        if (intersection != null)
                        {
                            // Test for closest intersection so far
                            if (closestIntersection == null || intersection < closestIntersection)
                            {
                                // Update closest intersection
                                closestIntersection = intersection;
                                subMeshResult       = subMeshIndex;
                                planeResult         = planeIndex;
                            }
                        }
                    }

                    // Increment planeIndex
                    planeIndex++;
                }

                // Increment subMeshIndex
                subMeshIndex++;
            }

            return(closestIntersection);
        }