/Radegast/GUI/Rendering/Frustum.cs

https://bitbucket.org/FlyMan/radegast · C# · 232 lines · 156 code · 29 blank · 47 comment · 21 complexity · 6399bb5db076f482432624c5f0e96b9f MD5 · raw file

  1. #region --- MIT License ---
  2. /* Licensed under the MIT/X11 license.
  3. * Copyright (c) 2011 mjt
  4. * This notice may not be removed from any source distribution.
  5. * See license.txt for licensing details.
  6. */
  7. #endregion
  8. /*
  9. * tutoriaali:
  10. * http://www.crownandcutlass.com/features/technicaldetails/frustum.html
  11. *
  12. */
  13. using System;
  14. using OpenMetaverse;
  15. //using OpenTK.Graphics.OpenGL;
  16. //using OpenTK;
  17. namespace Radegast.Rendering
  18. {
  19. public class Frustum
  20. {
  21. //static Matrix4 ProjMatrix, ModelMatrix;
  22. static float[] ClipMatrix = new float[16];
  23. static float[,] frustum = new float[6, 4];
  24. const int RIGHT = 0, LEFT = 1, BOTTOM = 2, TOP = 3, BACK = 4, FRONT = 5;
  25. static void NormalizePlane(float[,] frustum, int side)
  26. {
  27. float magnitude = (float)Math.Sqrt((frustum[side, 0] * frustum[side, 0]) + (frustum[side, 1] * frustum[side, 1])
  28. + (frustum[side, 2] * frustum[side, 2]));
  29. frustum[side, 0] /= magnitude;
  30. frustum[side, 1] /= magnitude;
  31. frustum[side, 2] /= magnitude;
  32. frustum[side, 3] /= magnitude;
  33. }
  34. public static void CalculateFrustum(OpenTK.Matrix4 ProjMatrix, OpenTK.Matrix4 ModelMatrix)
  35. {
  36. ClipMatrix[0] = (ModelMatrix.M11 * ProjMatrix.M11) + (ModelMatrix.M12 * ProjMatrix.M21) + (ModelMatrix.M13 * ProjMatrix.M31) + (ModelMatrix.M14 * ProjMatrix.M41);
  37. ClipMatrix[1] = (ModelMatrix.M11 * ProjMatrix.M12) + (ModelMatrix.M12 * ProjMatrix.M22) + (ModelMatrix.M13 * ProjMatrix.M32) + (ModelMatrix.M14 * ProjMatrix.M42);
  38. ClipMatrix[2] = (ModelMatrix.M11 * ProjMatrix.M13) + (ModelMatrix.M12 * ProjMatrix.M23) + (ModelMatrix.M13 * ProjMatrix.M33) + (ModelMatrix.M14 * ProjMatrix.M43);
  39. ClipMatrix[3] = (ModelMatrix.M11 * ProjMatrix.M14) + (ModelMatrix.M12 * ProjMatrix.M24) + (ModelMatrix.M13 * ProjMatrix.M34) + (ModelMatrix.M14 * ProjMatrix.M44);
  40. ClipMatrix[4] = (ModelMatrix.M21 * ProjMatrix.M11) + (ModelMatrix.M22 * ProjMatrix.M21) + (ModelMatrix.M23 * ProjMatrix.M31) + (ModelMatrix.M24 * ProjMatrix.M41);
  41. ClipMatrix[5] = (ModelMatrix.M21 * ProjMatrix.M12) + (ModelMatrix.M22 * ProjMatrix.M22) + (ModelMatrix.M23 * ProjMatrix.M32) + (ModelMatrix.M24 * ProjMatrix.M42);
  42. ClipMatrix[6] = (ModelMatrix.M21 * ProjMatrix.M13) + (ModelMatrix.M22 * ProjMatrix.M23) + (ModelMatrix.M23 * ProjMatrix.M33) + (ModelMatrix.M24 * ProjMatrix.M43);
  43. ClipMatrix[7] = (ModelMatrix.M21 * ProjMatrix.M14) + (ModelMatrix.M22 * ProjMatrix.M24) + (ModelMatrix.M23 * ProjMatrix.M34) + (ModelMatrix.M24 * ProjMatrix.M44);
  44. ClipMatrix[8] = (ModelMatrix.M31 * ProjMatrix.M11) + (ModelMatrix.M32 * ProjMatrix.M21) + (ModelMatrix.M33 * ProjMatrix.M31) + (ModelMatrix.M34 * ProjMatrix.M41);
  45. ClipMatrix[9] = (ModelMatrix.M31 * ProjMatrix.M12) + (ModelMatrix.M32 * ProjMatrix.M22) + (ModelMatrix.M33 * ProjMatrix.M32) + (ModelMatrix.M34 * ProjMatrix.M42);
  46. ClipMatrix[10] = (ModelMatrix.M31 * ProjMatrix.M13) + (ModelMatrix.M32 * ProjMatrix.M23) + (ModelMatrix.M33 * ProjMatrix.M33) + (ModelMatrix.M34 * ProjMatrix.M43);
  47. ClipMatrix[11] = (ModelMatrix.M31 * ProjMatrix.M14) + (ModelMatrix.M32 * ProjMatrix.M24) + (ModelMatrix.M33 * ProjMatrix.M34) + (ModelMatrix.M34 * ProjMatrix.M44);
  48. ClipMatrix[12] = (ModelMatrix.M41 * ProjMatrix.M11) + (ModelMatrix.M42 * ProjMatrix.M21) + (ModelMatrix.M43 * ProjMatrix.M31) + (ModelMatrix.M44 * ProjMatrix.M41);
  49. ClipMatrix[13] = (ModelMatrix.M41 * ProjMatrix.M12) + (ModelMatrix.M42 * ProjMatrix.M22) + (ModelMatrix.M43 * ProjMatrix.M32) + (ModelMatrix.M44 * ProjMatrix.M42);
  50. ClipMatrix[14] = (ModelMatrix.M41 * ProjMatrix.M13) + (ModelMatrix.M42 * ProjMatrix.M23) + (ModelMatrix.M43 * ProjMatrix.M33) + (ModelMatrix.M44 * ProjMatrix.M43);
  51. ClipMatrix[15] = (ModelMatrix.M41 * ProjMatrix.M14) + (ModelMatrix.M42 * ProjMatrix.M24) + (ModelMatrix.M43 * ProjMatrix.M34) + (ModelMatrix.M44 * ProjMatrix.M44);
  52. // laske frustumin tasot ja normalisoi ne
  53. frustum[RIGHT, 0] = ClipMatrix[3] - ClipMatrix[0];
  54. frustum[RIGHT, 1] = ClipMatrix[7] - ClipMatrix[4];
  55. frustum[RIGHT, 2] = ClipMatrix[11] - ClipMatrix[8];
  56. frustum[RIGHT, 3] = ClipMatrix[15] - ClipMatrix[12];
  57. NormalizePlane(frustum, RIGHT);
  58. frustum[LEFT, 0] = ClipMatrix[3] + ClipMatrix[0];
  59. frustum[LEFT, 1] = ClipMatrix[7] + ClipMatrix[4];
  60. frustum[LEFT, 2] = ClipMatrix[11] + ClipMatrix[8];
  61. frustum[LEFT, 3] = ClipMatrix[15] + ClipMatrix[12];
  62. NormalizePlane(frustum, LEFT);
  63. frustum[BOTTOM, 0] = ClipMatrix[3] + ClipMatrix[1];
  64. frustum[BOTTOM, 1] = ClipMatrix[7] + ClipMatrix[5];
  65. frustum[BOTTOM, 2] = ClipMatrix[11] + ClipMatrix[9];
  66. frustum[BOTTOM, 3] = ClipMatrix[15] + ClipMatrix[13];
  67. NormalizePlane(frustum, BOTTOM);
  68. frustum[TOP, 0] = ClipMatrix[3] - ClipMatrix[1];
  69. frustum[TOP, 1] = ClipMatrix[7] - ClipMatrix[5];
  70. frustum[TOP, 2] = ClipMatrix[11] - ClipMatrix[9];
  71. frustum[TOP, 3] = ClipMatrix[15] - ClipMatrix[13];
  72. NormalizePlane(frustum, TOP);
  73. frustum[BACK, 0] = ClipMatrix[3] - ClipMatrix[2];
  74. frustum[BACK, 1] = ClipMatrix[7] - ClipMatrix[6];
  75. frustum[BACK, 2] = ClipMatrix[11] - ClipMatrix[10];
  76. frustum[BACK, 3] = ClipMatrix[15] - ClipMatrix[14];
  77. NormalizePlane(frustum, BACK);
  78. frustum[FRONT, 0] = ClipMatrix[3] + ClipMatrix[2];
  79. frustum[FRONT, 1] = ClipMatrix[7] + ClipMatrix[6];
  80. frustum[FRONT, 2] = ClipMatrix[11] + ClipMatrix[10];
  81. frustum[FRONT, 3] = ClipMatrix[15] + ClipMatrix[14];
  82. NormalizePlane(frustum, FRONT);
  83. }
  84. /// <summary>
  85. /// tasojen normaalit osoittaa sisäänpäin joten jos testattava vertex on
  86. /// kaikkien tasojen "edessä", se on ruudulla ja rendataan
  87. /// </summary>
  88. /// <param name="x"></param>
  89. /// <param name="y"></param>
  90. /// <param name="z"></param>
  91. /// <returns></returns>
  92. public static bool PointInFrustum(float x, float y, float z)
  93. {
  94. // tasoyhtälö: A*x + B*y + C*z + D = 0
  95. // ABC on normaalin X, Y ja Z
  96. // D on tason etäisyys origosta
  97. // =0 vertex on tasolla
  98. // <0 tason takana
  99. // >0 tason edessä
  100. for (int a = 0; a < 6; a++)
  101. {
  102. // jos vertex jonkun tason takana, niin palauta false (ei rendata)
  103. if (((frustum[a, 0] * x) + (frustum[a, 1] * y) + (frustum[a, 2] * z) + frustum[a, 3]) <= 0)
  104. {
  105. return false;
  106. }
  107. }
  108. // ruudulla
  109. return true;
  110. }
  111. /// <summary>
  112. /// palauttaa etäisyyden kameraan jos pallo frustumissa, muuten 0.
  113. /// </summary>
  114. /// <param name="x"></param>
  115. /// <param name="y"></param>
  116. /// <param name="z"></param>
  117. /// <param name="radius"></param>
  118. /// <returns></returns>
  119. public static float SphereInFrustum(float x, float y, float z, float radius)
  120. {
  121. float d = 0;
  122. for (int p = 0; p < 6; p++)
  123. {
  124. d = frustum[p, 0] * x + frustum[p, 1] * y + frustum[p, 2] * z + frustum[p, 3];
  125. if (d <= -radius) // jos pallo ei ole ruudulla
  126. {
  127. return 0;
  128. }
  129. }
  130. // kaikkien tasojen edessä eli näkyvissä.
  131. return d + radius; // palauta matka kameraan
  132. }
  133. public static bool ObjectInFrustum(Vector3 position, BoundingVolume bound)
  134. {
  135. return ObjectInFrustum(position.X, position.Y, position.Z, bound);
  136. }
  137. public static bool ObjectInFrustum(float x, float y, float z, BoundingVolume bound)
  138. {
  139. if (bound == null) return true;
  140. if (SphereInFrustum(x, y, z, bound.ScaledR) == 0) return false;
  141. return true;
  142. }
  143. }
  144. public class BoundingVolume
  145. {
  146. Vector3 Min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
  147. Vector3 Max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
  148. float R = 0f;
  149. public Vector3 ScaledMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
  150. public Vector3 ScaledMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
  151. public float ScaledR = 0f;
  152. public void CalcScaled(Vector3 scale)
  153. {
  154. ScaledMin = Min * scale;
  155. ScaledMax = Max * scale;
  156. Vector3 dist = ScaledMax - ScaledMin;
  157. ScaledR = dist.Length();
  158. }
  159. public void CreateBoundingVolume(OpenMetaverse.Rendering.Face mesh, Vector3 scale)
  160. {
  161. for (int q = 0; q < mesh.Vertices.Count; q++)
  162. {
  163. if (mesh.Vertices[q].Position.X < Min.X) Min.X = mesh.Vertices[q].Position.X;
  164. if (mesh.Vertices[q].Position.Y < Min.Y) Min.Y = mesh.Vertices[q].Position.Y;
  165. if (mesh.Vertices[q].Position.Z < Min.Z) Min.Z = mesh.Vertices[q].Position.Z;
  166. if (mesh.Vertices[q].Position.X > Max.X) Max.X = mesh.Vertices[q].Position.X;
  167. if (mesh.Vertices[q].Position.Y > Max.Y) Max.Y = mesh.Vertices[q].Position.Y;
  168. if (mesh.Vertices[q].Position.Z > Max.Z) Max.Z = mesh.Vertices[q].Position.Z;
  169. }
  170. Vector3 dist = Max - Min;
  171. R = dist.Length();
  172. mesh.Center = Min + (dist / 2);
  173. CalcScaled(scale);
  174. }
  175. public void FromScale(Vector3 scale)
  176. {
  177. ScaledMax = scale / 2f;
  178. ScaledMin = -ScaledMax;
  179. Vector3 dist = ScaledMax - ScaledMin;
  180. ScaledR = dist.Length();
  181. }
  182. public void AddVolume(BoundingVolume vol, Vector3 scale)
  183. {
  184. if (vol.Min.X < this.Min.X) this.Min.X = vol.Min.X;
  185. if (vol.Min.Y < this.Min.Y) this.Min.Y = vol.Min.Y;
  186. if (vol.Min.Z < this.Min.Z) this.Min.Z = vol.Min.Z;
  187. if (vol.Max.X > this.Max.X) this.Max.X = vol.Max.X;
  188. if (vol.Max.Y > this.Max.Y) this.Max.Y = vol.Max.Y;
  189. if (vol.Max.Z > this.Max.Z) this.Max.Z = vol.Max.Z;
  190. Vector3 dist = Max - Min;
  191. R = dist.Length();
  192. CalcScaled(scale);
  193. }
  194. //public void CreateBoundingVolume(Model mesh, Vector3 min, Vector3 max)
  195. //{
  196. // Min = min;
  197. // Max = max;
  198. // Vector3 dist = Max - Min;
  199. // R = dist.Length;
  200. // mesh.ObjCenter = Min + (dist / 2); // objektin keskikohta
  201. //}
  202. }
  203. }