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