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