#region File Description //----------------------------------------------------------------------------- // A basic renderable model. // // Author: Ronen Ness. // Since: 2017. //----------------------------------------------------------------------------- #endregion using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System.Collections.Generic; namespace MonoGameSceneGraph { /// /// A basic renderable model. /// Note: this object is more of an example of how to create a renderable entity, you will probably /// need to implement something more sophisticated on your own. /// public class ModelEntity : IEntity { /// /// The model to render. /// public Model Model; /// /// Projection matrix to use with model. /// public Matrix Projection; /// /// View matrix to use with model. /// public Matrix View; /// /// Enable / disable default lighting on model. /// public bool EnableLighting = true; /// /// Create the model entity. /// /// Model to draw. public ModelEntity(Model model) { // visible by default Visible = true; // store model Model = model; // Create default Projection matrix (viewport) float aspectRatio = 1f; float fieldOfView = Microsoft.Xna.Framework.MathHelper.PiOver4; float nearClipPlane = 1; float farClipPlane = 200; Projection = Matrix.CreatePerspectiveFieldOfView( fieldOfView, aspectRatio, nearClipPlane, farClipPlane); // Create default View matrix (camera) var cameraPosition = new Vector3(0, 20, 0); var cameraLookAtVector = Vector3.Zero; var cameraUpVector = Vector3.UnitZ; View = Matrix.CreateLookAt(cameraPosition, cameraLookAtVector, cameraUpVector); } /// /// Draw this model. /// /// Parent node that's currently drawing this entity. /// Local transformations from the direct parent node. /// World transformations to apply on this entity (this is what you should use to draw this entity). public void Draw(Node parent, Matrix localTransformations, Matrix worldTransformations) { // iterate model meshes foreach (var mesh in Model.Meshes) { // iterate effect in mesh foreach (BasicEffect effect in mesh.Effects) { // enable lights if (EnableLighting) { // set default lightings effect.EnableDefaultLighting(); // This makes lighting look more realistic on // round surfaces, but at a slight performance cost: effect.PreferPerPixelLighting = true; } // set world matrix effect.World = worldTransformations; // set view matrix effect.View = View; // set projection matrix effect.Projection = Projection; } // draw current mesh mesh.Draw(); } } /// /// Return if the entity is currently visible. /// /// If the entity is visible or not. public bool Visible { get; set; } /// /// Get the bounding box of this entity. /// /// Parent node that's currently drawing this entity. /// Local transformations from the direct parent node. /// World transformations to apply on this entity (this is what you should use to draw this entity). /// Bounding box of the entity. public BoundingBox GetBoundingBox(Node parent, Matrix localTransformations, Matrix worldTransformations) { // initialize minimum and maximum corners of the bounding box to max and min values Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue); // iterate over mesh parts foreach (ModelMesh mesh in Model.Meshes) { foreach (ModelMeshPart meshPart in mesh.MeshParts) { // vertex buffer parameters int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride; int vertexBufferSize = meshPart.NumVertices * vertexStride; // get vertex data as float float[] vertexData = new float[vertexBufferSize / sizeof(float)]; meshPart.VertexBuffer.GetData(vertexData); // iterate through vertices (possibly) growing bounding box for (int i = 0; i < vertexBufferSize / sizeof(float); i += vertexStride / sizeof(float)) { // get curr position and update min / max Vector3 currPosition = new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]); currPosition = Vector3.Transform(currPosition, worldTransformations); min = Vector3.Min(min, currPosition); max = Vector3.Max(max, currPosition); } } } // return bounding box return new BoundingBox(min, max); } } }