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