1 | #include "Matrix4x4.h"
|
---|
2 | #include "Vector3.h"
|
---|
3 | #include <float.h>
|
---|
4 |
|
---|
5 |
|
---|
6 |
|
---|
7 | namespace CHCDemoEngine
|
---|
8 | {
|
---|
9 |
|
---|
10 | // Given min a vector to minimize and a candidate vector, replace
|
---|
11 | // elements of min whose corresponding elements in Candidate are
|
---|
12 | // smaller. This function is used for finding objects' bounds,
|
---|
13 | // among other things.
|
---|
14 | void Minimize(Vector3 &min, const Vector3 &Candidate)
|
---|
15 | {
|
---|
16 | if (Candidate.x < min.x)
|
---|
17 | min.x = Candidate.x;
|
---|
18 | if (Candidate.y < min.y)
|
---|
19 | min.y = Candidate.y;
|
---|
20 | if (Candidate.z < min.z)
|
---|
21 | min.z = Candidate.z;
|
---|
22 | }
|
---|
23 |
|
---|
24 | // Given min a vector to minimize and a candidate vector, replace
|
---|
25 | // elements of min whose corresponding elements in Candidate are
|
---|
26 | // larger. This function is used for finding objects' bounds,
|
---|
27 | // among other things.
|
---|
28 | void Maximize(Vector3 &max, const Vector3 &Candidate)
|
---|
29 | {
|
---|
30 | if (Candidate.x > max.x)
|
---|
31 | max.x = Candidate.x;
|
---|
32 | if (Candidate.y > max.y)
|
---|
33 | max.y = Candidate.y;
|
---|
34 | if (Candidate.z > max.z)
|
---|
35 | max.z = Candidate.z;
|
---|
36 | }
|
---|
37 |
|
---|
38 | // Project the vector onto the YZ, XZ, or XY plane depending on which.
|
---|
39 | // which Coordinate plane to project onto
|
---|
40 | // 0 YZ
|
---|
41 | // 1 XZ
|
---|
42 | // 2 XY
|
---|
43 | // This function is used by the polygon intersection code.
|
---|
44 |
|
---|
45 | void Vector3::ExtractVerts(float *px, float *py, int which) const
|
---|
46 | {
|
---|
47 | switch (which) {
|
---|
48 | case 0:
|
---|
49 | *px = y;
|
---|
50 | *py = z;
|
---|
51 | break;
|
---|
52 | case 1:
|
---|
53 | *px = x;
|
---|
54 | *py = z;
|
---|
55 | break;
|
---|
56 | case 2:
|
---|
57 | *px = x;
|
---|
58 | *py = y;
|
---|
59 | break;
|
---|
60 | }
|
---|
61 | }
|
---|
62 |
|
---|
63 | // returns the axis, where the vector has the largest value
|
---|
64 | int
|
---|
65 | Vector3::DrivingAxis(void) const
|
---|
66 | {
|
---|
67 | int axis = 0;
|
---|
68 | float val = fabs(x);
|
---|
69 |
|
---|
70 | if (fabs(y) > val) {
|
---|
71 | val = fabs(y);
|
---|
72 | axis = 1;
|
---|
73 | }
|
---|
74 |
|
---|
75 | if (fabs(z) > val)
|
---|
76 | axis = 2;
|
---|
77 |
|
---|
78 | return axis;
|
---|
79 | }
|
---|
80 |
|
---|
81 | // returns the axis, where the vector has the smallest value
|
---|
82 | int
|
---|
83 | Vector3::TinyAxis(void) const
|
---|
84 | {
|
---|
85 | int axis = 0;
|
---|
86 | float val = fabs(x);
|
---|
87 |
|
---|
88 | if (fabs(y) < val) {
|
---|
89 | val = fabs(y);
|
---|
90 | axis = 1;
|
---|
91 | }
|
---|
92 |
|
---|
93 | if (fabs(z) < val)
|
---|
94 | axis = 2;
|
---|
95 |
|
---|
96 | return axis;
|
---|
97 | }
|
---|
98 |
|
---|
99 |
|
---|
100 | // Construct a view vector ViewN, and the vector ViewU perpendicular
|
---|
101 | // to ViewN and lying in the plane given by ViewNxUpl
|
---|
102 | // the last vector of ortogonal system is ViewV, that is
|
---|
103 | // perpendicular to both ViewN and ViewU.
|
---|
104 | // |ViewN| = |ViewU| = |ViewV| = 1
|
---|
105 | // The ViewN vector pierces the center of the synthesized image
|
---|
106 | // ViewU vector goes from the center image rightwards
|
---|
107 | // ViewV vector goes from the center image upwards
|
---|
108 | void
|
---|
109 | ViewVectors(const Vector3 &DirAt, const Vector3 &Viewer,
|
---|
110 | const Vector3 &UpL, Vector3 &ViewV, Vector3 &ViewU,
|
---|
111 | Vector3 &ViewN)
|
---|
112 | {
|
---|
113 | Vector3 U, V, N;
|
---|
114 | Vector3 Up = Normalize(UpL);
|
---|
115 |
|
---|
116 | N = -Normalize(DirAt);
|
---|
117 |
|
---|
118 | V = Normalize(Up - DirAt);
|
---|
119 | V -= N * DotProd(V, N);
|
---|
120 | V = Normalize(V);
|
---|
121 | U = CrossProd(V, N);
|
---|
122 |
|
---|
123 | ViewU = U; // rightwards
|
---|
124 | ViewV = V; // upwards
|
---|
125 | ViewN = -N; // forwards
|
---|
126 | #ifdef GTP_DEBUG
|
---|
127 | const float eps = 1e-3f;
|
---|
128 | if (fabs(Magnitude(ViewU) - 1.0) > eps) {
|
---|
129 | Debug << "ViewU magnitude error= " << Magnitude(ViewU) << "\n";
|
---|
130 | }
|
---|
131 | if (fabs(Magnitude(ViewV) - 1.0) > eps) {
|
---|
132 | Debug << "ViewU magnitude error= " << Magnitude(ViewV) << "\n";
|
---|
133 | }
|
---|
134 | if (fabs(Magnitude(ViewN) - 1.0) > eps) {
|
---|
135 | Debug << "ViewU magnitude error= " << Magnitude(ViewN) << "\n";
|
---|
136 | }
|
---|
137 | #endif // GTP_DEBUG
|
---|
138 |
|
---|
139 | return;
|
---|
140 | }
|
---|
141 |
|
---|
142 | // Given the intersection point `P', you have available normal `N'
|
---|
143 | // of unit length. Let us suppose the incoming ray has direction `D'.
|
---|
144 | // Then we can construct such two vectors `U' and `V' that
|
---|
145 | // `U',`N', and `D' are coplanar, and `V' is perpendicular
|
---|
146 | // to the vectors `N','D', and `V'. Then 'N', 'U', and 'V' create
|
---|
147 | // the orthonormal base in space R3.
|
---|
148 | void
|
---|
149 | TangentVectors(Vector3 &U,
|
---|
150 | Vector3 &V, // output
|
---|
151 | const Vector3 &normal, // input
|
---|
152 | const Vector3 &dirIncoming)
|
---|
153 | {
|
---|
154 | #ifdef GTP_DEBUG
|
---|
155 | float d = Magnitude(normal);
|
---|
156 | if ( (d < 0.99) ||
|
---|
157 | (d > 1.01) ) {
|
---|
158 | Debug << " The normal has not unit length = " << d << endl;
|
---|
159 | }
|
---|
160 | d = Magnitude(dirIncoming);
|
---|
161 | if ( (d < 0.99) ||
|
---|
162 | (d > 1.01) ) {
|
---|
163 | Debug << " The incoming dir has not unit length = " << d << endl;
|
---|
164 | }
|
---|
165 | #endif
|
---|
166 |
|
---|
167 | V = CrossProd(normal, dirIncoming);
|
---|
168 |
|
---|
169 | if (SqrMagnitude(V) < 1e-3) {
|
---|
170 | // the normal and dirIncoming are colinear
|
---|
171 | // we can/have to generate arbitrary perpendicular vector to normal.
|
---|
172 | if (fabs(normal.x) < 0.6)
|
---|
173 | V.SetValue(0.0, -normal.z, normal.y);
|
---|
174 | else {
|
---|
175 | if (fabs(normal.y) < 0.6)
|
---|
176 | V.SetValue(-normal.z, 0.0, normal.x);
|
---|
177 | else
|
---|
178 | V.SetValue(-normal.y, normal.x, 0.0);
|
---|
179 | }
|
---|
180 | }
|
---|
181 | V = Normalize(V);
|
---|
182 |
|
---|
183 | U = CrossProd(normal, V);
|
---|
184 | #ifdef GTP_DEBUG
|
---|
185 | d = SqrMagnitude(U);
|
---|
186 | if ( (d < 0.99) ||
|
---|
187 | (d > 1.01) ) {
|
---|
188 | Debug << "The size of U vector incorrect\n";
|
---|
189 | }
|
---|
190 | #endif
|
---|
191 | return;
|
---|
192 | }
|
---|
193 |
|
---|
194 |
|
---|
195 | Vector3 UniformRandomVector()
|
---|
196 | {
|
---|
197 | float r1 = RandomValue(0.0f, 1.0f);
|
---|
198 | float r2 = RandomValue(0.0f, 1.0f);
|
---|
199 |
|
---|
200 | return UniformRandomVector(r1, r2);
|
---|
201 | }
|
---|
202 |
|
---|
203 |
|
---|
204 | Vector3 UniformRandomVector(const float r1, const float r2)
|
---|
205 | {
|
---|
206 | float cosTheta = 1.0f - 2*r1;
|
---|
207 | float sinTheta = sqrt(1 - sqrt(cosTheta));
|
---|
208 | float fi = 2.0f * M_PI * r2;
|
---|
209 |
|
---|
210 | Vector3 dir(sinTheta*sin(fi), cosTheta, sinTheta * cos(fi));
|
---|
211 |
|
---|
212 | return dir;
|
---|
213 | }
|
---|
214 |
|
---|
215 |
|
---|
216 | Vector3 CosineRandomVector(const Vector3 &normal)
|
---|
217 | {
|
---|
218 | float r1, r2;
|
---|
219 |
|
---|
220 | r1 = RandomValue(0.0f, 1.0f);
|
---|
221 | r2 = RandomValue(0.0f, 1.0f);
|
---|
222 |
|
---|
223 | return CosineRandomVector(r1, r2, normal);
|
---|
224 | }
|
---|
225 |
|
---|
226 |
|
---|
227 | Vector3 CosineRandomVector(const float r1,
|
---|
228 | const float r2,
|
---|
229 | const Vector3 &normal)
|
---|
230 | {
|
---|
231 | float theta = 2.0f * M_PI * r2;
|
---|
232 | float radius = sqrt(r1);
|
---|
233 |
|
---|
234 | float x = radius * sin(theta);
|
---|
235 | float z = radius * cos(theta);
|
---|
236 | float y = sqrt(1.0f - x*x - z*z);
|
---|
237 |
|
---|
238 | Vector3 dir(x, y, z);
|
---|
239 |
|
---|
240 | // return Normalize(dir);
|
---|
241 |
|
---|
242 | Matrix4x4 m = RotationVectorsMatrix(normal, Vector3(0,1,0));
|
---|
243 |
|
---|
244 | Matrix4x4 mi = Invert(m);
|
---|
245 |
|
---|
246 | m = m * RotationVectorsMatrix(Vector3(0,1,0), Normalize(dir)) * mi;
|
---|
247 |
|
---|
248 | return TransformNormal(m, normal);
|
---|
249 | }
|
---|
250 |
|
---|
251 |
|
---|
252 | Vector3 UniformRandomVector(const Vector3 &normal)
|
---|
253 | {
|
---|
254 | float r1 = RandomValue(0.0f, 1.0f);
|
---|
255 | float r2 = RandomValue(0.0f, 1.0f);
|
---|
256 |
|
---|
257 | float cosTheta = 1.0f - r1;
|
---|
258 | float sinTheta = sqrt(1 - sqr(cosTheta));
|
---|
259 | float fi = 2.0f*M_PI*r2;
|
---|
260 |
|
---|
261 | Vector3 dir(sinTheta*sin(fi),
|
---|
262 | cosTheta,
|
---|
263 | sinTheta*cos(fi));
|
---|
264 |
|
---|
265 | Matrix4x4 m = RotationVectorsMatrix(normal, Vector3(0,1,0));
|
---|
266 | Matrix4x4 mi = Invert(m);
|
---|
267 |
|
---|
268 | m = m*RotationVectorsMatrix(Vector3(0, 1, 0), Normalize(dir)) * mi;
|
---|
269 |
|
---|
270 | return TransformNormal(m, normal);
|
---|
271 | }
|
---|
272 |
|
---|
273 |
|
---|
274 | bool Vector3::CheckValidity() const
|
---|
275 | {
|
---|
276 | #ifdef _WIN32
|
---|
277 | return !(_isnan(x) || _isnan(y) || _isnan(z));
|
---|
278 | #else
|
---|
279 | return !(isnan(x) || isnan(y) || isnan(z));
|
---|
280 | #endif
|
---|
281 | }
|
---|
282 |
|
---|
283 | }
|
---|