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