OSDN Git Service

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