ModelEntity.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // A basic renderable model.
  4. //
  5. // Author: Ronen Ness.
  6. // Since: 2017.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. using Microsoft.Xna.Framework;
  10. using Microsoft.Xna.Framework.Graphics;
  11. using System.Collections.Generic;
  12. namespace MonoGameSceneGraph
  13. {
  14. /// <summary>
  15. /// A basic renderable model.
  16. /// Note: this object is more of an example of how to create a renderable entity, you will probably
  17. /// need to implement something more sophisticated on your own.
  18. /// </summary>
  19. public class ModelEntity : IEntity
  20. {
  21. /// <summary>
  22. /// The model to render.
  23. /// </summary>
  24. public Model Model;
  25. /// <summary>
  26. /// Projection matrix to use with model.
  27. /// </summary>
  28. public Matrix Projection;
  29. /// <summary>
  30. /// View matrix to use with model.
  31. /// </summary>
  32. public Matrix View;
  33. /// <summary>
  34. /// Enable / disable default lighting on model.
  35. /// </summary>
  36. public bool EnableLighting = true;
  37. /// <summary>
  38. /// Create the model entity.
  39. /// </summary>
  40. /// <param name="model">Model to draw.</param>
  41. public ModelEntity(Model model)
  42. {
  43. // store model
  44. Model = model;
  45. // Create default Projection matrix (viewport)
  46. float aspectRatio = 1f;
  47. float fieldOfView = Microsoft.Xna.Framework.MathHelper.PiOver4;
  48. float nearClipPlane = 1;
  49. float farClipPlane = 200;
  50. Projection = Matrix.CreatePerspectiveFieldOfView(
  51. fieldOfView, aspectRatio, nearClipPlane, farClipPlane);
  52. // Create default View matrix (camera)
  53. var cameraPosition = new Vector3(0, 20, 0);
  54. var cameraLookAtVector = Vector3.Zero;
  55. var cameraUpVector = Vector3.UnitZ;
  56. View = Matrix.CreateLookAt(cameraPosition, cameraLookAtVector, cameraUpVector);
  57. }
  58. /// <summary>
  59. /// Draw this model.
  60. /// </summary>
  61. /// <param name="parent">Parent node that's currently drawing this entity.</param>
  62. /// <param name="localTransformations">Local transformations from the direct parent node.</param>
  63. /// <param name="worldTransformations">World transformations to apply on this entity (this is what you should use to draw this entity).</param>
  64. public void Draw(Node parent, Matrix localTransformations, Matrix worldTransformations)
  65. {
  66. // A model is composed of "Meshes" which are
  67. // parts of the model which can be positioned
  68. // independently, which can use different textures,
  69. // and which can have different rendering states
  70. // such as lighting applied.
  71. foreach (var mesh in Model.Meshes)
  72. {
  73. // "Effect" refers to a shader. Each mesh may
  74. // have multiple shaders applied to it for more
  75. // advanced visuals.
  76. foreach (BasicEffect effect in mesh.Effects)
  77. {
  78. // enable lights
  79. if (EnableLighting)
  80. {
  81. // set default lightings
  82. effect.EnableDefaultLighting();
  83. // This makes lighting look more realistic on
  84. // round surfaces, but at a slight performance cost:
  85. effect.PreferPerPixelLighting = true;
  86. }
  87. // set world matrix
  88. effect.World = worldTransformations;
  89. // set view matrix
  90. effect.View = View;
  91. // set projection matrix
  92. effect.Projection = Projection;
  93. }
  94. // Now that we've assigned our properties on the effects we can
  95. // draw the entire mesh
  96. mesh.Draw();
  97. }
  98. }
  99. /// <summary>
  100. /// Get the bounding box of this entity.
  101. /// </summary>
  102. /// <param name="parent">Parent node that's currently drawing this entity.</param>
  103. /// <param name="localTransformations">Local transformations from the direct parent node.</param>
  104. /// <param name="worldTransformations">World transformations to apply on this entity (this is what you should use to draw this entity).</param>
  105. /// <returns>Bounding box of the entity.</returns>
  106. public BoundingBox GetBoundingBox(Node parent, Matrix localTransformations, Matrix worldTransformations)
  107. {
  108. // apply model transformations on world transform (note: don't support animations)
  109. worldTransformations = worldTransformations * Model.Bones[0].Transform;
  110. // initialize minimum and maximum corners of the bounding box to max and min values
  111. Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
  112. Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
  113. // iterate over mesh parts
  114. foreach (ModelMesh mesh in Model.Meshes)
  115. {
  116. foreach (ModelMeshPart meshPart in mesh.MeshParts)
  117. {
  118. // vertex buffer parameters
  119. int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride;
  120. int vertexBufferSize = meshPart.NumVertices * vertexStride;
  121. // get vertex data as float
  122. float[] vertexData = new float[vertexBufferSize / sizeof(float)];
  123. meshPart.VertexBuffer.GetData<float>(vertexData);
  124. // iterate through vertices (possibly) growing bounding box
  125. for (int i = 0; i < vertexBufferSize / sizeof(float); i += vertexStride / sizeof(float))
  126. {
  127. // get curr position and update min / max
  128. Vector3 currPosition = new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]);
  129. min = Vector3.Min(min, currPosition);
  130. max = Vector3.Max(max, currPosition);
  131. }
  132. }
  133. }
  134. // transform min and max position so it will be in world space
  135. min = Vector3.Transform(min, worldTransformations);
  136. max = Vector3.Transform(max, worldTransformations);
  137. // return the bounding box
  138. return new BoundingBox(min, max);
  139. }
  140. }
  141. }