#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);
}
}
}