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