0026025: Visualization, TKOpenGl - stereoscopic output does not work
[occt.git] / src / Graphic3d / Graphic3d_Camera.cxx
CommitLineData
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
ed063270 25#include <NCollection_Sequence.hxx>
26
b5ac8292 27IMPLEMENT_STANDARD_HANDLE(Graphic3d_Camera, Standard_Transient)
28IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_Camera, Standard_Transient)
29
30namespace
31{
32 // (degrees -> radians) * 0.5
197ac94e 33 static const Standard_Real DTR_HALF = 0.5 * 0.0174532925;
34
35 // default property values
36 static const Standard_Real DEFAULT_ZNEAR = 0.001;
37 static const Standard_Real DEFAULT_ZFAR = 3000.0;
b5ac8292 38
39 // atomic state counter
40 static volatile Standard_Integer THE_STATE_COUNTER = 0;
3c648527 41
42 // minimum camera distance
43 static const Standard_Real MIN_DISTANCE = Pow (0.1, ShortRealDigits() - 2);
b5ac8292 44};
45
46// =======================================================================
47// function : Graphic3d_Camera
48// purpose :
49// =======================================================================
50Graphic3d_Camera::Graphic3d_Camera()
51: myUp (0.0, 1.0, 0.0),
52 myEye (0.0, 0.0, -1500.0),
53 myCenter (0.0, 0.0, 0.0),
b5ac8292 54 myAxialScale (1.0, 1.0, 1.0),
55 myProjType (Projection_Orthographic),
56 myFOVy (45.0),
197ac94e 57 myZNear (DEFAULT_ZNEAR),
58 myZFar (DEFAULT_ZFAR),
b5ac8292 59 myAspect (1.0),
60 myScale (1000.0),
61 myZFocus (1.0),
62 myZFocusType (FocusType_Relative),
63 myIOD (0.05),
197ac94e 64 myIODType (IODType_Relative)
b5ac8292 65{
66 myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
67 myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
b5ac8292 68}
69
70// =======================================================================
71// function : Graphic3d_Camera
72// purpose :
73// =======================================================================
74Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
b5ac8292 75{
76 Copy (theOther);
77}
78
79// =======================================================================
80// function : CopyMappingData
81// purpose :
82// =======================================================================
83void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera)
84{
197ac94e 85 myFOVy = theOtherCamera->myFOVy;
86 myZNear = theOtherCamera->myZNear;
87 myZFar = theOtherCamera->myZFar;
88 myAspect = theOtherCamera->myAspect;
89 myScale = theOtherCamera->myScale;
90 myZFocus = theOtherCamera->myZFocus;
91 myZFocusType = theOtherCamera->myZFocusType;
92 myIOD = theOtherCamera->myIOD;
93 myIODType = theOtherCamera->myIODType;
94 myProjType = theOtherCamera->myProjType;
95 myProjectionState = theOtherCamera->myProjectionState;
b5ac8292 96
197ac94e 97 InvalidateProjection();
b5ac8292 98}
99
100// =======================================================================
101// function : CopyOrientationData
102// purpose :
103// =======================================================================
104void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera)
105{
197ac94e 106 myUp = theOtherCamera->myUp;
107 myEye = theOtherCamera->myEye;
108 myCenter = theOtherCamera->myCenter;
109 myAxialScale = theOtherCamera->myAxialScale;
b5ac8292 110 myOrientationState = theOtherCamera->myOrientationState;
111
197ac94e 112 InvalidateOrientation();
b5ac8292 113}
114
115// =======================================================================
116// function : Copy
117// purpose :
118// =======================================================================
119void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther)
120{
b5ac8292 121 CopyMappingData (theOther);
122 CopyOrientationData (theOther);
b5ac8292 123}
124
125// =======================================================================
126// function : SetEye
127// purpose :
128// =======================================================================
129void Graphic3d_Camera::SetEye (const gp_Pnt& theEye)
130{
131 myEye = theEye;
197ac94e 132 InvalidateOrientation();
b5ac8292 133}
134
135// =======================================================================
136// function : SetCenter
137// purpose :
138// =======================================================================
139void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter)
140{
141 myCenter = theCenter;
197ac94e 142 InvalidateOrientation();
b5ac8292 143}
144
145// =======================================================================
146// function : SetUp
147// purpose :
148// =======================================================================
149void Graphic3d_Camera::SetUp (const gp_Dir& theUp)
150{
151 myUp = theUp;
197ac94e 152 InvalidateOrientation();
b5ac8292 153}
154
155// =======================================================================
156// function : SetAxialScale
157// purpose :
158// =======================================================================
197ac94e 159void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale)
b5ac8292 160{
161 myAxialScale = theAxialScale;
197ac94e 162 InvalidateOrientation();
b5ac8292 163}
164
165// =======================================================================
166// function : SetDistance
167// purpose :
168// =======================================================================
169void Graphic3d_Camera::SetDistance (const Standard_Real theDistance)
170{
171 gp_Vec aCenter2Eye (Direction());
172 aCenter2Eye.Reverse();
3c648527 173
174 // Camera should have non-zero distance.
175 aCenter2Eye.Scale (Max (theDistance, MIN_DISTANCE));
b5ac8292 176 SetEye (Center().Translated (aCenter2Eye));
177}
178
179// =======================================================================
180// function : Distance
181// purpose :
182// =======================================================================
183Standard_Real Graphic3d_Camera::Distance() const
184{
185 return myEye.Distance (myCenter);
186}
187
188// =======================================================================
189// function : SetDirection
190// purpose :
191// =======================================================================
192void Graphic3d_Camera::SetDirection (const gp_Dir& theDir)
193{
194 gp_Vec aScaledDir (theDir);
195 aScaledDir.Scale (Distance());
196 aScaledDir.Reverse();
197 SetEye (Center().Translated (aScaledDir));
198}
199
200// =======================================================================
201// function : Direction
202// purpose :
203// =======================================================================
204gp_Dir Graphic3d_Camera::Direction() const
205{
206 return gp_Dir (gp_Vec (myEye, myCenter));
207}
208
209// =======================================================================
210// function : SetScale
211// purpose :
212// =======================================================================
213void Graphic3d_Camera::SetScale (const Standard_Real theScale)
214{
215 myScale = theScale;
216
217 switch (myProjType)
218 {
219 case Projection_Perspective :
220 case Projection_Stereo :
221 case Projection_MonoLeftEye :
222 case Projection_MonoRightEye :
223 {
224 Standard_Real aDistance = theScale * 0.5 / Tan(myFOVy * M_PI / 360.0);
225 SetDistance (aDistance);
226 }
227
228 default :
229 break;
230 }
231
197ac94e 232 InvalidateProjection();
b5ac8292 233}
234
235// =======================================================================
236// function : Scale
237// purpose :
238// =======================================================================
239Standard_Real Graphic3d_Camera::Scale() const
240{
241 switch (myProjType)
242 {
243 case Projection_Orthographic :
244 return myScale;
245
246 // case Projection_Perspective :
247 // case Projection_Stereo :
248 // case Projection_MonoLeftEye :
249 // case Projection_MonoRightEye :
250 default :
197ac94e 251 return Distance() * 2.0 * Tan (myFOVy * M_PI / 360.0);
b5ac8292 252 }
253}
254
255// =======================================================================
256// function : SetProjectionType
257// purpose :
258// =======================================================================
259void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType)
260{
261 Projection anOldType = myProjType;
262
263 if (anOldType == theProjectionType)
264 {
265 return;
266 }
267
197ac94e 268 if (anOldType == Projection_Orthographic)
b5ac8292 269 {
197ac94e 270 if (myZNear <= RealEpsilon())
271 {
272 myZNear = DEFAULT_ZNEAR;
273 }
274 if (myZFar <= RealEpsilon())
275 {
276 myZFar = DEFAULT_ZFAR;
277 }
b5ac8292 278 }
279
197ac94e 280 myProjType = theProjectionType;
281
282 InvalidateProjection();
b5ac8292 283}
284
285// =======================================================================
286// function : SetFOVy
287// purpose :
288// =======================================================================
289void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy)
290{
291 myFOVy = theFOVy;
197ac94e 292 InvalidateProjection();
b5ac8292 293}
294
295// =======================================================================
197ac94e 296// function : SetZRange
b5ac8292 297// purpose :
298// =======================================================================
197ac94e 299void Graphic3d_Camera::SetZRange (const Standard_Real theZNear,
300 const Standard_Real theZFar)
b5ac8292 301{
197ac94e 302 Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear");
303 if (!IsOrthographic())
b5ac8292 304 {
197ac94e 305 Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera");
306 Standard_ASSERT_RAISE (theZFar > 0.0, "Only positive Z-Far is allowed for perspective camera");
b5ac8292 307 }
308
197ac94e 309 myZNear = theZNear;
310 myZFar = theZFar;
b5ac8292 311
197ac94e 312 InvalidateProjection();
b5ac8292 313}
314
315// =======================================================================
316// function : SetAspect
317// purpose :
318// =======================================================================
319void Graphic3d_Camera::SetAspect (const Standard_Real theAspect)
320{
321 myAspect = theAspect;
197ac94e 322 InvalidateProjection();
b5ac8292 323}
324
325// =======================================================================
326// function : SetZFocus
327// purpose :
328// =======================================================================
329void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus)
330{
331 myZFocusType = theType;
332 myZFocus = theZFocus;
197ac94e 333 InvalidateProjection();
b5ac8292 334}
335
336// =======================================================================
337// function : SetIOD
338// purpose :
339// =======================================================================
340void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD)
341{
342 myIODType = theType;
343 myIOD = theIOD;
197ac94e 344 InvalidateProjection();
b5ac8292 345}
346
347// =======================================================================
348// function : OrthogonalizeUp
349// purpose :
350// =======================================================================
351void Graphic3d_Camera::OrthogonalizeUp()
352{
197ac94e 353 SetUp (OrthogonalizedUp());
b5ac8292 354}
355
356// =======================================================================
197ac94e 357// function : OrthogonalizedUp
b5ac8292 358// purpose :
359// =======================================================================
197ac94e 360gp_Dir Graphic3d_Camera::OrthogonalizedUp() const
b5ac8292 361{
197ac94e 362 gp_Dir aDir = Direction();
363 gp_Dir aLeft = aDir.Crossed (Up());
b5ac8292 364
197ac94e 365 // recompute up as: up = left x direction
366 return aLeft.Crossed (aDir);
b5ac8292 367}
368
369// =======================================================================
370// function : Transform
371// purpose :
372// =======================================================================
373void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf)
374{
375 myUp.Transform (theTrsf);
376 myEye.Transform (theTrsf);
377 myCenter.Transform (theTrsf);
197ac94e 378 InvalidateOrientation();
b5ac8292 379}
380
381// =======================================================================
382// function : safePointCast
383// purpose :
384// =======================================================================
197ac94e 385static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt)
b5ac8292 386{
387 Standard_Real aLim = 1e15f;
197ac94e 388
b5ac8292 389 // have to deal with values greater then max float
390 gp_Pnt aSafePoint = thePnt;
391 const Standard_Real aBigFloat = aLim * 0.1f;
392 if (Abs (aSafePoint.X()) > aLim)
393 aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
394 if (Abs (aSafePoint.Y()) > aLim)
395 aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
396 if (Abs (aSafePoint.Z()) > aLim)
397 aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
398
399 // convert point
197ac94e 400 Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
b5ac8292 401
402 return aPnt;
403}
404
405// =======================================================================
406// function : Project
407// purpose :
408// =======================================================================
409gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const
410{
197ac94e 411 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
412 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 413
414 // use compatible type of point
197ac94e 415 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 416
417 aPnt = aViewMx * aPnt; // convert to view coordinate space
418 aPnt = aProjMx * aPnt; // convert to projection coordinate space
419
420 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
421
422 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
423}
424
425// =======================================================================
426// function : UnProject
427// purpose :
428// =======================================================================
429gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const
430{
197ac94e 431 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
432 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 433
197ac94e 434 Graphic3d_Mat4d aInvView;
435 Graphic3d_Mat4d aInvProj;
b5ac8292 436
437 // this case should never happen
438 if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj))
439 {
440 return gp_Pnt (0.0, 0.0, 0.0);
441 }
442
443 // use compatible type of point
197ac94e 444 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 445
446 aPnt = aInvProj * aPnt; // convert to view coordinate space
447 aPnt = aInvView * aPnt; // convert to world coordinate space
448
449 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
450
451 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
452}
453
454// =======================================================================
455// function : ConvertView2Proj
456// purpose :
457// =======================================================================
458gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const
459{
197ac94e 460 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 461
462 // use compatible type of point
197ac94e 463 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 464
465 aPnt = aProjMx * aPnt; // convert to projection coordinate space
466
467 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
468
469 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
470}
471
472// =======================================================================
473// function : ConvertProj2View
474// purpose :
475// =======================================================================
476gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const
477{
197ac94e 478 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 479
197ac94e 480 Graphic3d_Mat4d aInvProj;
b5ac8292 481
482 // this case should never happen, but...
483 if (!aProjMx.Inverted (aInvProj))
484 {
197ac94e 485 return gp_Pnt (0, 0, 0);
b5ac8292 486 }
487
488 // use compatible type of point
197ac94e 489 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 490
491 aPnt = aInvProj * aPnt; // convert to view coordinate space
492
493 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
494
495 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
496}
497
498// =======================================================================
499// function : ConvertWorld2View
500// purpose :
501// =======================================================================
502gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const
503{
197ac94e 504 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
b5ac8292 505
506 // use compatible type of point
197ac94e 507 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 508
509 aPnt = aViewMx * aPnt; // convert to view coordinate space
510
511 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
512
513 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
514}
515
516// =======================================================================
517// function : ConvertView2World
518// purpose :
519// =======================================================================
520gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const
521{
197ac94e 522 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
b5ac8292 523
197ac94e 524 Graphic3d_Mat4d aInvView;
b5ac8292 525
526 if (!aViewMx.Inverted (aInvView))
527 {
528 return gp_Pnt(0, 0, 0);
529 }
530
531 // use compatible type of point
197ac94e 532 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 533
534 aPnt = aInvView * aPnt; // convert to world coordinate space
535
536 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
537
538 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
539}
540
541// =======================================================================
542// function : ViewDimensions
543// purpose :
544// =======================================================================
197ac94e 545gp_XYZ Graphic3d_Camera::ViewDimensions() const
b5ac8292 546{
547 // view plane dimensions
548 Standard_Real aSizeY = IsOrthographic() ? myScale : (2.0 * Distance() * Tan (DTR_HALF * myFOVy));
549 Standard_Real aSizeX = myAspect * aSizeY;
550
551 // and frustum depth
197ac94e 552 return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear);
b5ac8292 553}
554
555// =======================================================================
197ac94e 556// function : Frustum
b5ac8292 557// purpose :
558// =======================================================================
197ac94e 559void Graphic3d_Camera::Frustum (gp_Pln& theLeft,
560 gp_Pln& theRight,
561 gp_Pln& theBottom,
562 gp_Pln& theTop,
563 gp_Pln& theNear,
564 gp_Pln& theFar) const
b5ac8292 565{
197ac94e 566 gp_Vec aProjection = gp_Vec (Direction());
567 gp_Vec anUp = OrthogonalizedUp();
568 gp_Vec aSide = aProjection ^ anUp;
569
570 Standard_ASSERT_RAISE (
571 !aProjection.IsParallel (anUp, Precision::Angular()),
572 "Can not derive SIDE = PROJ x UP - directions are parallel");
573
574 theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection);
575 theFar = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection);
576
577 Standard_Real aHScaleHor = Scale() * 0.5 * Aspect();
578 Standard_Real aHScaleVer = Scale() * 0.5;
579
580 gp_Pnt aPntLeft = Center().Translated (aHScaleHor * -aSide);
581 gp_Pnt aPntRight = Center().Translated (aHScaleHor * aSide);
582 gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp);
583 gp_Pnt aPntTop = Center().Translated (aHScaleVer * anUp);
584
585 gp_Vec aDirLeft = aSide;
586 gp_Vec aDirRight = -aSide;
587 gp_Vec aDirBottom = anUp;
588 gp_Vec aDirTop = -anUp;
589 if (!IsOrthographic())
590 {
591 Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect());
592 Standard_Real aHFOVVer = DTR_HALF * FOVy();
593 aDirLeft.Rotate (gp_Ax1 (gp::Origin(), anUp), aHFOVHor);
594 aDirRight.Rotate (gp_Ax1 (gp::Origin(), anUp), -aHFOVHor);
595 aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer);
596 aDirTop.Rotate (gp_Ax1 (gp::Origin(), aSide), aHFOVVer);
597 }
598
599 theLeft = gp_Pln (aPntLeft, aDirLeft);
600 theRight = gp_Pln (aPntRight, aDirRight);
601 theBottom = gp_Pln (aPntBottom, aDirBottom);
602 theTop = gp_Pln (aPntTop, aDirTop);
603}
604
605// =======================================================================
606// function : OrientationMatrix
607// purpose :
608// =======================================================================
609const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const
610{
611 return *UpdateOrientation (myMatricesD).Orientation;
612}
613
614// =======================================================================
615// function : OrientationMatrixF
616// purpose :
617// =======================================================================
618const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const
619{
620 return *UpdateOrientation (myMatricesF).Orientation;
621}
622
623// =======================================================================
624// function : ProjectionMatrix
625// purpose :
626// =======================================================================
627const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const
628{
629 return *UpdateProjection (myMatricesD).MProjection;
630}
631
632// =======================================================================
633// function : ProjectionMatrixF
634// purpose :
635// =======================================================================
636const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const
637{
638 return *UpdateProjection (myMatricesF).MProjection;
639}
640
641// =======================================================================
642// function : ProjectionStereoLeft
643// purpose :
644// =======================================================================
645const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const
646{
647 return *UpdateProjection (myMatricesD).LProjection;
648}
649
650// =======================================================================
651// function : ProjectionStereoLeftF
652// purpose :
653// =======================================================================
654const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const
655{
656 return *UpdateProjection (myMatricesF).LProjection;
657}
658
659// =======================================================================
660// function : ProjectionStereoRight
661// purpose :
662// =======================================================================
663const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const
664{
665 return *UpdateProjection (myMatricesD).RProjection;
666}
667
668// =======================================================================
669// function : ProjectionStereoRightF
670// purpose :
671// =======================================================================
672const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const
673{
674 return *UpdateProjection (myMatricesF).RProjection;
b5ac8292 675}
676
677// =======================================================================
678// function : UpdateProjection
679// purpose :
680// =======================================================================
197ac94e 681template <typename Elem_t>
682Graphic3d_Camera::TransformMatrices<Elem_t>&
683 Graphic3d_Camera::UpdateProjection (TransformMatrices<Elem_t>& theMatrices) const
b5ac8292 684{
197ac94e 685 if (theMatrices.IsProjectionValid())
b5ac8292 686 {
197ac94e 687 return theMatrices; // for inline accessors
b5ac8292 688 }
689
197ac94e 690 theMatrices.InitProjection();
b5ac8292 691
692 // sets top of frustum based on FOVy and near clipping plane
197ac94e 693 Elem_t aScale = static_cast<Elem_t> (myScale);
694 Elem_t aZNear = static_cast<Elem_t> (myZNear);
695 Elem_t aZFar = static_cast<Elem_t> (myZFar);
696 Elem_t anAspect = static_cast<Elem_t> (myAspect);
697 Elem_t aDYHalf = 0.0;
b5ac8292 698 if (IsOrthographic())
699 {
197ac94e 700 aDYHalf = aScale * Elem_t (0.5);
b5ac8292 701 }
702 else
703 {
197ac94e 704 aDYHalf = aZNear * Elem_t (Tan (DTR_HALF * myFOVy));
b5ac8292 705 }
706
707 // sets right of frustum based on aspect ratio
197ac94e 708 Elem_t aDXHalf = anAspect * aDYHalf;
709 Elem_t aLeft = -aDXHalf;
710 Elem_t aRight = aDXHalf;
711 Elem_t aBot = -aDYHalf;
712 Elem_t aTop = aDYHalf;
b5ac8292 713
197ac94e 714 Elem_t aIOD = myIODType == IODType_Relative
715 ? static_cast<Elem_t> (myIOD * Distance())
716 : static_cast<Elem_t> (myIOD);
b5ac8292 717
197ac94e 718 Elem_t aFocus = myZFocusType == FocusType_Relative
719 ? static_cast<Elem_t> (myZFocus * Distance())
720 : static_cast<Elem_t> (myZFocus);
b5ac8292 721
722 switch (myProjType)
723 {
724 case Projection_Orthographic :
197ac94e 725 OrthoProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
b5ac8292 726 break;
727
728 case Projection_Perspective :
197ac94e 729 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
b5ac8292 730 break;
731
732 case Projection_MonoLeftEye :
733 {
197ac94e 734 StereoEyeProj (aLeft, aRight, aBot, aTop,
735 aZNear, aZFar, aIOD, aFocus,
736 Standard_True, *theMatrices.MProjection);
38a0206f 737 *theMatrices.LProjection = *theMatrices.MProjection;
b5ac8292 738 break;
739 }
740
741 case Projection_MonoRightEye :
742 {
197ac94e 743 StereoEyeProj (aLeft, aRight, aBot, aTop,
744 aZNear, aZFar, aIOD, aFocus,
745 Standard_False, *theMatrices.MProjection);
38a0206f 746 *theMatrices.RProjection = *theMatrices.MProjection;
b5ac8292 747 break;
748 }
749
750 case Projection_Stereo :
751 {
197ac94e 752 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
b5ac8292 753
197ac94e 754 StereoEyeProj (aLeft, aRight, aBot, aTop,
755 aZNear, aZFar, aIOD, aFocus,
756 Standard_True,
757 *theMatrices.LProjection);
b5ac8292 758
197ac94e 759 StereoEyeProj (aLeft, aRight, aBot, aTop,
760 aZNear, aZFar, aIOD, aFocus,
761 Standard_False,
762 *theMatrices.RProjection);
b5ac8292 763 break;
764 }
765 }
197ac94e 766
767 return theMatrices; // for inline accessors
b5ac8292 768}
769
770// =======================================================================
771// function : UpdateOrientation
772// purpose :
773// =======================================================================
197ac94e 774template <typename Elem_t>
775Graphic3d_Camera::TransformMatrices<Elem_t>&
776 Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
b5ac8292 777{
197ac94e 778 if (theMatrices.IsOrientationValid())
b5ac8292 779 {
197ac94e 780 return theMatrices; // for inline accessors
b5ac8292 781 }
782
197ac94e 783 theMatrices.InitOrientation();
784
785 NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
786 static_cast<Elem_t> (myEye.Y()),
787 static_cast<Elem_t> (myEye.Z()));
788
789 NCollection_Vec3<Elem_t> aCenter (static_cast<Elem_t> (myCenter.X()),
790 static_cast<Elem_t> (myCenter.Y()),
791 static_cast<Elem_t> (myCenter.Z()));
b5ac8292 792
197ac94e 793 NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
794 static_cast<Elem_t> (myUp.Y()),
795 static_cast<Elem_t> (myUp.Z()));
b5ac8292 796
197ac94e 797 NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
798 static_cast<Elem_t> (myAxialScale.Y()),
799 static_cast<Elem_t> (myAxialScale.Z()));
b5ac8292 800
197ac94e 801 LookOrientation (anEye, aCenter, anUp, anAxialScale, *theMatrices.Orientation);
b5ac8292 802
197ac94e 803 return theMatrices; // for inline accessors
804}
b5ac8292 805
197ac94e 806// =======================================================================
807// function : InvalidateProjection
808// purpose :
809// =======================================================================
810void Graphic3d_Camera::InvalidateProjection()
811{
812 myMatricesD.ResetProjection();
813 myMatricesF.ResetProjection();
814 myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
815}
b5ac8292 816
197ac94e 817// =======================================================================
818// function : InvalidateOrientation
819// purpose :
820// =======================================================================
821void Graphic3d_Camera::InvalidateOrientation()
822{
823 myMatricesD.ResetOrientation();
824 myMatricesF.ResetOrientation();
825 myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
b5ac8292 826}
827
828// =======================================================================
829// function : OrthoProj
830// purpose :
831// =======================================================================
197ac94e 832template <typename Elem_t>
833void Graphic3d_Camera::OrthoProj (const Elem_t theLeft,
834 const Elem_t theRight,
835 const Elem_t theBottom,
836 const Elem_t theTop,
837 const Elem_t theNear,
838 const Elem_t theFar,
839 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 840{
841 // row 0
197ac94e 842 theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft);
843 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
844 theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
b5ac8292 845 theOutMx.ChangeValue (0, 3) = - (theRight + theLeft) / (theRight - theLeft);
846
847 // row 1
197ac94e 848 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
849 theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theTop - theBottom);
850 theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
b5ac8292 851 theOutMx.ChangeValue (1, 3) = - (theTop + theBottom) / (theTop - theBottom);
852
853 // row 2
197ac94e 854 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
855 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
856 theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
b5ac8292 857 theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
858
859 // row 3
197ac94e 860 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
861 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
862 theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
863 theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
b5ac8292 864}
865
866// =======================================================================
867// function : PerspectiveProj
868// purpose :
869// =======================================================================
197ac94e 870template <typename Elem_t>
871void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft,
872 const Elem_t theRight,
873 const Elem_t theBottom,
874 const Elem_t theTop,
875 const Elem_t theNear,
876 const Elem_t theFar,
877 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 878{
879 // column 0
197ac94e 880 theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft);
881 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
882 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
883 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
b5ac8292 884
885 // column 1
197ac94e 886 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
887 theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theTop - theBottom);
888 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
889 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
b5ac8292 890
891 // column 2
892 theOutMx.ChangeValue (0, 2) = (theRight + theLeft) / (theRight - theLeft);
893 theOutMx.ChangeValue (1, 2) = (theTop + theBottom) / (theTop - theBottom);
894 theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
197ac94e 895 theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
b5ac8292 896
897 // column 3
197ac94e 898 theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
899 theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
900 theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
901 theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
b5ac8292 902}
903
904// =======================================================================
905// function : StereoEyeProj
906// purpose :
907// =======================================================================
197ac94e 908template <typename Elem_t>
909void Graphic3d_Camera::StereoEyeProj (const Elem_t theLeft,
910 const Elem_t theRight,
911 const Elem_t theBottom,
912 const Elem_t theTop,
913 const Elem_t theNear,
914 const Elem_t theFar,
915 const Elem_t theIOD,
916 const Elem_t theZFocus,
917 const Standard_Boolean theIsLeft,
918 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 919{
197ac94e 920 Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
921 Elem_t aDXStereoShift = aDx * theNear / theZFocus;
b5ac8292 922
923 // construct eye projection matrix
924 PerspectiveProj (theLeft + aDXStereoShift,
925 theRight + aDXStereoShift,
926 theBottom, theTop, theNear, theFar,
b5ac8292 927 theOutMx);
928
197ac94e 929 if (theIOD != Elem_t (0.0))
b5ac8292 930 {
931 // X translation to cancel parallax
197ac94e 932 theOutMx.Translate (NCollection_Vec3<Elem_t> (aDx, Elem_t (0.0), Elem_t (0.0)));
b5ac8292 933 }
934}
935
936// =======================================================================
937// function : LookOrientation
938// purpose :
939// =======================================================================
197ac94e 940template <typename Elem_t>
941void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
942 const NCollection_Vec3<Elem_t>& theLookAt,
943 const NCollection_Vec3<Elem_t>& theUpDir,
944 const NCollection_Vec3<Elem_t>& theAxialScale,
945 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 946{
197ac94e 947 NCollection_Vec3<Elem_t> aForward = theLookAt - theEye;
b5ac8292 948 aForward.Normalize();
949
950 // side = forward x up
197ac94e 951 NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
b5ac8292 952 aSide.Normalize();
953
954 // recompute up as: up = side x forward
197ac94e 955 NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
b5ac8292 956
197ac94e 957 NCollection_Mat4<Elem_t> aLookMx;
b5ac8292 958 aLookMx.SetRow (0, aSide);
959 aLookMx.SetRow (1, anUp);
960 aLookMx.SetRow (2, -aForward);
961
197ac94e 962 theOutMx.InitIdentity();
963 theOutMx.Multiply (aLookMx);
b5ac8292 964 theOutMx.Translate (-theEye);
965
197ac94e 966 NCollection_Mat4<Elem_t> anAxialScaleMx;
b5ac8292 967 anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
968 anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
969 anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
970
971 theOutMx.Multiply (anAxialScaleMx);
972}
6bc6a6fc 973
974//=============================================================================
975//function : ZFitAll
976//purpose :
977//=============================================================================
978void Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor, const Bnd_Box& theMinMax, const Bnd_Box& theGraphicBB)
979{
980 Standard_ASSERT_RAISE (theScaleFactor > 0.0, "Zero or negative scale factor is not allowed.");
981
982 // Method changes ZNear and ZFar planes of camera so as to fit the graphical structures
983 // by their real boundaries (computed ignoring infinite flag) into the viewing volume.
984 // In addition to the graphical boundaries, the usual min max used for fitting perspective
985 // camera. To avoid numeric errors for perspective camera the negative ZNear values are
986 // fixed using tolerance distance, relative to boundaries size. The tolerance distance
987 // should be computed using information on boundaries of primary application actors,
988 // (e.g. representing the displayed model) - to ensure that they are not unreasonably clipped.
989
ed063270 990 if (theGraphicBB.IsVoid())
6bc6a6fc 991 {
992 // ShortReal precision factor used to add meaningful tolerance to
993 // ZNear, ZFar values in order to avoid equality after type conversion
994 // to ShortReal matrices type.
995 const Standard_Real aPrecision = 1.0 / Pow (10.0, ShortRealDigits() - 1);
996
997 Standard_Real aZFar = Distance() * 3.0;
998 Standard_Real aZNear = 0.0;
999
1000 if (!IsOrthographic())
1001 {
1002 if (aZFar < aPrecision)
1003 {
1004 // Invalid case when both values are negative
1005 aZNear = aPrecision;
1006 aZFar = aPrecision * 2.0;
1007 }
1008 else if (aZNear < Abs (aZFar) * aPrecision)
1009 {
1010 // Z is less than 0.0, try to fix it using any appropriate z-scale
1011 aZNear = Abs (aZFar) * aPrecision;
1012 }
1013 }
1014
1015 SetZRange (aZNear, aZFar);
1016 return;
1017 }
1018
1019 // Measure depth of boundary points from camera eye
ed063270 1020 NCollection_Sequence<gp_Pnt> aPntsToMeasure;
1021
1022 Standard_Real aGraphicBB[6]; // real graphical boundaries (not accounting infinite flag).
1023 theGraphicBB.Get (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2], aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]);
1024
1025 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2]));
1026 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[5]));
1027 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[2]));
1028 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[5]));
1029 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[2]));
1030 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[5]));
1031 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[2]));
1032 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]));
1033
1034 if (!theMinMax.IsVoid() && !theMinMax.IsWhole())
6bc6a6fc 1035 {
ed063270 1036 Standard_Real aMinMax[6]; // applicative min max boundaries
1037 theMinMax.Get (aMinMax[0], aMinMax[1], aMinMax[2], aMinMax[3], aMinMax[4], aMinMax[5]);
1038
1039 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[2]));
1040 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[5]));
1041 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[2]));
1042 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[5]));
1043 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[2]));
1044 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[5]));
1045 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[2]));
1046 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[5]));
1047 }
6bc6a6fc 1048
1049 // Camera eye plane
1050 gp_Dir aCamDir = Direction();
1051 gp_Pnt aCamEye = myEye;
1052 gp_Pln aCamPln (aCamEye, aCamDir);
1053
1054 Standard_Real aModelMinDist = RealLast();
1055 Standard_Real aModelMaxDist = RealFirst();
1056 Standard_Real aGraphicMinDist = RealLast();
1057 Standard_Real aGraphicMaxDist = RealFirst();
1058
1059 const gp_XYZ& anAxialScale = myAxialScale;
1060
1061 // Get minimum and maximum distances to the eye plane
ed063270 1062 Standard_Integer aCounter = 0;
1063 NCollection_Sequence<gp_Pnt>::Iterator aPntIt(aPntsToMeasure);
1064 for (; aPntIt.More(); aPntIt.Next())
6bc6a6fc 1065 {
ed063270 1066 gp_Pnt aMeasurePnt = aPntIt.Value();
6bc6a6fc 1067
1068 aMeasurePnt = gp_Pnt (aMeasurePnt.X() * anAxialScale.X(),
ed063270 1069 aMeasurePnt.Y() * anAxialScale.Y(),
1070 aMeasurePnt.Z() * anAxialScale.Z());
6bc6a6fc 1071
1072 Standard_Real aDistance = aCamPln.Distance (aMeasurePnt);
1073
1074 // Check if the camera is intruded into the scene
1075 if (aCamDir.IsOpposite (gp_Vec (aCamEye, aMeasurePnt), M_PI * 0.5))
1076 {
1077 aDistance *= -1;
1078 }
1079
ed063270 1080 // the first eight points are from theGraphicBB, the last eight points are from theMinMax
1081 // (they can be absent).
1082 Standard_Real& aChangeMinDist = aCounter >= 8 ? aModelMinDist : aGraphicMinDist;
1083 Standard_Real& aChangeMaxDist = aCounter >= 8 ? aModelMaxDist : aGraphicMaxDist;
6bc6a6fc 1084 aChangeMinDist = Min (aDistance, aChangeMinDist);
1085 aChangeMaxDist = Max (aDistance, aChangeMaxDist);
ed063270 1086 aCounter++;
6bc6a6fc 1087 }
1088
1089 // Compute depth of bounding box center
1090 Standard_Real aMidDepth = (aGraphicMinDist + aGraphicMaxDist) * 0.5;
1091 Standard_Real aHalfDepth = (aGraphicMaxDist - aGraphicMinDist) * 0.5;
1092
1093 // ShortReal precision factor used to add meaningful tolerance to
1094 // ZNear, ZFar values in order to avoid equality after type conversion
1095 // to ShortReal matrices type.
1096 const Standard_Real aPrecision = Pow (0.1, ShortRealDigits() - 2);
1097
1098 // Compute enlarged or shrank near and far z ranges
1099 Standard_Real aZNear = aMidDepth - aHalfDepth * theScaleFactor;
1100 Standard_Real aZFar = aMidDepth + aHalfDepth * theScaleFactor;
1101 aZNear -= aPrecision * 0.5;
1102 aZFar += aPrecision * 0.5;
1103
1104 if (!IsOrthographic())
1105 {
1106 if (aZFar >= aPrecision)
1107 {
1108 // To avoid numeric errors... (See comments in the beginning of the method).
1109 // Choose between model distance and graphical distance, as the model boundaries
1110 // might be infinite if all structures have infinite flag.
1111 const Standard_Real aGraphicDepth = aGraphicMaxDist >= aGraphicMinDist
1112 ? aGraphicMaxDist - aGraphicMinDist : RealLast();
1113
1114 const Standard_Real aModelDepth = aModelMaxDist >= aModelMinDist
1115 ? aModelMaxDist - aModelMinDist : RealLast();
1116
1117 const Standard_Real aMinDepth = Min (aModelDepth, aGraphicDepth);
1118 const Standard_Real aZTolerance =
1119 Max (Abs (aMinDepth) * aPrecision, aPrecision);
1120
1121 if (aZNear < aZTolerance)
1122 {
1123 aZNear = aZTolerance;
1124 }
1125 }
1126 else // aZFar < aPrecision - Invalid case when both ZNear and ZFar are negative
1127 {
1128 aZNear = aPrecision;
1129 aZFar = aPrecision * 2.0;
1130 }
1131 }
1132
1133 // If range is too small
1134 if (aZFar < (aZNear + Abs (aZFar) * aPrecision))
1135 {
1136 aZFar = aZNear + Abs (aZFar) * aPrecision;
1137 }
1138
1139 SetZRange (aZNear, aZFar);
1140}