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