0025981: Wrong result obtained by projection algorithm.
[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);
ab1c121b 697 Elem_t aDXHalf = 0.0, aDYHalf = 0.0;
b5ac8292 698 if (IsOrthographic())
699 {
ab1c121b 700 aDXHalf = aScale * Elem_t (0.5);
197ac94e 701 aDYHalf = aScale * Elem_t (0.5);
b5ac8292 702 }
703 else
704 {
ab1c121b 705 aDXHalf = aZNear * Elem_t (Tan (DTR_HALF * myFOVy));
197ac94e 706 aDYHalf = aZNear * Elem_t (Tan (DTR_HALF * myFOVy));
b5ac8292 707 }
708
ab1c121b 709 if (anAspect > 1.0)
710 {
711 aDXHalf *= anAspect;
712 }
713 else
714 {
715 aDYHalf /= anAspect;
716 }
717
b5ac8292 718 // sets right of frustum based on aspect ratio
197ac94e 719 Elem_t aLeft = -aDXHalf;
720 Elem_t aRight = aDXHalf;
721 Elem_t aBot = -aDYHalf;
722 Elem_t aTop = aDYHalf;
b5ac8292 723
197ac94e 724 Elem_t aIOD = myIODType == IODType_Relative
725 ? static_cast<Elem_t> (myIOD * Distance())
726 : static_cast<Elem_t> (myIOD);
b5ac8292 727
197ac94e 728 Elem_t aFocus = myZFocusType == FocusType_Relative
729 ? static_cast<Elem_t> (myZFocus * Distance())
730 : static_cast<Elem_t> (myZFocus);
b5ac8292 731
732 switch (myProjType)
733 {
734 case Projection_Orthographic :
197ac94e 735 OrthoProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
b5ac8292 736 break;
737
738 case Projection_Perspective :
197ac94e 739 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
b5ac8292 740 break;
741
742 case Projection_MonoLeftEye :
743 {
197ac94e 744 StereoEyeProj (aLeft, aRight, aBot, aTop,
745 aZNear, aZFar, aIOD, aFocus,
746 Standard_True, *theMatrices.MProjection);
38a0206f 747 *theMatrices.LProjection = *theMatrices.MProjection;
b5ac8292 748 break;
749 }
750
751 case Projection_MonoRightEye :
752 {
197ac94e 753 StereoEyeProj (aLeft, aRight, aBot, aTop,
754 aZNear, aZFar, aIOD, aFocus,
755 Standard_False, *theMatrices.MProjection);
38a0206f 756 *theMatrices.RProjection = *theMatrices.MProjection;
b5ac8292 757 break;
758 }
759
760 case Projection_Stereo :
761 {
197ac94e 762 PerspectiveProj (aLeft, aRight, aBot, aTop, aZNear, aZFar, *theMatrices.MProjection);
b5ac8292 763
197ac94e 764 StereoEyeProj (aLeft, aRight, aBot, aTop,
765 aZNear, aZFar, aIOD, aFocus,
766 Standard_True,
767 *theMatrices.LProjection);
b5ac8292 768
197ac94e 769 StereoEyeProj (aLeft, aRight, aBot, aTop,
770 aZNear, aZFar, aIOD, aFocus,
771 Standard_False,
772 *theMatrices.RProjection);
b5ac8292 773 break;
774 }
775 }
197ac94e 776
777 return theMatrices; // for inline accessors
b5ac8292 778}
779
780// =======================================================================
781// function : UpdateOrientation
782// purpose :
783// =======================================================================
197ac94e 784template <typename Elem_t>
785Graphic3d_Camera::TransformMatrices<Elem_t>&
786 Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
b5ac8292 787{
197ac94e 788 if (theMatrices.IsOrientationValid())
b5ac8292 789 {
197ac94e 790 return theMatrices; // for inline accessors
b5ac8292 791 }
792
197ac94e 793 theMatrices.InitOrientation();
794
795 NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
796 static_cast<Elem_t> (myEye.Y()),
797 static_cast<Elem_t> (myEye.Z()));
798
799 NCollection_Vec3<Elem_t> aCenter (static_cast<Elem_t> (myCenter.X()),
800 static_cast<Elem_t> (myCenter.Y()),
801 static_cast<Elem_t> (myCenter.Z()));
b5ac8292 802
197ac94e 803 NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
804 static_cast<Elem_t> (myUp.Y()),
805 static_cast<Elem_t> (myUp.Z()));
b5ac8292 806
197ac94e 807 NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
808 static_cast<Elem_t> (myAxialScale.Y()),
809 static_cast<Elem_t> (myAxialScale.Z()));
b5ac8292 810
197ac94e 811 LookOrientation (anEye, aCenter, anUp, anAxialScale, *theMatrices.Orientation);
b5ac8292 812
197ac94e 813 return theMatrices; // for inline accessors
814}
b5ac8292 815
197ac94e 816// =======================================================================
817// function : InvalidateProjection
818// purpose :
819// =======================================================================
820void Graphic3d_Camera::InvalidateProjection()
821{
822 myMatricesD.ResetProjection();
823 myMatricesF.ResetProjection();
824 myProjectionState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
825}
b5ac8292 826
197ac94e 827// =======================================================================
828// function : InvalidateOrientation
829// purpose :
830// =======================================================================
831void Graphic3d_Camera::InvalidateOrientation()
832{
833 myMatricesD.ResetOrientation();
834 myMatricesF.ResetOrientation();
835 myOrientationState = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
b5ac8292 836}
837
838// =======================================================================
839// function : OrthoProj
840// purpose :
841// =======================================================================
197ac94e 842template <typename Elem_t>
843void Graphic3d_Camera::OrthoProj (const Elem_t theLeft,
844 const Elem_t theRight,
845 const Elem_t theBottom,
846 const Elem_t theTop,
847 const Elem_t theNear,
848 const Elem_t theFar,
849 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 850{
851 // row 0
197ac94e 852 theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theRight - theLeft);
853 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
854 theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
b5ac8292 855 theOutMx.ChangeValue (0, 3) = - (theRight + theLeft) / (theRight - theLeft);
856
857 // row 1
197ac94e 858 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
859 theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theTop - theBottom);
860 theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
b5ac8292 861 theOutMx.ChangeValue (1, 3) = - (theTop + theBottom) / (theTop - theBottom);
862
863 // row 2
197ac94e 864 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
865 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
866 theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
b5ac8292 867 theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
868
869 // row 3
197ac94e 870 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
871 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
872 theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
873 theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
b5ac8292 874}
875
876// =======================================================================
877// function : PerspectiveProj
878// purpose :
879// =======================================================================
197ac94e 880template <typename Elem_t>
881void Graphic3d_Camera::PerspectiveProj (const Elem_t theLeft,
882 const Elem_t theRight,
883 const Elem_t theBottom,
884 const Elem_t theTop,
885 const Elem_t theNear,
886 const Elem_t theFar,
887 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 888{
889 // column 0
197ac94e 890 theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theRight - theLeft);
891 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
892 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
893 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
b5ac8292 894
895 // column 1
197ac94e 896 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
897 theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theTop - theBottom);
898 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
899 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
b5ac8292 900
901 // column 2
902 theOutMx.ChangeValue (0, 2) = (theRight + theLeft) / (theRight - theLeft);
903 theOutMx.ChangeValue (1, 2) = (theTop + theBottom) / (theTop - theBottom);
904 theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
197ac94e 905 theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
b5ac8292 906
907 // column 3
197ac94e 908 theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
909 theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
910 theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
911 theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
b5ac8292 912}
913
914// =======================================================================
915// function : StereoEyeProj
916// purpose :
917// =======================================================================
197ac94e 918template <typename Elem_t>
919void Graphic3d_Camera::StereoEyeProj (const Elem_t theLeft,
920 const Elem_t theRight,
921 const Elem_t theBottom,
922 const Elem_t theTop,
923 const Elem_t theNear,
924 const Elem_t theFar,
925 const Elem_t theIOD,
926 const Elem_t theZFocus,
927 const Standard_Boolean theIsLeft,
928 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 929{
197ac94e 930 Elem_t aDx = theIsLeft ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
931 Elem_t aDXStereoShift = aDx * theNear / theZFocus;
b5ac8292 932
933 // construct eye projection matrix
934 PerspectiveProj (theLeft + aDXStereoShift,
935 theRight + aDXStereoShift,
936 theBottom, theTop, theNear, theFar,
b5ac8292 937 theOutMx);
938
197ac94e 939 if (theIOD != Elem_t (0.0))
b5ac8292 940 {
941 // X translation to cancel parallax
197ac94e 942 theOutMx.Translate (NCollection_Vec3<Elem_t> (aDx, Elem_t (0.0), Elem_t (0.0)));
b5ac8292 943 }
944}
945
946// =======================================================================
947// function : LookOrientation
948// purpose :
949// =======================================================================
197ac94e 950template <typename Elem_t>
951void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
952 const NCollection_Vec3<Elem_t>& theLookAt,
953 const NCollection_Vec3<Elem_t>& theUpDir,
954 const NCollection_Vec3<Elem_t>& theAxialScale,
955 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 956{
197ac94e 957 NCollection_Vec3<Elem_t> aForward = theLookAt - theEye;
b5ac8292 958 aForward.Normalize();
959
960 // side = forward x up
197ac94e 961 NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
b5ac8292 962 aSide.Normalize();
963
964 // recompute up as: up = side x forward
197ac94e 965 NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
b5ac8292 966
197ac94e 967 NCollection_Mat4<Elem_t> aLookMx;
b5ac8292 968 aLookMx.SetRow (0, aSide);
969 aLookMx.SetRow (1, anUp);
970 aLookMx.SetRow (2, -aForward);
971
197ac94e 972 theOutMx.InitIdentity();
973 theOutMx.Multiply (aLookMx);
b5ac8292 974 theOutMx.Translate (-theEye);
975
197ac94e 976 NCollection_Mat4<Elem_t> anAxialScaleMx;
b5ac8292 977 anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
978 anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
979 anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
980
981 theOutMx.Multiply (anAxialScaleMx);
982}
6bc6a6fc 983
984//=============================================================================
985//function : ZFitAll
986//purpose :
987//=============================================================================
988void Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor, const Bnd_Box& theMinMax, const Bnd_Box& theGraphicBB)
989{
990 Standard_ASSERT_RAISE (theScaleFactor > 0.0, "Zero or negative scale factor is not allowed.");
991
992 // Method changes ZNear and ZFar planes of camera so as to fit the graphical structures
993 // by their real boundaries (computed ignoring infinite flag) into the viewing volume.
994 // In addition to the graphical boundaries, the usual min max used for fitting perspective
995 // camera. To avoid numeric errors for perspective camera the negative ZNear values are
996 // fixed using tolerance distance, relative to boundaries size. The tolerance distance
997 // should be computed using information on boundaries of primary application actors,
998 // (e.g. representing the displayed model) - to ensure that they are not unreasonably clipped.
2157d6ac 999 const Standard_ShortReal anEpsilon = 1e-4f;
6bc6a6fc 1000
ed063270 1001 if (theGraphicBB.IsVoid())
6bc6a6fc 1002 {
35c4a17c 1003 // Precision factor used to add meaningful tolerance to
6bc6a6fc 1004 // ZNear, ZFar values in order to avoid equality after type conversion
1005 // to ShortReal matrices type.
6bc6a6fc 1006
1007 Standard_Real aZFar = Distance() * 3.0;
1008 Standard_Real aZNear = 0.0;
1009
1010 if (!IsOrthographic())
1011 {
35c4a17c 1012 if (aZFar < anEpsilon)
6bc6a6fc 1013 {
35c4a17c 1014 aZNear = anEpsilon;
1015 aZFar = anEpsilon * 2.0;
6bc6a6fc 1016 }
35c4a17c 1017 else if (aZNear < aZFar * anEpsilon)
6bc6a6fc 1018 {
35c4a17c 1019 aZNear = aZFar * anEpsilon;
6bc6a6fc 1020 }
1021 }
1022
1023 SetZRange (aZNear, aZFar);
1024 return;
1025 }
1026
1027 // Measure depth of boundary points from camera eye
ed063270 1028 NCollection_Sequence<gp_Pnt> aPntsToMeasure;
1029
1030 Standard_Real aGraphicBB[6]; // real graphical boundaries (not accounting infinite flag).
1031 theGraphicBB.Get (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2], aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]);
1032
1033 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2]));
1034 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[5]));
1035 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[2]));
1036 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[5]));
1037 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[2]));
1038 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[5]));
1039 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[2]));
1040 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]));
1041
1042 if (!theMinMax.IsVoid() && !theMinMax.IsWhole())
6bc6a6fc 1043 {
ed063270 1044 Standard_Real aMinMax[6]; // applicative min max boundaries
1045 theMinMax.Get (aMinMax[0], aMinMax[1], aMinMax[2], aMinMax[3], aMinMax[4], aMinMax[5]);
1046
1047 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[2]));
1048 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[5]));
1049 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[2]));
1050 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[5]));
1051 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[2]));
1052 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[5]));
1053 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[2]));
1054 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[5]));
1055 }
6bc6a6fc 1056
1057 // Camera eye plane
1058 gp_Dir aCamDir = Direction();
1059 gp_Pnt aCamEye = myEye;
1060 gp_Pln aCamPln (aCamEye, aCamDir);
1061
1062 Standard_Real aModelMinDist = RealLast();
1063 Standard_Real aModelMaxDist = RealFirst();
1064 Standard_Real aGraphicMinDist = RealLast();
1065 Standard_Real aGraphicMaxDist = RealFirst();
1066
1067 const gp_XYZ& anAxialScale = myAxialScale;
1068
1069 // Get minimum and maximum distances to the eye plane
ed063270 1070 Standard_Integer aCounter = 0;
1071 NCollection_Sequence<gp_Pnt>::Iterator aPntIt(aPntsToMeasure);
1072 for (; aPntIt.More(); aPntIt.Next())
6bc6a6fc 1073 {
ed063270 1074 gp_Pnt aMeasurePnt = aPntIt.Value();
6bc6a6fc 1075
1076 aMeasurePnt = gp_Pnt (aMeasurePnt.X() * anAxialScale.X(),
ed063270 1077 aMeasurePnt.Y() * anAxialScale.Y(),
1078 aMeasurePnt.Z() * anAxialScale.Z());
6bc6a6fc 1079
1080 Standard_Real aDistance = aCamPln.Distance (aMeasurePnt);
1081
1082 // Check if the camera is intruded into the scene
1083 if (aCamDir.IsOpposite (gp_Vec (aCamEye, aMeasurePnt), M_PI * 0.5))
1084 {
1085 aDistance *= -1;
1086 }
1087
ed063270 1088 // the first eight points are from theGraphicBB, the last eight points are from theMinMax
1089 // (they can be absent).
1090 Standard_Real& aChangeMinDist = aCounter >= 8 ? aModelMinDist : aGraphicMinDist;
1091 Standard_Real& aChangeMaxDist = aCounter >= 8 ? aModelMaxDist : aGraphicMaxDist;
6bc6a6fc 1092 aChangeMinDist = Min (aDistance, aChangeMinDist);
1093 aChangeMaxDist = Max (aDistance, aChangeMaxDist);
ed063270 1094 aCounter++;
6bc6a6fc 1095 }
1096
1097 // Compute depth of bounding box center
1098 Standard_Real aMidDepth = (aGraphicMinDist + aGraphicMaxDist) * 0.5;
1099 Standard_Real aHalfDepth = (aGraphicMaxDist - aGraphicMinDist) * 0.5;
1100
6bc6a6fc 1101 // Compute enlarged or shrank near and far z ranges
35c4a17c 1102 Standard_Real aZNear = aMidDepth - aHalfDepth * theScaleFactor;
1103 Standard_Real aZFar = aMidDepth + aHalfDepth * theScaleFactor;
1104 Standard_Real aZRange = Abs (aZFar - aZNear);
1105 Standard_Real aZConf = Max (static_cast <Standard_Real> (anEpsilon * aZRange),
1106 static_cast <Standard_Real> (anEpsilon));
1107
1108 aZNear -= Abs (aZNear) * anEpsilon + aZConf;
1109 aZFar += Abs (aZFar) * anEpsilon + aZConf;
6bc6a6fc 1110
1111 if (!IsOrthographic())
1112 {
35c4a17c 1113 if (aZFar > anEpsilon)
6bc6a6fc 1114 {
6bc6a6fc 1115 // Choose between model distance and graphical distance, as the model boundaries
1116 // might be infinite if all structures have infinite flag.
1117 const Standard_Real aGraphicDepth = aGraphicMaxDist >= aGraphicMinDist
1118 ? aGraphicMaxDist - aGraphicMinDist : RealLast();
1119
1120 const Standard_Real aModelDepth = aModelMaxDist >= aModelMinDist
1121 ? aModelMaxDist - aModelMinDist : RealLast();
1122
1123 const Standard_Real aMinDepth = Min (aModelDepth, aGraphicDepth);
35c4a17c 1124 const Standard_Real aZTol = Max (static_cast<Standard_Real> (anEpsilon * Abs (aMinDepth)),
1125 static_cast<Standard_Real> (anEpsilon));
1126 if (aZNear < aZTol)
6bc6a6fc 1127 {
35c4a17c 1128 aZNear = aZTol;
6bc6a6fc 1129 }
1130 }
35c4a17c 1131 else
6bc6a6fc 1132 {
35c4a17c 1133 aZNear = anEpsilon;
1134 aZFar = anEpsilon * 2.0;
6bc6a6fc 1135 }
1136 }
1137
35c4a17c 1138 if (aZFar < (aZNear + Abs (aZFar) * anEpsilon))
6bc6a6fc 1139 {
35c4a17c 1140 aZFar = aZNear + Abs (aZFar) * anEpsilon;
6bc6a6fc 1141 }
1142
1143 SetZRange (aZNear, aZFar);
1144}