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