b5ac8292 |
1 | // Created on: 2013-05-29 |
2 | // Created by: Anton POLETAEV |
3 | // Copyright (c) 1999-2014 OPEN CASCADE SAS |
4 | // |
5 | // This file is part of Open CASCADE Technology software library. |
6 | // |
d5f74e42 |
7 | // This library is free software; you can redistribute it and/or modify it under |
8 | // the terms of the GNU Lesser General Public License version 2.1 as published |
b5ac8292 |
9 | // by the Free Software Foundation, with special exception defined in the file |
10 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
11 | // distribution for complete text of the license and disclaimer of any warranty. |
12 | // |
13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. |
15 | |
16 | #include <gp_Pln.hxx> |
17 | #include <Standard_ShortReal.hxx> |
18 | |
19 | #include <Graphic3d_Vec4.hxx> |
20 | #include <Graphic3d_Camera.hxx> |
21 | |
22 | #include <Standard_Atomic.hxx> |
197ac94e |
23 | #include <Standard_Assert.hxx> |
b5ac8292 |
24 | |
25 | IMPLEMENT_STANDARD_HANDLE(Graphic3d_Camera, Standard_Transient) |
26 | IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_Camera, Standard_Transient) |
27 | |
28 | namespace |
29 | { |
30 | // (degrees -> radians) * 0.5 |
197ac94e |
31 | static const Standard_Real DTR_HALF = 0.5 * 0.0174532925; |
32 | |
33 | // default property values |
34 | static const Standard_Real DEFAULT_ZNEAR = 0.001; |
35 | static const Standard_Real DEFAULT_ZFAR = 3000.0; |
b5ac8292 |
36 | |
37 | // atomic state counter |
38 | static volatile Standard_Integer THE_STATE_COUNTER = 0; |
39 | }; |
40 | |
41 | // ======================================================================= |
42 | // function : Graphic3d_Camera |
43 | // purpose : |
44 | // ======================================================================= |
45 | Graphic3d_Camera::Graphic3d_Camera() |
46 | : myUp (0.0, 1.0, 0.0), |
47 | myEye (0.0, 0.0, -1500.0), |
48 | myCenter (0.0, 0.0, 0.0), |
b5ac8292 |
49 | myAxialScale (1.0, 1.0, 1.0), |
50 | myProjType (Projection_Orthographic), |
51 | myFOVy (45.0), |
197ac94e |
52 | myZNear (DEFAULT_ZNEAR), |
53 | myZFar (DEFAULT_ZFAR), |
b5ac8292 |
54 | myAspect (1.0), |
55 | myScale (1000.0), |
56 | myZFocus (1.0), |
57 | myZFocusType (FocusType_Relative), |
58 | myIOD (0.05), |
197ac94e |
59 | myIODType (IODType_Relative) |
b5ac8292 |
60 | { |
61 | myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER); |
62 | myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER); |
b5ac8292 |
63 | } |
64 | |
65 | // ======================================================================= |
66 | // function : Graphic3d_Camera |
67 | // purpose : |
68 | // ======================================================================= |
69 | Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther) |
b5ac8292 |
70 | { |
71 | Copy (theOther); |
72 | } |
73 | |
74 | // ======================================================================= |
75 | // function : CopyMappingData |
76 | // purpose : |
77 | // ======================================================================= |
78 | void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera) |
79 | { |
197ac94e |
80 | myFOVy = theOtherCamera->myFOVy; |
81 | myZNear = theOtherCamera->myZNear; |
82 | myZFar = theOtherCamera->myZFar; |
83 | myAspect = theOtherCamera->myAspect; |
84 | myScale = theOtherCamera->myScale; |
85 | myZFocus = theOtherCamera->myZFocus; |
86 | myZFocusType = theOtherCamera->myZFocusType; |
87 | myIOD = theOtherCamera->myIOD; |
88 | myIODType = theOtherCamera->myIODType; |
89 | myProjType = theOtherCamera->myProjType; |
90 | myProjectionState = theOtherCamera->myProjectionState; |
b5ac8292 |
91 | |
197ac94e |
92 | InvalidateProjection(); |
b5ac8292 |
93 | } |
94 | |
95 | // ======================================================================= |
96 | // function : CopyOrientationData |
97 | // purpose : |
98 | // ======================================================================= |
99 | void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera) |
100 | { |
197ac94e |
101 | myUp = theOtherCamera->myUp; |
102 | myEye = theOtherCamera->myEye; |
103 | myCenter = theOtherCamera->myCenter; |
104 | myAxialScale = theOtherCamera->myAxialScale; |
b5ac8292 |
105 | myOrientationState = theOtherCamera->myOrientationState; |
106 | |
197ac94e |
107 | InvalidateOrientation(); |
b5ac8292 |
108 | } |
109 | |
110 | // ======================================================================= |
111 | // function : Copy |
112 | // purpose : |
113 | // ======================================================================= |
114 | void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther) |
115 | { |
b5ac8292 |
116 | CopyMappingData (theOther); |
117 | CopyOrientationData (theOther); |
b5ac8292 |
118 | } |
119 | |
120 | // ======================================================================= |
121 | // function : SetEye |
122 | // purpose : |
123 | // ======================================================================= |
124 | void Graphic3d_Camera::SetEye (const gp_Pnt& theEye) |
125 | { |
126 | myEye = theEye; |
197ac94e |
127 | InvalidateOrientation(); |
b5ac8292 |
128 | } |
129 | |
130 | // ======================================================================= |
131 | // function : SetCenter |
132 | // purpose : |
133 | // ======================================================================= |
134 | void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter) |
135 | { |
136 | myCenter = theCenter; |
197ac94e |
137 | InvalidateOrientation(); |
b5ac8292 |
138 | } |
139 | |
140 | // ======================================================================= |
141 | // function : SetUp |
142 | // purpose : |
143 | // ======================================================================= |
144 | void Graphic3d_Camera::SetUp (const gp_Dir& theUp) |
145 | { |
146 | myUp = theUp; |
197ac94e |
147 | InvalidateOrientation(); |
b5ac8292 |
148 | } |
149 | |
150 | // ======================================================================= |
151 | // function : SetAxialScale |
152 | // purpose : |
153 | // ======================================================================= |
197ac94e |
154 | void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale) |
b5ac8292 |
155 | { |
156 | myAxialScale = theAxialScale; |
197ac94e |
157 | InvalidateOrientation(); |
b5ac8292 |
158 | } |
159 | |
160 | // ======================================================================= |
161 | // function : SetDistance |
162 | // purpose : |
163 | // ======================================================================= |
164 | void Graphic3d_Camera::SetDistance (const Standard_Real theDistance) |
165 | { |
166 | gp_Vec aCenter2Eye (Direction()); |
167 | aCenter2Eye.Reverse(); |
168 | aCenter2Eye.Scale (theDistance); |
169 | SetEye (Center().Translated (aCenter2Eye)); |
170 | } |
171 | |
172 | // ======================================================================= |
173 | // function : Distance |
174 | // purpose : |
175 | // ======================================================================= |
176 | Standard_Real Graphic3d_Camera::Distance() const |
177 | { |
178 | return myEye.Distance (myCenter); |
179 | } |
180 | |
181 | // ======================================================================= |
182 | // function : SetDirection |
183 | // purpose : |
184 | // ======================================================================= |
185 | void Graphic3d_Camera::SetDirection (const gp_Dir& theDir) |
186 | { |
187 | gp_Vec aScaledDir (theDir); |
188 | aScaledDir.Scale (Distance()); |
189 | aScaledDir.Reverse(); |
190 | SetEye (Center().Translated (aScaledDir)); |
191 | } |
192 | |
193 | // ======================================================================= |
194 | // function : Direction |
195 | // purpose : |
196 | // ======================================================================= |
197 | gp_Dir Graphic3d_Camera::Direction() const |
198 | { |
199 | return gp_Dir (gp_Vec (myEye, myCenter)); |
200 | } |
201 | |
202 | // ======================================================================= |
203 | // function : SetScale |
204 | // purpose : |
205 | // ======================================================================= |
206 | void Graphic3d_Camera::SetScale (const Standard_Real theScale) |
207 | { |
208 | myScale = theScale; |
209 | |
210 | switch (myProjType) |
211 | { |
212 | case Projection_Perspective : |
213 | case Projection_Stereo : |
214 | case Projection_MonoLeftEye : |
215 | case Projection_MonoRightEye : |
216 | { |
217 | Standard_Real aDistance = theScale * 0.5 / Tan(myFOVy * M_PI / 360.0); |
218 | SetDistance (aDistance); |
219 | } |
220 | |
221 | default : |
222 | break; |
223 | } |
224 | |
197ac94e |
225 | InvalidateProjection(); |
b5ac8292 |
226 | } |
227 | |
228 | // ======================================================================= |
229 | // function : Scale |
230 | // purpose : |
231 | // ======================================================================= |
232 | Standard_Real Graphic3d_Camera::Scale() const |
233 | { |
234 | switch (myProjType) |
235 | { |
236 | case Projection_Orthographic : |
237 | return myScale; |
238 | |
239 | // case Projection_Perspective : |
240 | // case Projection_Stereo : |
241 | // case Projection_MonoLeftEye : |
242 | // case Projection_MonoRightEye : |
243 | default : |
197ac94e |
244 | return Distance() * 2.0 * Tan (myFOVy * M_PI / 360.0); |
b5ac8292 |
245 | } |
246 | } |
247 | |
248 | // ======================================================================= |
249 | // function : SetProjectionType |
250 | // purpose : |
251 | // ======================================================================= |
252 | void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType) |
253 | { |
254 | Projection anOldType = myProjType; |
255 | |
256 | if (anOldType == theProjectionType) |
257 | { |
258 | return; |
259 | } |
260 | |
197ac94e |
261 | if (anOldType == Projection_Orthographic) |
b5ac8292 |
262 | { |
197ac94e |
263 | if (myZNear <= RealEpsilon()) |
264 | { |
265 | myZNear = DEFAULT_ZNEAR; |
266 | } |
267 | if (myZFar <= RealEpsilon()) |
268 | { |
269 | myZFar = DEFAULT_ZFAR; |
270 | } |
b5ac8292 |
271 | } |
272 | |
197ac94e |
273 | myProjType = theProjectionType; |
274 | |
275 | InvalidateProjection(); |
b5ac8292 |
276 | } |
277 | |
278 | // ======================================================================= |
279 | // function : SetFOVy |
280 | // purpose : |
281 | // ======================================================================= |
282 | void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy) |
283 | { |
284 | myFOVy = theFOVy; |
197ac94e |
285 | InvalidateProjection(); |
b5ac8292 |
286 | } |
287 | |
288 | // ======================================================================= |
197ac94e |
289 | // function : SetZRange |
b5ac8292 |
290 | // purpose : |
291 | // ======================================================================= |
197ac94e |
292 | void Graphic3d_Camera::SetZRange (const Standard_Real theZNear, |
293 | const Standard_Real theZFar) |
b5ac8292 |
294 | { |
197ac94e |
295 | Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear"); |
296 | if (!IsOrthographic()) |
b5ac8292 |
297 | { |
197ac94e |
298 | Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera"); |
299 | Standard_ASSERT_RAISE (theZFar > 0.0, "Only positive Z-Far is allowed for perspective camera"); |
b5ac8292 |
300 | } |
301 | |
197ac94e |
302 | myZNear = theZNear; |
303 | myZFar = theZFar; |
b5ac8292 |
304 | |
197ac94e |
305 | InvalidateProjection(); |
b5ac8292 |
306 | } |
307 | |
308 | // ======================================================================= |
309 | // function : SetAspect |
310 | // purpose : |
311 | // ======================================================================= |
312 | void Graphic3d_Camera::SetAspect (const Standard_Real theAspect) |
313 | { |
314 | myAspect = theAspect; |
197ac94e |
315 | InvalidateProjection(); |
b5ac8292 |
316 | } |
317 | |
318 | // ======================================================================= |
319 | // function : SetZFocus |
320 | // purpose : |
321 | // ======================================================================= |
322 | void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus) |
323 | { |
324 | myZFocusType = theType; |
325 | myZFocus = theZFocus; |
197ac94e |
326 | InvalidateProjection(); |
b5ac8292 |
327 | } |
328 | |
329 | // ======================================================================= |
330 | // function : SetIOD |
331 | // purpose : |
332 | // ======================================================================= |
333 | void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD) |
334 | { |
335 | myIODType = theType; |
336 | myIOD = theIOD; |
197ac94e |
337 | InvalidateProjection(); |
b5ac8292 |
338 | } |
339 | |
340 | // ======================================================================= |
341 | // function : OrthogonalizeUp |
342 | // purpose : |
343 | // ======================================================================= |
344 | void Graphic3d_Camera::OrthogonalizeUp() |
345 | { |
197ac94e |
346 | SetUp (OrthogonalizedUp()); |
b5ac8292 |
347 | } |
348 | |
349 | // ======================================================================= |
197ac94e |
350 | // function : OrthogonalizedUp |
b5ac8292 |
351 | // purpose : |
352 | // ======================================================================= |
197ac94e |
353 | gp_Dir Graphic3d_Camera::OrthogonalizedUp() const |
b5ac8292 |
354 | { |
197ac94e |
355 | gp_Dir aDir = Direction(); |
356 | gp_Dir aLeft = aDir.Crossed (Up()); |
b5ac8292 |
357 | |
197ac94e |
358 | // recompute up as: up = left x direction |
359 | return aLeft.Crossed (aDir); |
b5ac8292 |
360 | } |
361 | |
362 | // ======================================================================= |
363 | // function : Transform |
364 | // purpose : |
365 | // ======================================================================= |
366 | void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf) |
367 | { |
368 | myUp.Transform (theTrsf); |
369 | myEye.Transform (theTrsf); |
370 | myCenter.Transform (theTrsf); |
197ac94e |
371 | InvalidateOrientation(); |
b5ac8292 |
372 | } |
373 | |
374 | // ======================================================================= |
375 | // function : safePointCast |
376 | // purpose : |
377 | // ======================================================================= |
197ac94e |
378 | static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt) |
b5ac8292 |
379 | { |
380 | Standard_Real aLim = 1e15f; |
197ac94e |
381 | |
b5ac8292 |
382 | // have to deal with values greater then max float |
383 | gp_Pnt aSafePoint = thePnt; |
384 | const Standard_Real aBigFloat = aLim * 0.1f; |
385 | if (Abs (aSafePoint.X()) > aLim) |
386 | aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat); |
387 | if (Abs (aSafePoint.Y()) > aLim) |
388 | aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat); |
389 | if (Abs (aSafePoint.Z()) > aLim) |
390 | aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat); |
391 | |
392 | // convert point |
197ac94e |
393 | Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0); |
b5ac8292 |
394 | |
395 | return aPnt; |
396 | } |
397 | |
398 | // ======================================================================= |
399 | // function : Project |
400 | // purpose : |
401 | // ======================================================================= |
402 | gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const |
403 | { |
197ac94e |
404 | const Graphic3d_Mat4d& aViewMx = OrientationMatrix(); |
405 | const Graphic3d_Mat4d& aProjMx = ProjectionMatrix(); |
b5ac8292 |
406 | |
407 | // use compatible type of point |
197ac94e |
408 | Graphic3d_Vec4d aPnt = safePointCast (thePnt); |
b5ac8292 |
409 | |
410 | aPnt = aViewMx * aPnt; // convert to view coordinate space |
411 | aPnt = aProjMx * aPnt; // convert to projection coordinate space |
412 | |
413 | const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w()); |
414 | |
415 | return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW); |
416 | } |
417 | |
418 | // ======================================================================= |
419 | // function : UnProject |
420 | // purpose : |
421 | // ======================================================================= |
422 | gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const |
423 | { |
197ac94e |
424 | const Graphic3d_Mat4d& aViewMx = OrientationMatrix(); |
425 | const Graphic3d_Mat4d& aProjMx = ProjectionMatrix(); |
b5ac8292 |
426 | |
197ac94e |
427 | Graphic3d_Mat4d aInvView; |
428 | Graphic3d_Mat4d aInvProj; |
b5ac8292 |
429 | |
430 | // this case should never happen |
431 | if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj)) |
432 | { |
433 | return gp_Pnt (0.0, 0.0, 0.0); |
434 | } |
435 | |
436 | // use compatible type of point |
197ac94e |
437 | Graphic3d_Vec4d aPnt = safePointCast (thePnt); |
b5ac8292 |
438 | |
439 | aPnt = aInvProj * aPnt; // convert to view coordinate space |
440 | aPnt = aInvView * aPnt; // convert to world coordinate space |
441 | |
442 | const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w()); |
443 | |
444 | return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW); |
445 | } |
446 | |
447 | // ======================================================================= |
448 | // function : ConvertView2Proj |
449 | // purpose : |
450 | // ======================================================================= |
451 | gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const |
452 | { |
197ac94e |
453 | const Graphic3d_Mat4d& aProjMx = ProjectionMatrix(); |
b5ac8292 |
454 | |
455 | // use compatible type of point |
197ac94e |
456 | Graphic3d_Vec4d aPnt = safePointCast (thePnt); |
b5ac8292 |
457 | |
458 | aPnt = aProjMx * aPnt; // convert to projection coordinate space |
459 | |
460 | const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w()); |
461 | |
462 | return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW); |
463 | } |
464 | |
465 | // ======================================================================= |
466 | // function : ConvertProj2View |
467 | // purpose : |
468 | // ======================================================================= |
469 | gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const |
470 | { |
197ac94e |
471 | const Graphic3d_Mat4d& aProjMx = ProjectionMatrix(); |
b5ac8292 |
472 | |
197ac94e |
473 | Graphic3d_Mat4d aInvProj; |
b5ac8292 |
474 | |
475 | // this case should never happen, but... |
476 | if (!aProjMx.Inverted (aInvProj)) |
477 | { |
197ac94e |
478 | return gp_Pnt (0, 0, 0); |
b5ac8292 |
479 | } |
480 | |
481 | // use compatible type of point |
197ac94e |
482 | Graphic3d_Vec4d aPnt = safePointCast (thePnt); |
b5ac8292 |
483 | |
484 | aPnt = aInvProj * aPnt; // convert to view coordinate space |
485 | |
486 | const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w()); |
487 | |
488 | return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW); |
489 | } |
490 | |
491 | // ======================================================================= |
492 | // function : ConvertWorld2View |
493 | // purpose : |
494 | // ======================================================================= |
495 | gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const |
496 | { |
197ac94e |
497 | const Graphic3d_Mat4d& aViewMx = OrientationMatrix(); |
b5ac8292 |
498 | |
499 | // use compatible type of point |
197ac94e |
500 | Graphic3d_Vec4d aPnt = safePointCast (thePnt); |
b5ac8292 |
501 | |
502 | aPnt = aViewMx * aPnt; // convert to view coordinate space |
503 | |
504 | const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w()); |
505 | |
506 | return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW); |
507 | } |
508 | |
509 | // ======================================================================= |
510 | // function : ConvertView2World |
511 | // purpose : |
512 | // ======================================================================= |
513 | gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const |
514 | { |
197ac94e |
515 | const Graphic3d_Mat4d& aViewMx = OrientationMatrix(); |
b5ac8292 |
516 | |
197ac94e |
517 | Graphic3d_Mat4d aInvView; |
b5ac8292 |
518 | |
519 | if (!aViewMx.Inverted (aInvView)) |
520 | { |
521 | return gp_Pnt(0, 0, 0); |
522 | } |
523 | |
524 | // use compatible type of point |
197ac94e |
525 | Graphic3d_Vec4d aPnt = safePointCast (thePnt); |
b5ac8292 |
526 | |
527 | aPnt = aInvView * aPnt; // convert to world coordinate space |
528 | |
529 | const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w()); |
530 | |
531 | return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW); |
532 | } |
533 | |
534 | // ======================================================================= |
535 | // function : ViewDimensions |
536 | // purpose : |
537 | // ======================================================================= |
197ac94e |
538 | gp_XYZ Graphic3d_Camera::ViewDimensions() const |
b5ac8292 |
539 | { |
540 | // view plane dimensions |
541 | Standard_Real aSizeY = IsOrthographic() ? myScale : (2.0 * Distance() * Tan (DTR_HALF * myFOVy)); |
542 | Standard_Real aSizeX = myAspect * aSizeY; |
543 | |
544 | // and frustum depth |
197ac94e |
545 | return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear); |
b5ac8292 |
546 | } |
547 | |
548 | // ======================================================================= |
197ac94e |
549 | // function : Frustum |
b5ac8292 |
550 | // purpose : |
551 | // ======================================================================= |
197ac94e |
552 | void Graphic3d_Camera::Frustum (gp_Pln& theLeft, |
553 | gp_Pln& theRight, |
554 | gp_Pln& theBottom, |
555 | gp_Pln& theTop, |
556 | gp_Pln& theNear, |
557 | gp_Pln& theFar) const |
b5ac8292 |
558 | { |
197ac94e |
559 | gp_Vec aProjection = gp_Vec (Direction()); |
560 | gp_Vec anUp = OrthogonalizedUp(); |
561 | gp_Vec aSide = aProjection ^ anUp; |
562 | |
563 | Standard_ASSERT_RAISE ( |
564 | !aProjection.IsParallel (anUp, Precision::Angular()), |
565 | "Can not derive SIDE = PROJ x UP - directions are parallel"); |
566 | |
567 | theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection); |
568 | theFar = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection); |
569 | |
570 | Standard_Real aHScaleHor = Scale() * 0.5 * Aspect(); |
571 | Standard_Real aHScaleVer = Scale() * 0.5; |
572 | |
573 | gp_Pnt aPntLeft = Center().Translated (aHScaleHor * -aSide); |
574 | gp_Pnt aPntRight = Center().Translated (aHScaleHor * aSide); |
575 | gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp); |
576 | gp_Pnt aPntTop = Center().Translated (aHScaleVer * anUp); |
577 | |
578 | gp_Vec aDirLeft = aSide; |
579 | gp_Vec aDirRight = -aSide; |
580 | gp_Vec aDirBottom = anUp; |
581 | gp_Vec aDirTop = -anUp; |
582 | if (!IsOrthographic()) |
583 | { |
584 | Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect()); |
585 | Standard_Real aHFOVVer = DTR_HALF * FOVy(); |
586 | aDirLeft.Rotate (gp_Ax1 (gp::Origin(), anUp), aHFOVHor); |
587 | aDirRight.Rotate (gp_Ax1 (gp::Origin(), anUp), -aHFOVHor); |
588 | aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer); |
589 | aDirTop.Rotate (gp_Ax1 (gp::Origin(), aSide), aHFOVVer); |
590 | } |
591 | |
592 | theLeft = gp_Pln (aPntLeft, aDirLeft); |
593 | theRight = gp_Pln (aPntRight, aDirRight); |
594 | theBottom = gp_Pln (aPntBottom, aDirBottom); |
595 | theTop = gp_Pln (aPntTop, aDirTop); |
596 | } |
597 | |
598 | // ======================================================================= |
599 | // function : OrientationMatrix |
600 | // purpose : |
601 | // ======================================================================= |
602 | const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const |
603 | { |
604 | return *UpdateOrientation (myMatricesD).Orientation; |
605 | } |
606 | |
607 | // ======================================================================= |
608 | // function : OrientationMatrixF |
609 | // purpose : |
610 | // ======================================================================= |
611 | const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const |
612 | { |
613 | return *UpdateOrientation (myMatricesF).Orientation; |
614 | } |
615 | |
616 | // ======================================================================= |
617 | // function : ProjectionMatrix |
618 | // purpose : |
619 | // ======================================================================= |
620 | const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const |
621 | { |
622 | return *UpdateProjection (myMatricesD).MProjection; |
623 | } |
624 | |
625 | // ======================================================================= |
626 | // function : ProjectionMatrixF |
627 | // purpose : |
628 | // ======================================================================= |
629 | const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const |
630 | { |
631 | return *UpdateProjection (myMatricesF).MProjection; |
632 | } |
633 | |
634 | // ======================================================================= |
635 | // function : ProjectionStereoLeft |
636 | // purpose : |
637 | // ======================================================================= |
638 | const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const |
639 | { |
640 | return *UpdateProjection (myMatricesD).LProjection; |
641 | } |
642 | |
643 | // ======================================================================= |
644 | // function : ProjectionStereoLeftF |
645 | // purpose : |
646 | // ======================================================================= |
647 | const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const |
648 | { |
649 | return *UpdateProjection (myMatricesF).LProjection; |
650 | } |
651 | |
652 | // ======================================================================= |
653 | // function : ProjectionStereoRight |
654 | // purpose : |
655 | // ======================================================================= |
656 | const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const |
657 | { |
658 | return *UpdateProjection (myMatricesD).RProjection; |
659 | } |
660 | |
661 | // ======================================================================= |
662 | // function : ProjectionStereoRightF |
663 | // purpose : |
664 | // ======================================================================= |
665 | const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const |
666 | { |
667 | return *UpdateProjection (myMatricesF).RProjection; |
b5ac8292 |
668 | } |
669 | |
670 | // ======================================================================= |
671 | // function : UpdateProjection |
672 | // purpose : |
673 | // ======================================================================= |
197ac94e |
674 | template <typename Elem_t> |
675 | Graphic3d_Camera::TransformMatrices<Elem_t>& |
676 | Graphic3d_Camera::UpdateProjection (TransformMatrices<Elem_t>& theMatrices) const |
b5ac8292 |
677 | { |
197ac94e |
678 | if (theMatrices.IsProjectionValid()) |
b5ac8292 |
679 | { |
197ac94e |
680 | return theMatrices; // for inline accessors |
b5ac8292 |
681 | } |
682 | |
197ac94e |
683 | theMatrices.InitProjection(); |
b5ac8292 |
684 | |
685 | // sets top of frustum based on FOVy and near clipping plane |
197ac94e |
686 | Elem_t aScale = static_cast<Elem_t> (myScale); |
687 | Elem_t aZNear = static_cast<Elem_t> (myZNear); |
688 | Elem_t aZFar = static_cast<Elem_t> (myZFar); |
689 | Elem_t anAspect = static_cast<Elem_t> (myAspect); |
690 | Elem_t aDYHalf = 0.0; |
b5ac8292 |
691 | if (IsOrthographic()) |
692 | { |
197ac94e |
693 | aDYHalf = aScale * Elem_t (0.5); |
b5ac8292 |
694 | } |
695 | else |
696 | { |
197ac94e |
697 | aDYHalf = aZNear * Elem_t (Tan (DTR_HALF * myFOVy)); |
b5ac8292 |
698 | } |
699 | |
700 | // sets right of frustum based on aspect ratio |
197ac94e |
701 | Elem_t aDXHalf = anAspect * aDYHalf; |
702 | Elem_t aLeft = -aDXHalf; |
703 | Elem_t aRight = aDXHalf; |
704 | Elem_t aBot = -aDYHalf; |
705 | Elem_t aTop = aDYHalf; |
b5ac8292 |
706 | |
197ac94e |
707 | Elem_t aIOD = myIODType == IODType_Relative |
708 | ? static_cast<Elem_t> (myIOD * Distance()) |
709 | : static_cast<Elem_t> (myIOD); |
b5ac8292 |
710 | |
197ac94e |
711 | Elem_t aFocus = myZFocusType == FocusType_Relative |
712 | ? static_cast<Elem_t> (myZFocus * Distance()) |
713 | : static_cast<Elem_t> (myZFocus); |
b5ac8292 |
714 | |
715 | switch (myProjType) |
716 | { |
717 | case Projection_Orthographic : |
197ac94e |
718 | OrthoProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection); |
b5ac8292 |
719 | break; |
720 | |
721 | case Projection_Perspective : |
197ac94e |
722 | PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection); |
b5ac8292 |
723 | break; |
724 | |
725 | case Projection_MonoLeftEye : |
726 | { |
197ac94e |
727 | StereoEyeProj (aLeft, aRight, aBot, aTop, |
728 | aZNear, aZFar, aIOD, aFocus, |
729 | Standard_True, *theMatrices.MProjection); |
b5ac8292 |
730 | break; |
731 | } |
732 | |
733 | case Projection_MonoRightEye : |
734 | { |
197ac94e |
735 | StereoEyeProj (aLeft, aRight, aBot, aTop, |
736 | aZNear, aZFar, aIOD, aFocus, |
737 | Standard_False, *theMatrices.MProjection); |
b5ac8292 |
738 | break; |
739 | } |
740 | |
741 | case Projection_Stereo : |
742 | { |
197ac94e |
743 | PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection); |
b5ac8292 |
744 | |
197ac94e |
745 | StereoEyeProj (aLeft, aRight, aBot, aTop, |
746 | aZNear, aZFar, aIOD, aFocus, |
747 | Standard_True, |
748 | *theMatrices.LProjection); |
b5ac8292 |
749 | |
197ac94e |
750 | StereoEyeProj (aLeft, aRight, aBot, aTop, |
751 | aZNear, aZFar, aIOD, aFocus, |
752 | Standard_False, |
753 | *theMatrices.RProjection); |
b5ac8292 |
754 | break; |
755 | } |
756 | } |
197ac94e |
757 | |
758 | return theMatrices; // for inline accessors |
b5ac8292 |
759 | } |
760 | |
761 | // ======================================================================= |
762 | // function : UpdateOrientation |
763 | // purpose : |
764 | // ======================================================================= |
197ac94e |
765 | template <typename Elem_t> |
766 | Graphic3d_Camera::TransformMatrices<Elem_t>& |
767 | Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const |
b5ac8292 |
768 | { |
197ac94e |
769 | if (theMatrices.IsOrientationValid()) |
b5ac8292 |
770 | { |
197ac94e |
771 | return theMatrices; // for inline accessors |
b5ac8292 |
772 | } |
773 | |
197ac94e |
774 | theMatrices.InitOrientation(); |
775 | |
776 | NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()), |
777 | static_cast<Elem_t> (myEye.Y()), |
778 | static_cast<Elem_t> (myEye.Z())); |
779 | |
780 | NCollection_Vec3<Elem_t> aCenter (static_cast<Elem_t> (myCenter.X()), |
781 | static_cast<Elem_t> (myCenter.Y()), |
782 | static_cast<Elem_t> (myCenter.Z())); |
b5ac8292 |
783 | |
197ac94e |
784 | NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()), |
785 | static_cast<Elem_t> (myUp.Y()), |
786 | static_cast<Elem_t> (myUp.Z())); |
b5ac8292 |
787 | |
197ac94e |
788 | NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()), |
789 | static_cast<Elem_t> (myAxialScale.Y()), |
790 | static_cast<Elem_t> (myAxialScale.Z())); |
b5ac8292 |
791 | |
197ac94e |
792 | LookOrientation (anEye, aCenter, anUp, anAxialScale, *theMatrices.Orientation); |
b5ac8292 |
793 | |
197ac94e |
794 | return theMatrices; // for inline accessors |
795 | } |
b5ac8292 |
796 | |
197ac94e |
797 | // ======================================================================= |
798 | // function : InvalidateProjection |
799 | // purpose : |
800 | // ======================================================================= |
801 | void Graphic3d_Camera::InvalidateProjection() |
802 | { |
803 | myMatricesD.ResetProjection(); |
804 | myMatricesF.ResetProjection(); |
805 | myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER); |
806 | } |
b5ac8292 |
807 | |
197ac94e |
808 | // ======================================================================= |
809 | // function : InvalidateOrientation |
810 | // purpose : |
811 | // ======================================================================= |
812 | void Graphic3d_Camera::InvalidateOrientation() |
813 | { |
814 | myMatricesD.ResetOrientation(); |
815 | myMatricesF.ResetOrientation(); |
816 | myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER); |
b5ac8292 |
817 | } |
818 | |
819 | // ======================================================================= |
820 | // function : OrthoProj |
821 | // purpose : |
822 | // ======================================================================= |
197ac94e |
823 | template <typename Elem_t> |
824 | void Graphic3d_Camera::OrthoProj (const Elem_t theLeft, |
825 | const Elem_t theRight, |
826 | const Elem_t theBottom, |
827 | const Elem_t theTop, |
828 | const Elem_t theNear, |
829 | const Elem_t theFar, |
830 | NCollection_Mat4<Elem_t>& theOutMx) |
b5ac8292 |
831 | { |
832 | // row 0 |
197ac94e |
833 | theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft); |
834 | theOutMx.ChangeValue (0, 1) = Elem_t (0.0); |
835 | theOutMx.ChangeValue (0, 2) = Elem_t (0.0); |
b5ac8292 |
836 | theOutMx.ChangeValue (0, 3) = - (theRight + theLeft) / (theRight - theLeft); |
837 | |
838 | // row 1 |
197ac94e |
839 | theOutMx.ChangeValue (1, 0) = Elem_t (0.0); |
840 | theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theTop - theBottom); |
841 | theOutMx.ChangeValue (1, 2) = Elem_t (0.0); |
b5ac8292 |
842 | theOutMx.ChangeValue (1, 3) = - (theTop + theBottom) / (theTop - theBottom); |
843 | |
844 | // row 2 |
197ac94e |
845 | theOutMx.ChangeValue (2, 0) = Elem_t (0.0); |
846 | theOutMx.ChangeValue (2, 1) = Elem_t (0.0); |
847 | theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear); |
b5ac8292 |
848 | theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear); |
849 | |
850 | // row 3 |
197ac94e |
851 | theOutMx.ChangeValue (3, 0) = Elem_t (0.0); |
852 | theOutMx.ChangeValue (3, 1) = Elem_t (0.0); |
853 | theOutMx.ChangeValue (3, 2) = Elem_t (0.0); |
854 | theOutMx.ChangeValue (3, 3) = Elem_t (1.0); |
b5ac8292 |
855 | } |
856 | |
857 | // ======================================================================= |
858 | // function : PerspectiveProj |
859 | // purpose : |
860 | // ======================================================================= |
197ac94e |
861 | template <typename Elem_t> |
862 | void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft, |
863 | const Elem_t theRight, |
864 | const Elem_t theBottom, |
865 | const Elem_t theTop, |
866 | const Elem_t theNear, |
867 | const Elem_t theFar, |
868 | NCollection_Mat4<Elem_t>& theOutMx) |
b5ac8292 |
869 | { |
870 | // column 0 |
197ac94e |
871 | theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft); |
872 | theOutMx.ChangeValue (1, 0) = Elem_t (0.0); |
873 | theOutMx.ChangeValue (2, 0) = Elem_t (0.0); |
874 | theOutMx.ChangeValue (3, 0) = Elem_t (0.0); |
b5ac8292 |
875 | |
876 | // column 1 |
197ac94e |
877 | theOutMx.ChangeValue (0, 1) = Elem_t (0.0); |
878 | theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theTop - theBottom); |
879 | theOutMx.ChangeValue (2, 1) = Elem_t (0.0); |
880 | theOutMx.ChangeValue (3, 1) = Elem_t (0.0); |
b5ac8292 |
881 | |
882 | // column 2 |
883 | theOutMx.ChangeValue (0, 2) = (theRight + theLeft) / (theRight - theLeft); |
884 | theOutMx.ChangeValue (1, 2) = (theTop + theBottom) / (theTop - theBottom); |
885 | theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear); |
197ac94e |
886 | theOutMx.ChangeValue (3, 2) = Elem_t (-1.0); |
b5ac8292 |
887 | |
888 | // column 3 |
197ac94e |
889 | theOutMx.ChangeValue (0, 3) = Elem_t (0.0); |
890 | theOutMx.ChangeValue (1, 3) = Elem_t (0.0); |
891 | theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear); |
892 | theOutMx.ChangeValue (3, 3) = Elem_t (0.0); |
b5ac8292 |
893 | } |
894 | |
895 | // ======================================================================= |
896 | // function : StereoEyeProj |
897 | // purpose : |
898 | // ======================================================================= |
197ac94e |
899 | template <typename Elem_t> |
900 | void Graphic3d_Camera::StereoEyeProj (const Elem_t theLeft, |
901 | const Elem_t theRight, |
902 | const Elem_t theBottom, |
903 | const Elem_t theTop, |
904 | const Elem_t theNear, |
905 | const Elem_t theFar, |
906 | const Elem_t theIOD, |
907 | const Elem_t theZFocus, |
908 | const Standard_Boolean theIsLeft, |
909 | NCollection_Mat4<Elem_t>& theOutMx) |
b5ac8292 |
910 | { |
197ac94e |
911 | Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD; |
912 | Elem_t aDXStereoShift = aDx * theNear / theZFocus; |
b5ac8292 |
913 | |
914 | // construct eye projection matrix |
915 | PerspectiveProj (theLeft + aDXStereoShift, |
916 | theRight + aDXStereoShift, |
917 | theBottom, theTop, theNear, theFar, |
b5ac8292 |
918 | theOutMx); |
919 | |
197ac94e |
920 | if (theIOD != Elem_t (0.0)) |
b5ac8292 |
921 | { |
922 | // X translation to cancel parallax |
197ac94e |
923 | theOutMx.Translate (NCollection_Vec3<Elem_t> (aDx, Elem_t (0.0), Elem_t (0.0))); |
b5ac8292 |
924 | } |
925 | } |
926 | |
927 | // ======================================================================= |
928 | // function : LookOrientation |
929 | // purpose : |
930 | // ======================================================================= |
197ac94e |
931 | template <typename Elem_t> |
932 | void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye, |
933 | const NCollection_Vec3<Elem_t>& theLookAt, |
934 | const NCollection_Vec3<Elem_t>& theUpDir, |
935 | const NCollection_Vec3<Elem_t>& theAxialScale, |
936 | NCollection_Mat4<Elem_t>& theOutMx) |
b5ac8292 |
937 | { |
197ac94e |
938 | NCollection_Vec3<Elem_t> aForward = theLookAt - theEye; |
b5ac8292 |
939 | aForward.Normalize(); |
940 | |
941 | // side = forward x up |
197ac94e |
942 | NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir); |
b5ac8292 |
943 | aSide.Normalize(); |
944 | |
945 | // recompute up as: up = side x forward |
197ac94e |
946 | NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward); |
b5ac8292 |
947 | |
197ac94e |
948 | NCollection_Mat4<Elem_t> aLookMx; |
b5ac8292 |
949 | aLookMx.SetRow (0, aSide); |
950 | aLookMx.SetRow (1, anUp); |
951 | aLookMx.SetRow (2, -aForward); |
952 | |
197ac94e |
953 | theOutMx.InitIdentity(); |
954 | theOutMx.Multiply (aLookMx); |
b5ac8292 |
955 | theOutMx.Translate (-theEye); |
956 | |
197ac94e |
957 | NCollection_Mat4<Elem_t> anAxialScaleMx; |
b5ac8292 |
958 | anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x(); |
959 | anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y(); |
960 | anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z(); |
961 | |
962 | theOutMx.Multiply (anAxialScaleMx); |
963 | } |