0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[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
ea764884 42 // z-range tolerance compatible with for floating point.
43 static Standard_Real zEpsilon()
44 {
45 return FLT_EPSILON;
46 }
47
48 // relative z-range tolerance compatible with for floating point.
49 static Standard_Real zEpsilon (const Standard_Real theValue)
50 {
5c8908e0 51 Standard_Real anAbsValue = Abs (theValue);
52 if (anAbsValue <= (double)FLT_MIN)
825aa485 53 {
5c8908e0 54 return FLT_MIN;
825aa485 55 }
5c8908e0 56 Standard_Real aLogRadix = Log10 (anAbsValue) / Log10 (FLT_RADIX);
ea764884 57 Standard_Real aExp = Floor (aLogRadix);
58 return FLT_EPSILON * Pow (FLT_RADIX, aExp);
a3f6f591 59 }
1beb58d7 60
61 //! Convert camera definition to Ax3
62 gp_Ax3 cameraToAx3 (const Graphic3d_Camera& theCamera)
63 {
607e5e62 64 const gp_Dir aBackDir = -theCamera.Direction();
1beb58d7 65 const gp_Dir anXAxis (theCamera.Up().Crossed (aBackDir));
66 const gp_Dir anYAxis (aBackDir .Crossed (anXAxis));
67 const gp_Dir aZAxis (anXAxis .Crossed (anYAxis));
68 return gp_Ax3 (gp_Pnt (0.0, 0.0, 0.0), aZAxis, anXAxis);
69 }
a3f6f591 70}
b5ac8292 71
72// =======================================================================
73// function : Graphic3d_Camera
74// purpose :
75// =======================================================================
76Graphic3d_Camera::Graphic3d_Camera()
77: myUp (0.0, 1.0, 0.0),
607e5e62 78 myDirection (0.0, 0.0, 1.0),
b5ac8292 79 myEye (0.0, 0.0, -1500.0),
607e5e62 80 myDistance (1500.0),
b5ac8292 81 myAxialScale (1.0, 1.0, 1.0),
82 myProjType (Projection_Orthographic),
83 myFOVy (45.0),
b40cdc2b 84 myFOVx (45.0),
85 myFOV2d (180.0),
778cd667 86 myFOVyTan (Tan (DTR_HALF * 45.0)),
197ac94e 87 myZNear (DEFAULT_ZNEAR),
88 myZFar (DEFAULT_ZFAR),
b5ac8292 89 myAspect (1.0),
e70625d6 90 myIsZeroToOneDepth (false),
b5ac8292 91 myScale (1000.0),
92 myZFocus (1.0),
93 myZFocusType (FocusType_Relative),
94 myIOD (0.05),
b40cdc2b 95 myIODType (IODType_Relative),
96 myIsCustomProjMatM (false),
97 myIsCustomProjMatLR(false),
98 myIsCustomFrustomLR(false)
b5ac8292 99{
825aa485 100 myWorldViewProjState.Initialize ((Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
101 (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER),
102 this);
b5ac8292 103}
104
105// =======================================================================
106// function : Graphic3d_Camera
107// purpose :
108// =======================================================================
109Graphic3d_Camera::Graphic3d_Camera (const Handle(Graphic3d_Camera)& theOther)
c55c8fe9 110: myUp (0.0, 1.0, 0.0),
607e5e62 111 myDirection (0.0, 0.0, 1.0),
c55c8fe9 112 myEye (0.0, 0.0, -1500.0),
607e5e62 113 myDistance (1500.0),
c55c8fe9 114 myAxialScale (1.0, 1.0, 1.0),
115 myProjType (Projection_Orthographic),
116 myFOVy (45.0),
b40cdc2b 117 myFOVx (45.0),
118 myFOV2d (180.0),
c55c8fe9 119 myFOVyTan (Tan (DTR_HALF * 45.0)),
120 myZNear (DEFAULT_ZNEAR),
121 myZFar (DEFAULT_ZFAR),
122 myAspect (1.0),
e70625d6 123 myIsZeroToOneDepth (false),
c55c8fe9 124 myScale (1000.0),
125 myZFocus (1.0),
126 myZFocusType (FocusType_Relative),
127 myIOD (0.05),
b40cdc2b 128 myIODType (IODType_Relative),
129 myIsCustomProjMatM (false),
130 myIsCustomProjMatLR(false),
131 myIsCustomFrustomLR(false)
b5ac8292 132{
825aa485 133 myWorldViewProjState.Initialize (this);
134
b5ac8292 135 Copy (theOther);
136}
137
138// =======================================================================
139// function : CopyMappingData
140// purpose :
141// =======================================================================
142void Graphic3d_Camera::CopyMappingData (const Handle(Graphic3d_Camera)& theOtherCamera)
143{
e70625d6 144 SetZeroToOneDepth (theOtherCamera->IsZeroToOneDepth());
7e251883 145 SetProjectionType (theOtherCamera->ProjectionType());
bf02aa7d 146 SetFOVy (theOtherCamera->FOVy());
b40cdc2b 147 SetFOV2d (theOtherCamera->FOV2d());
bf02aa7d 148 SetZRange (theOtherCamera->ZNear(), theOtherCamera->ZFar());
149 SetAspect (theOtherCamera->Aspect());
150 SetScale (theOtherCamera->Scale());
151 SetZFocus (theOtherCamera->ZFocusType(), theOtherCamera->ZFocus());
152 SetIOD (theOtherCamera->GetIODType(), theOtherCamera->IOD());
3bffef55 153 SetTile (theOtherCamera->myTile);
b40cdc2b 154
155 ResetCustomProjection();
156 if (theOtherCamera->IsCustomStereoProjection())
157 {
cdc54fb0 158 SetCustomStereoProjection (theOtherCamera->myCustomProjMatL,
159 theOtherCamera->myCustomHeadToEyeMatL,
160 theOtherCamera->myCustomProjMatR,
161 theOtherCamera->myCustomHeadToEyeMatR);
b40cdc2b 162 }
163 else if (theOtherCamera->IsCustomStereoFrustum())
164 {
165 SetCustomStereoFrustums (theOtherCamera->myCustomFrustumL, theOtherCamera->myCustomFrustumR);
166 }
167 if (theOtherCamera->IsCustomMonoProjection())
168 {
169 SetCustomMonoProjection (theOtherCamera->myCustomProjMatM);
170 }
b5ac8292 171}
172
173// =======================================================================
174// function : CopyOrientationData
175// purpose :
176// =======================================================================
177void Graphic3d_Camera::CopyOrientationData (const Handle(Graphic3d_Camera)& theOtherCamera)
178{
607e5e62 179 if (!myEye.IsEqual (theOtherCamera->Eye(), 0.0)
180 || !myUp.IsEqual (theOtherCamera->Up(), 0.0)
181 || !myDirection.IsEqual (theOtherCamera->Direction(), 0.0)
182 || myDistance != theOtherCamera->Distance())
183 {
184 myEye = theOtherCamera->Eye();
185 myUp = theOtherCamera->Up();
186 myDirection = theOtherCamera->Direction();
187 myDistance = theOtherCamera->Distance();
188 InvalidateOrientation();
189 }
bf02aa7d 190 SetAxialScale (theOtherCamera->AxialScale());
b5ac8292 191}
192
193// =======================================================================
194// function : Copy
195// purpose :
196// =======================================================================
197void Graphic3d_Camera::Copy (const Handle(Graphic3d_Camera)& theOther)
198{
b5ac8292 199 CopyMappingData (theOther);
200 CopyOrientationData (theOther);
b5ac8292 201}
202
51d4a4f9 203// =======================================================================
204// function : SetIdentityOrientation
205// purpose :
206// =======================================================================
207void Graphic3d_Camera::SetIdentityOrientation()
208{
209 SetEyeAndCenter (gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(0.0, 0.0, -1.0));
210 SetUp (gp_Dir(0.0, 1.0, 0.0));
211}
212
607e5e62 213// =======================================================================
214// function : MoveEyeTo
215// purpose :
216// =======================================================================
217void Graphic3d_Camera::MoveEyeTo (const gp_Pnt& theEye)
218{
219 if (myEye.IsEqual (theEye, 0.0))
220 {
221 return;
222 }
223
224 myEye = theEye;
225 InvalidateOrientation();
226}
227
228// =======================================================================
229// function : SetEyeAndCenter
230// purpose :
231// =======================================================================
232void Graphic3d_Camera::SetEyeAndCenter (const gp_Pnt& theEye,
233 const gp_Pnt& theCenter)
234{
235 if (Eye() .IsEqual (theEye, 0.0)
236 && Center().IsEqual (theCenter, 0.0))
237 {
238 return;
239 }
240
241 myEye = theEye;
242 myDistance = theEye.Distance (theCenter);
243 if (myDistance > gp::Resolution())
244 {
245 myDirection = gp_Dir (theCenter.XYZ() - theEye.XYZ());
246 }
247 InvalidateOrientation();
248}
249
b5ac8292 250// =======================================================================
251// function : SetEye
252// purpose :
253// =======================================================================
254void Graphic3d_Camera::SetEye (const gp_Pnt& theEye)
255{
bf02aa7d 256 if (Eye().IsEqual (theEye, 0.0))
257 {
258 return;
259 }
260
607e5e62 261 const gp_Pnt aCenter = Center();
b5ac8292 262 myEye = theEye;
607e5e62 263 myDistance = myEye.Distance (aCenter);
264 if (myDistance > gp::Resolution())
265 {
266 myDirection = gp_Dir (aCenter.XYZ() - myEye.XYZ());
267 }
197ac94e 268 InvalidateOrientation();
b5ac8292 269}
270
271// =======================================================================
272// function : SetCenter
273// purpose :
274// =======================================================================
275void Graphic3d_Camera::SetCenter (const gp_Pnt& theCenter)
276{
607e5e62 277 const Standard_Real aDistance = myEye.Distance (theCenter);
278 if (myDistance == aDistance)
bf02aa7d 279 {
280 return;
281 }
282
607e5e62 283 myDistance = aDistance;
284 if (myDistance > gp::Resolution())
285 {
286 myDirection = gp_Dir (theCenter.XYZ() - myEye.XYZ());
287 }
197ac94e 288 InvalidateOrientation();
b5ac8292 289}
290
291// =======================================================================
292// function : SetUp
293// purpose :
294// =======================================================================
295void Graphic3d_Camera::SetUp (const gp_Dir& theUp)
296{
bf02aa7d 297 if (Up().IsEqual (theUp, 0.0))
298 {
299 return;
300 }
301
b5ac8292 302 myUp = theUp;
197ac94e 303 InvalidateOrientation();
b5ac8292 304}
305
306// =======================================================================
307// function : SetAxialScale
308// purpose :
309// =======================================================================
197ac94e 310void Graphic3d_Camera::SetAxialScale (const gp_XYZ& theAxialScale)
b5ac8292 311{
bf02aa7d 312 if (AxialScale().IsEqual (theAxialScale, 0.0))
313 {
314 return;
315 }
316
b5ac8292 317 myAxialScale = theAxialScale;
197ac94e 318 InvalidateOrientation();
b5ac8292 319}
320
321// =======================================================================
322// function : SetDistance
323// purpose :
324// =======================================================================
325void Graphic3d_Camera::SetDistance (const Standard_Real theDistance)
326{
607e5e62 327 if (myDistance == theDistance)
bf02aa7d 328 {
329 return;
330 }
331
607e5e62 332 const gp_Pnt aCenter = Center();
333 myDistance = theDistance;
334 myEye = aCenter.XYZ() - myDirection.XYZ() * myDistance;
335 InvalidateOrientation();
b5ac8292 336}
337
338// =======================================================================
607e5e62 339// function : SetDirectionFromEye
b5ac8292 340// purpose :
341// =======================================================================
607e5e62 342void Graphic3d_Camera::SetDirectionFromEye (const gp_Dir& theDir)
b5ac8292 343{
607e5e62 344 if (myDirection.IsEqual (theDir, 0.0))
345 {
346 return;
347 }
348
349 myDirection = theDir;
350 InvalidateOrientation();
b5ac8292 351}
352
353// =======================================================================
354// function : SetDirection
355// purpose :
356// =======================================================================
357void Graphic3d_Camera::SetDirection (const gp_Dir& theDir)
358{
607e5e62 359 if (myDirection.IsEqual (theDir, 0.0))
bf02aa7d 360 {
361 return;
362 }
363
607e5e62 364 const gp_Pnt aCenter = Center();
365 myDirection = theDir;
366 myEye = aCenter.XYZ() - theDir.XYZ() * myDistance;
367 InvalidateOrientation();
b5ac8292 368}
369
370// =======================================================================
371// function : SetScale
372// purpose :
373// =======================================================================
374void Graphic3d_Camera::SetScale (const Standard_Real theScale)
375{
c357e426 376 if (Scale() == theScale)
377 {
378 return;
379 }
380
b5ac8292 381 myScale = theScale;
382
383 switch (myProjType)
384 {
385 case Projection_Perspective :
386 case Projection_Stereo :
387 case Projection_MonoLeftEye :
388 case Projection_MonoRightEye :
389 {
778cd667 390 Standard_Real aDistance = theScale * 0.5 / myFOVyTan;
b5ac8292 391 SetDistance (aDistance);
392 }
393
394 default :
395 break;
396 }
397
197ac94e 398 InvalidateProjection();
b5ac8292 399}
400
401// =======================================================================
402// function : Scale
403// purpose :
404// =======================================================================
405Standard_Real Graphic3d_Camera::Scale() const
406{
407 switch (myProjType)
408 {
409 case Projection_Orthographic :
410 return myScale;
411
412 // case Projection_Perspective :
413 // case Projection_Stereo :
414 // case Projection_MonoLeftEye :
415 // case Projection_MonoRightEye :
416 default :
778cd667 417 return Distance() * 2.0 * myFOVyTan;
b5ac8292 418 }
419}
420
421// =======================================================================
422// function : SetProjectionType
423// purpose :
424// =======================================================================
425void Graphic3d_Camera::SetProjectionType (const Projection theProjectionType)
426{
c357e426 427 Projection anOldType = ProjectionType();
b5ac8292 428
429 if (anOldType == theProjectionType)
430 {
431 return;
432 }
433
197ac94e 434 if (anOldType == Projection_Orthographic)
b5ac8292 435 {
197ac94e 436 if (myZNear <= RealEpsilon())
437 {
438 myZNear = DEFAULT_ZNEAR;
439 }
440 if (myZFar <= RealEpsilon())
441 {
442 myZFar = DEFAULT_ZFAR;
443 }
b5ac8292 444 }
445
197ac94e 446 myProjType = theProjectionType;
447
448 InvalidateProjection();
b5ac8292 449}
450
451// =======================================================================
452// function : SetFOVy
453// purpose :
454// =======================================================================
455void Graphic3d_Camera::SetFOVy (const Standard_Real theFOVy)
456{
c357e426 457 if (FOVy() == theFOVy)
458 {
459 return;
460 }
461
b5ac8292 462 myFOVy = theFOVy;
b40cdc2b 463 myFOVx = theFOVy * myAspect;
778cd667 464 myFOVyTan = Tan(DTR_HALF * myFOVy);
c357e426 465
197ac94e 466 InvalidateProjection();
b5ac8292 467}
468
b40cdc2b 469// =======================================================================
470// function : SetFOV2d
471// purpose :
472// =======================================================================
473void Graphic3d_Camera::SetFOV2d (const Standard_Real theFOV)
474{
475 if (FOV2d() == theFOV)
476 {
477 return;
478 }
479
480 myFOV2d = theFOV;
481 InvalidateProjection();
482}
483
b5ac8292 484// =======================================================================
197ac94e 485// function : SetZRange
b5ac8292 486// purpose :
487// =======================================================================
197ac94e 488void Graphic3d_Camera::SetZRange (const Standard_Real theZNear,
489 const Standard_Real theZFar)
b5ac8292 490{
197ac94e 491 Standard_ASSERT_RAISE (theZFar > theZNear, "ZFar should be greater than ZNear");
492 if (!IsOrthographic())
b5ac8292 493 {
197ac94e 494 Standard_ASSERT_RAISE (theZNear > 0.0, "Only positive Z-Near is allowed for perspective camera");
495 Standard_ASSERT_RAISE (theZFar > 0.0, "Only positive Z-Far is allowed for perspective camera");
b5ac8292 496 }
497
c357e426 498 if (ZNear() == theZNear
499 && ZFar () == theZFar)
500 {
501 return;
502 }
503
197ac94e 504 myZNear = theZNear;
505 myZFar = theZFar;
b5ac8292 506
197ac94e 507 InvalidateProjection();
b5ac8292 508}
509
510// =======================================================================
511// function : SetAspect
512// purpose :
513// =======================================================================
514void Graphic3d_Camera::SetAspect (const Standard_Real theAspect)
515{
c357e426 516 if (Aspect() == theAspect)
517 {
518 return;
519 }
520
b5ac8292 521 myAspect = theAspect;
b40cdc2b 522 myFOVx = myFOVy * theAspect;
c357e426 523
197ac94e 524 InvalidateProjection();
b5ac8292 525}
526
527// =======================================================================
528// function : SetZFocus
529// purpose :
530// =======================================================================
531void Graphic3d_Camera::SetZFocus(const FocusType theType, const Standard_Real theZFocus)
532{
c357e426 533 if (ZFocusType() == theType
534 && ZFocus () == theZFocus)
535 {
536 return;
537 }
538
b5ac8292 539 myZFocusType = theType;
c357e426 540 myZFocus = theZFocus;
541
197ac94e 542 InvalidateProjection();
b5ac8292 543}
544
545// =======================================================================
546// function : SetIOD
547// purpose :
548// =======================================================================
549void Graphic3d_Camera::SetIOD (const IODType theType, const Standard_Real theIOD)
550{
bf02aa7d 551 if (GetIODType() == theType
552 && IOD () == theIOD)
c357e426 553 {
554 return;
555 }
556
b5ac8292 557 myIODType = theType;
c357e426 558 myIOD = theIOD;
559
197ac94e 560 InvalidateProjection();
b5ac8292 561}
562
3bffef55 563// =======================================================================
564// function : SetTile
565// purpose :
566// =======================================================================
567void Graphic3d_Camera::SetTile (const Graphic3d_CameraTile& theTile)
568{
569 if (myTile == theTile)
570 {
571 return;
572 }
573
574 myTile = theTile;
575 InvalidateProjection();
576}
577
b5ac8292 578// =======================================================================
579// function : OrthogonalizeUp
580// purpose :
581// =======================================================================
582void Graphic3d_Camera::OrthogonalizeUp()
583{
197ac94e 584 SetUp (OrthogonalizedUp());
b5ac8292 585}
586
587// =======================================================================
197ac94e 588// function : OrthogonalizedUp
b5ac8292 589// purpose :
590// =======================================================================
197ac94e 591gp_Dir Graphic3d_Camera::OrthogonalizedUp() const
b5ac8292 592{
197ac94e 593 gp_Dir aDir = Direction();
594 gp_Dir aLeft = aDir.Crossed (Up());
b5ac8292 595
197ac94e 596 // recompute up as: up = left x direction
597 return aLeft.Crossed (aDir);
b5ac8292 598}
599
600// =======================================================================
601// function : Transform
602// purpose :
603// =======================================================================
604void Graphic3d_Camera::Transform (const gp_Trsf& theTrsf)
605{
bf02aa7d 606 if (theTrsf.Form() == gp_Identity)
607 {
608 return;
609 }
610
607e5e62 611 myUp .Transform (theTrsf);
612 myDirection.Transform (theTrsf);
613 myEye.Transform (theTrsf);
614 InvalidateOrientation();
b5ac8292 615}
616
617// =======================================================================
618// function : safePointCast
619// purpose :
620// =======================================================================
197ac94e 621static Graphic3d_Vec4d safePointCast (const gp_Pnt& thePnt)
b5ac8292 622{
623 Standard_Real aLim = 1e15f;
197ac94e 624
b5ac8292 625 // have to deal with values greater then max float
626 gp_Pnt aSafePoint = thePnt;
627 const Standard_Real aBigFloat = aLim * 0.1f;
628 if (Abs (aSafePoint.X()) > aLim)
629 aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
630 if (Abs (aSafePoint.Y()) > aLim)
631 aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
632 if (Abs (aSafePoint.Z()) > aLim)
633 aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
634
635 // convert point
197ac94e 636 Graphic3d_Vec4d aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
b5ac8292 637
638 return aPnt;
639}
640
641// =======================================================================
642// function : Project
643// purpose :
644// =======================================================================
645gp_Pnt Graphic3d_Camera::Project (const gp_Pnt& thePnt) const
646{
197ac94e 647 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
648 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 649
650 // use compatible type of point
197ac94e 651 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 652
653 aPnt = aViewMx * aPnt; // convert to view coordinate space
654 aPnt = aProjMx * aPnt; // convert to projection coordinate space
655
656 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
657
658 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
659}
660
661// =======================================================================
662// function : UnProject
663// purpose :
664// =======================================================================
665gp_Pnt Graphic3d_Camera::UnProject (const gp_Pnt& thePnt) const
666{
197ac94e 667 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
668 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 669
197ac94e 670 Graphic3d_Mat4d aInvView;
671 Graphic3d_Mat4d aInvProj;
b5ac8292 672
673 // this case should never happen
674 if (!aViewMx.Inverted (aInvView) || !aProjMx.Inverted (aInvProj))
675 {
676 return gp_Pnt (0.0, 0.0, 0.0);
677 }
678
679 // use compatible type of point
197ac94e 680 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 681
682 aPnt = aInvProj * aPnt; // convert to view coordinate space
683 aPnt = aInvView * aPnt; // convert to world coordinate space
684
685 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
686
687 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
688}
689
690// =======================================================================
691// function : ConvertView2Proj
692// purpose :
693// =======================================================================
694gp_Pnt Graphic3d_Camera::ConvertView2Proj (const gp_Pnt& thePnt) const
695{
197ac94e 696 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 697
698 // use compatible type of point
197ac94e 699 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 700
701 aPnt = aProjMx * aPnt; // convert to projection coordinate space
702
703 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
704
705 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
706}
707
708// =======================================================================
709// function : ConvertProj2View
710// purpose :
711// =======================================================================
712gp_Pnt Graphic3d_Camera::ConvertProj2View (const gp_Pnt& thePnt) const
713{
197ac94e 714 const Graphic3d_Mat4d& aProjMx = ProjectionMatrix();
b5ac8292 715
197ac94e 716 Graphic3d_Mat4d aInvProj;
b5ac8292 717
718 // this case should never happen, but...
719 if (!aProjMx.Inverted (aInvProj))
720 {
197ac94e 721 return gp_Pnt (0, 0, 0);
b5ac8292 722 }
723
724 // use compatible type of point
197ac94e 725 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 726
727 aPnt = aInvProj * aPnt; // convert to view coordinate space
728
729 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
730
731 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
732}
733
734// =======================================================================
735// function : ConvertWorld2View
736// purpose :
737// =======================================================================
738gp_Pnt Graphic3d_Camera::ConvertWorld2View (const gp_Pnt& thePnt) const
739{
197ac94e 740 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
b5ac8292 741
742 // use compatible type of point
197ac94e 743 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 744
745 aPnt = aViewMx * aPnt; // convert to view coordinate space
746
747 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
748
749 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
750}
751
752// =======================================================================
753// function : ConvertView2World
754// purpose :
755// =======================================================================
756gp_Pnt Graphic3d_Camera::ConvertView2World (const gp_Pnt& thePnt) const
757{
197ac94e 758 const Graphic3d_Mat4d& aViewMx = OrientationMatrix();
b5ac8292 759
197ac94e 760 Graphic3d_Mat4d aInvView;
b5ac8292 761
762 if (!aViewMx.Inverted (aInvView))
763 {
764 return gp_Pnt(0, 0, 0);
765 }
766
767 // use compatible type of point
197ac94e 768 Graphic3d_Vec4d aPnt = safePointCast (thePnt);
b5ac8292 769
770 aPnt = aInvView * aPnt; // convert to world coordinate space
771
772 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
773
774 return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
775}
776
777// =======================================================================
778// function : ViewDimensions
779// purpose :
780// =======================================================================
3fe9ce0e 781gp_XYZ Graphic3d_Camera::ViewDimensions (const Standard_Real theZValue) const
b5ac8292 782{
783 // view plane dimensions
778cd667 784 Standard_Real aSize = IsOrthographic() ? myScale : (2.0 * theZValue * myFOVyTan);
539d3a1b 785 Standard_Real aSizeX, aSizeY;
786 if (myAspect > 1.0)
787 {
788 aSizeX = aSize * myAspect;
789 aSizeY = aSize;
790 }
791 else
792 {
793 aSizeX = aSize;
794 aSizeY = aSize / myAspect;
795 }
b5ac8292 796
797 // and frustum depth
197ac94e 798 return gp_XYZ (aSizeX, aSizeY, myZFar - myZNear);
b5ac8292 799}
800
801// =======================================================================
197ac94e 802// function : Frustum
b5ac8292 803// purpose :
804// =======================================================================
197ac94e 805void Graphic3d_Camera::Frustum (gp_Pln& theLeft,
806 gp_Pln& theRight,
807 gp_Pln& theBottom,
808 gp_Pln& theTop,
809 gp_Pln& theNear,
810 gp_Pln& theFar) const
b5ac8292 811{
197ac94e 812 gp_Vec aProjection = gp_Vec (Direction());
813 gp_Vec anUp = OrthogonalizedUp();
814 gp_Vec aSide = aProjection ^ anUp;
815
816 Standard_ASSERT_RAISE (
817 !aProjection.IsParallel (anUp, Precision::Angular()),
818 "Can not derive SIDE = PROJ x UP - directions are parallel");
819
820 theNear = gp_Pln (Eye().Translated (aProjection * ZNear()), aProjection);
821 theFar = gp_Pln (Eye().Translated (aProjection * ZFar()), -aProjection);
822
a4d594cb 823 Standard_Real aHScaleHor = 0.0, aHScaleVer = 0.0;
824 if (Aspect() >= 1.0)
825 {
826 aHScaleHor = Scale() * 0.5 * Aspect();
827 aHScaleVer = Scale() * 0.5;
828 }
829 else
830 {
831 aHScaleHor = Scale() * 0.5;
832 aHScaleVer = Scale() * 0.5 / Aspect();
833 }
197ac94e 834
835 gp_Pnt aPntLeft = Center().Translated (aHScaleHor * -aSide);
836 gp_Pnt aPntRight = Center().Translated (aHScaleHor * aSide);
837 gp_Pnt aPntBottom = Center().Translated (aHScaleVer * -anUp);
838 gp_Pnt aPntTop = Center().Translated (aHScaleVer * anUp);
839
840 gp_Vec aDirLeft = aSide;
841 gp_Vec aDirRight = -aSide;
842 gp_Vec aDirBottom = anUp;
843 gp_Vec aDirTop = -anUp;
844 if (!IsOrthographic())
845 {
846 Standard_Real aHFOVHor = ATan (Tan (DTR_HALF * FOVy()) * Aspect());
847 Standard_Real aHFOVVer = DTR_HALF * FOVy();
848 aDirLeft.Rotate (gp_Ax1 (gp::Origin(), anUp), aHFOVHor);
849 aDirRight.Rotate (gp_Ax1 (gp::Origin(), anUp), -aHFOVHor);
850 aDirBottom.Rotate (gp_Ax1 (gp::Origin(), aSide), -aHFOVVer);
851 aDirTop.Rotate (gp_Ax1 (gp::Origin(), aSide), aHFOVVer);
852 }
853
854 theLeft = gp_Pln (aPntLeft, aDirLeft);
855 theRight = gp_Pln (aPntRight, aDirRight);
856 theBottom = gp_Pln (aPntBottom, aDirBottom);
857 theTop = gp_Pln (aPntTop, aDirTop);
858}
859
860// =======================================================================
861// function : OrientationMatrix
862// purpose :
863// =======================================================================
864const Graphic3d_Mat4d& Graphic3d_Camera::OrientationMatrix() const
865{
778cd667 866 return UpdateOrientation (myMatricesD).Orientation;
197ac94e 867}
868
869// =======================================================================
870// function : OrientationMatrixF
871// purpose :
872// =======================================================================
873const Graphic3d_Mat4& Graphic3d_Camera::OrientationMatrixF() const
874{
778cd667 875 return UpdateOrientation (myMatricesF).Orientation;
197ac94e 876}
877
878// =======================================================================
879// function : ProjectionMatrix
880// purpose :
881// =======================================================================
882const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionMatrix() const
883{
778cd667 884 return UpdateProjection (myMatricesD).MProjection;
197ac94e 885}
886
887// =======================================================================
888// function : ProjectionMatrixF
889// purpose :
890// =======================================================================
891const Graphic3d_Mat4& Graphic3d_Camera::ProjectionMatrixF() const
892{
778cd667 893 return UpdateProjection (myMatricesF).MProjection;
197ac94e 894}
895
896// =======================================================================
897// function : ProjectionStereoLeft
898// purpose :
899// =======================================================================
900const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoLeft() const
901{
778cd667 902 return UpdateProjection (myMatricesD).LProjection;
197ac94e 903}
904
905// =======================================================================
906// function : ProjectionStereoLeftF
907// purpose :
908// =======================================================================
909const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoLeftF() const
910{
778cd667 911 return UpdateProjection (myMatricesF).LProjection;
197ac94e 912}
913
914// =======================================================================
915// function : ProjectionStereoRight
916// purpose :
917// =======================================================================
918const Graphic3d_Mat4d& Graphic3d_Camera::ProjectionStereoRight() const
919{
778cd667 920 return UpdateProjection (myMatricesD).RProjection;
197ac94e 921}
922
923// =======================================================================
924// function : ProjectionStereoRightF
925// purpose :
926// =======================================================================
927const Graphic3d_Mat4& Graphic3d_Camera::ProjectionStereoRightF() const
928{
778cd667 929 return UpdateProjection (myMatricesF).RProjection;
b5ac8292 930}
931
b40cdc2b 932// =======================================================================
933// function : ResetCustomProjection
934// purpose :
935// =======================================================================
936void Graphic3d_Camera::ResetCustomProjection()
937{
938 if (myIsCustomFrustomLR
939 || myIsCustomProjMatLR
940 || myIsCustomProjMatM)
941 {
942 myIsCustomFrustomLR = false;
943 myIsCustomProjMatLR = false;
944 myIsCustomProjMatM = false;
945 InvalidateProjection();
946 }
947}
948
cdc54fb0 949// =======================================================================
950// function : StereoProjection
951// purpose :
952// =======================================================================
953void Graphic3d_Camera::StereoProjection (Graphic3d_Mat4d& theProjL,
954 Graphic3d_Mat4d& theHeadToEyeL,
955 Graphic3d_Mat4d& theProjR,
956 Graphic3d_Mat4d& theHeadToEyeR) const
957{
958 stereoProjection (theProjL, theHeadToEyeL, theProjR, theHeadToEyeR);
959}
960
961// =======================================================================
962// function : StereoProjectionF
963// purpose :
964// =======================================================================
965void Graphic3d_Camera::StereoProjectionF (Graphic3d_Mat4& theProjL,
966 Graphic3d_Mat4& theHeadToEyeL,
967 Graphic3d_Mat4& theProjR,
968 Graphic3d_Mat4& theHeadToEyeR) const
969{
970 stereoProjection (theProjL, theHeadToEyeL, theProjR, theHeadToEyeR);
971}
972
973// =======================================================================
974// function : stereoProjection
975// purpose :
976// =======================================================================
977template <typename Elem_t>
978void Graphic3d_Camera::stereoProjection (NCollection_Mat4<Elem_t>& theProjL,
979 NCollection_Mat4<Elem_t>& theHeadToEyeL,
980 NCollection_Mat4<Elem_t>& theProjR,
981 NCollection_Mat4<Elem_t>& theHeadToEyeR) const
982{
983 if (myIsCustomProjMatLR)
984 {
985 theProjL .ConvertFrom (myCustomProjMatL);
986 theHeadToEyeL.ConvertFrom (myCustomHeadToEyeMatL);
987 theProjR .ConvertFrom (myCustomProjMatR);
988 theHeadToEyeR.ConvertFrom (myCustomHeadToEyeMatR);
989 return;
990 }
991
992 NCollection_Mat4<Elem_t> aDummy;
993 computeProjection (aDummy, theProjL, theProjR, false);
994
995 const Standard_Real aIOD = myIODType == IODType_Relative
996 ? myIOD * Distance()
997 : myIOD;
998 if (aIOD != 0.0)
999 {
1000 // X translation to cancel parallax
1001 theHeadToEyeL.InitIdentity();
1002 theHeadToEyeL.SetColumn (3, NCollection_Vec3<Elem_t> (Elem_t ( 0.5 * aIOD), Elem_t (0.0), Elem_t (0.0)));
1003 theHeadToEyeR.InitIdentity();
1004 theHeadToEyeR.SetColumn (3, NCollection_Vec3<Elem_t> (Elem_t (-0.5 * aIOD), Elem_t (0.0), Elem_t (0.0)));
1005 }
1006}
1007
b40cdc2b 1008// =======================================================================
1009// function : SetCustomStereoFrustums
1010// purpose :
1011// =======================================================================
1012void Graphic3d_Camera::SetCustomStereoFrustums (const Aspect_FrustumLRBT<Standard_Real>& theFrustumL,
1013 const Aspect_FrustumLRBT<Standard_Real>& theFrustumR)
1014{
1015 myCustomFrustumL = theFrustumL;
1016 myCustomFrustumR = theFrustumR;
1017 myIsCustomFrustomLR = true;
1018 myIsCustomProjMatLR = false;
1019 InvalidateProjection();
1020}
1021
1022// =======================================================================
1023// function : SetCustomStereoProjection
1024// purpose :
1025// =======================================================================
1026void Graphic3d_Camera::SetCustomStereoProjection (const Graphic3d_Mat4d& theProjL,
cdc54fb0 1027 const Graphic3d_Mat4d& theHeadToEyeL,
1028 const Graphic3d_Mat4d& theProjR,
1029 const Graphic3d_Mat4d& theHeadToEyeR)
b40cdc2b 1030{
1031 myCustomProjMatL = theProjL;
1032 myCustomProjMatR = theProjR;
cdc54fb0 1033 myCustomHeadToEyeMatL = theHeadToEyeL;
1034 myCustomHeadToEyeMatR = theHeadToEyeR;
b40cdc2b 1035 myIsCustomProjMatLR = true;
1036 myIsCustomFrustomLR = false;
1037 InvalidateProjection();
1038}
1039
1040// =======================================================================
1041// function : SetCustomMonoProjection
1042// purpose :
1043// =======================================================================
1044void Graphic3d_Camera::SetCustomMonoProjection (const Graphic3d_Mat4d& theProj)
1045{
1046 myCustomProjMatM = theProj;
1047 myIsCustomProjMatM = true;
1048 InvalidateProjection();
1049}
1050
b5ac8292 1051// =======================================================================
cdc54fb0 1052// function : computeProjection
b5ac8292 1053// purpose :
1054// =======================================================================
197ac94e 1055template <typename Elem_t>
cdc54fb0 1056void Graphic3d_Camera::computeProjection (NCollection_Mat4<Elem_t>& theProjM,
1057 NCollection_Mat4<Elem_t>& theProjL,
1058 NCollection_Mat4<Elem_t>& theProjR,
1059 bool theToAddHeadToEye) const
b5ac8292 1060{
cdc54fb0 1061 theProjM.InitIdentity();
1062 theProjL.InitIdentity();
1063 theProjR.InitIdentity();
b5ac8292 1064
1065 // sets top of frustum based on FOVy and near clipping plane
197ac94e 1066 Elem_t aScale = static_cast<Elem_t> (myScale);
1067 Elem_t aZNear = static_cast<Elem_t> (myZNear);
1068 Elem_t aZFar = static_cast<Elem_t> (myZFar);
1069 Elem_t anAspect = static_cast<Elem_t> (myAspect);
ab1c121b 1070 Elem_t aDXHalf = 0.0, aDYHalf = 0.0;
b5ac8292 1071 if (IsOrthographic())
1072 {
b40cdc2b 1073 aDXHalf = aDYHalf = aScale * Elem_t (0.5);
b5ac8292 1074 }
1075 else
1076 {
b40cdc2b 1077 aDXHalf = aDYHalf = aZNear * Elem_t (myFOVyTan);
b5ac8292 1078 }
1079
ab1c121b 1080 if (anAspect > 1.0)
1081 {
1082 aDXHalf *= anAspect;
1083 }
1084 else
1085 {
1086 aDYHalf /= anAspect;
1087 }
1088
b5ac8292 1089 // sets right of frustum based on aspect ratio
b40cdc2b 1090 Aspect_FrustumLRBT<Elem_t> anLRBT;
1091 anLRBT.Left = -aDXHalf;
1092 anLRBT.Right = aDXHalf;
1093 anLRBT.Bottom = -aDYHalf;
1094 anLRBT.Top = aDYHalf;
b5ac8292 1095
197ac94e 1096 Elem_t aIOD = myIODType == IODType_Relative
1097 ? static_cast<Elem_t> (myIOD * Distance())
1098 : static_cast<Elem_t> (myIOD);
b5ac8292 1099
197ac94e 1100 Elem_t aFocus = myZFocusType == FocusType_Relative
1101 ? static_cast<Elem_t> (myZFocus * Distance())
1102 : static_cast<Elem_t> (myZFocus);
b5ac8292 1103
3bffef55 1104 if (myTile.IsValid())
1105 {
1106 const Elem_t aDXFull = Elem_t(2) * aDXHalf;
1107 const Elem_t aDYFull = Elem_t(2) * aDYHalf;
1108 const Graphic3d_Vec2i anOffset = myTile.OffsetLowerLeft();
b40cdc2b 1109 anLRBT.Left = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
1110 anLRBT.Right = -aDXHalf + aDXFull * static_cast<Elem_t> (anOffset.x() + myTile.TileSize.x()) / static_cast<Elem_t> (myTile.TotalSize.x());
1111 anLRBT.Bottom = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
1112 anLRBT.Top = -aDYHalf + aDYFull * static_cast<Elem_t> (anOffset.y() + myTile.TileSize.y()) / static_cast<Elem_t> (myTile.TotalSize.y());
3bffef55 1113 }
1114
b40cdc2b 1115 if (myIsCustomProjMatM)
1116 {
cdc54fb0 1117 theProjM.ConvertFrom (myCustomProjMatM);
b40cdc2b 1118 }
b5ac8292 1119 switch (myProjType)
1120 {
b40cdc2b 1121 case Projection_Orthographic:
b5ac8292 1122 {
b40cdc2b 1123 if (!myIsCustomProjMatM)
1124 {
cdc54fb0 1125 orthoProj (theProjM, anLRBT, aZNear, aZFar);
b40cdc2b 1126 }
b5ac8292 1127 break;
1128 }
b40cdc2b 1129 case Projection_Perspective:
b5ac8292 1130 {
b40cdc2b 1131 if (!myIsCustomProjMatM)
1132 {
cdc54fb0 1133 perspectiveProj (theProjM, anLRBT, aZNear, aZFar);
b40cdc2b 1134 }
b5ac8292 1135 break;
1136 }
b40cdc2b 1137 case Projection_MonoLeftEye:
1138 case Projection_MonoRightEye:
1139 case Projection_Stereo:
b5ac8292 1140 {
b40cdc2b 1141 if (!myIsCustomProjMatM)
1142 {
cdc54fb0 1143 perspectiveProj (theProjM, anLRBT, aZNear, aZFar);
b40cdc2b 1144 }
1145 if (myIsCustomProjMatLR)
1146 {
cdc54fb0 1147 if (theToAddHeadToEye)
1148 {
1149 theProjL.ConvertFrom (myCustomProjMatL * myCustomHeadToEyeMatL);
1150 theProjR.ConvertFrom (myCustomProjMatR * myCustomHeadToEyeMatR);
1151 }
1152 else
1153 {
1154 theProjL.ConvertFrom (myCustomProjMatL);
1155 theProjR.ConvertFrom (myCustomProjMatR);
1156 }
b40cdc2b 1157 }
1158 else if (myIsCustomFrustomLR)
1159 {
1160 anLRBT = Aspect_FrustumLRBT<Elem_t> (myCustomFrustumL).Multiplied (aZNear);
cdc54fb0 1161 perspectiveProj (theProjL, anLRBT, aZNear, aZFar);
b40cdc2b 1162
1163 anLRBT = Aspect_FrustumLRBT<Elem_t> (myCustomFrustumR).Multiplied (aZNear);
cdc54fb0 1164 perspectiveProj (theProjR, anLRBT, aZNear, aZFar);
b40cdc2b 1165 }
1166 else
1167 {
cdc54fb0 1168 stereoEyeProj (theProjL,
b40cdc2b 1169 anLRBT, aZNear, aZFar, aIOD, aFocus,
1170 Aspect_Eye_Left);
cdc54fb0 1171 stereoEyeProj (theProjR,
b40cdc2b 1172 anLRBT, aZNear, aZFar, aIOD, aFocus,
1173 Aspect_Eye_Right);
1174 }
cdc54fb0 1175
1176 if (theToAddHeadToEye
1177 && !myIsCustomProjMatLR
1178 && aIOD != Elem_t (0.0))
1179 {
1180 // X translation to cancel parallax
1181 theProjL.Translate (NCollection_Vec3<Elem_t> (Elem_t ( 0.5) * aIOD, Elem_t (0.0), Elem_t (0.0)));
1182 theProjR.Translate (NCollection_Vec3<Elem_t> (Elem_t (-0.5) * aIOD, Elem_t (0.0), Elem_t (0.0)));
1183 }
b5ac8292 1184 break;
1185 }
1186 }
b40cdc2b 1187 if (myProjType == Projection_MonoLeftEye)
1188 {
cdc54fb0 1189 theProjM = theProjL;
b40cdc2b 1190 }
1191 else if (myProjType == Projection_MonoRightEye)
1192 {
cdc54fb0 1193 theProjM = theProjR;
b40cdc2b 1194 }
b5ac8292 1195}
1196
1197// =======================================================================
1198// function : UpdateOrientation
1199// purpose :
1200// =======================================================================
197ac94e 1201template <typename Elem_t>
1202Graphic3d_Camera::TransformMatrices<Elem_t>&
1203 Graphic3d_Camera::UpdateOrientation (TransformMatrices<Elem_t>& theMatrices) const
b5ac8292 1204{
197ac94e 1205 if (theMatrices.IsOrientationValid())
b5ac8292 1206 {
197ac94e 1207 return theMatrices; // for inline accessors
b5ac8292 1208 }
1209
197ac94e 1210 theMatrices.InitOrientation();
1211
1212 NCollection_Vec3<Elem_t> anEye (static_cast<Elem_t> (myEye.X()),
1213 static_cast<Elem_t> (myEye.Y()),
1214 static_cast<Elem_t> (myEye.Z()));
1215
607e5e62 1216 NCollection_Vec3<Elem_t> aViewDir (static_cast<Elem_t> (myDirection.X()),
1217 static_cast<Elem_t> (myDirection.Y()),
1218 static_cast<Elem_t> (myDirection.Z()));
b5ac8292 1219
197ac94e 1220 NCollection_Vec3<Elem_t> anUp (static_cast<Elem_t> (myUp.X()),
1221 static_cast<Elem_t> (myUp.Y()),
1222 static_cast<Elem_t> (myUp.Z()));
b5ac8292 1223
197ac94e 1224 NCollection_Vec3<Elem_t> anAxialScale (static_cast<Elem_t> (myAxialScale.X()),
1225 static_cast<Elem_t> (myAxialScale.Y()),
1226 static_cast<Elem_t> (myAxialScale.Z()));
b5ac8292 1227
607e5e62 1228 LookOrientation (anEye, aViewDir, anUp, anAxialScale, theMatrices.Orientation);
b5ac8292 1229
197ac94e 1230 return theMatrices; // for inline accessors
1231}
b5ac8292 1232
197ac94e 1233// =======================================================================
1234// function : InvalidateProjection
1235// purpose :
1236// =======================================================================
1237void Graphic3d_Camera::InvalidateProjection()
1238{
1239 myMatricesD.ResetProjection();
1240 myMatricesF.ResetProjection();
825aa485 1241 myWorldViewProjState.ProjectionState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
197ac94e 1242}
b5ac8292 1243
197ac94e 1244// =======================================================================
1245// function : InvalidateOrientation
1246// purpose :
1247// =======================================================================
1248void Graphic3d_Camera::InvalidateOrientation()
1249{
1250 myMatricesD.ResetOrientation();
1251 myMatricesF.ResetOrientation();
825aa485 1252 myWorldViewProjState.WorldViewState() = (Standard_Size)Standard_Atomic_Increment (&THE_STATE_COUNTER);
b5ac8292 1253}
1254
1255// =======================================================================
b40cdc2b 1256// function : orthoProj
b5ac8292 1257// purpose :
1258// =======================================================================
197ac94e 1259template <typename Elem_t>
b40cdc2b 1260void Graphic3d_Camera::orthoProj (NCollection_Mat4<Elem_t>& theOutMx,
1261 const Aspect_FrustumLRBT<Elem_t>& theLRBT,
197ac94e 1262 const Elem_t theNear,
e70625d6 1263 const Elem_t theFar) const
b5ac8292 1264{
1265 // row 0
b40cdc2b 1266 theOutMx.ChangeValue (0, 0) = Elem_t (2.0) / (theLRBT.Right - theLRBT.Left);
197ac94e 1267 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
1268 theOutMx.ChangeValue (0, 2) = Elem_t (0.0);
b40cdc2b 1269 theOutMx.ChangeValue (0, 3) = - (theLRBT.Right + theLRBT.Left) / (theLRBT.Right - theLRBT.Left);
b5ac8292 1270
1271 // row 1
197ac94e 1272 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
b40cdc2b 1273 theOutMx.ChangeValue (1, 1) = Elem_t (2.0) / (theLRBT.Top - theLRBT.Bottom);
197ac94e 1274 theOutMx.ChangeValue (1, 2) = Elem_t (0.0);
b40cdc2b 1275 theOutMx.ChangeValue (1, 3) = - (theLRBT.Top + theLRBT.Bottom) / (theLRBT.Top - theLRBT.Bottom);
b5ac8292 1276
1277 // row 2
197ac94e 1278 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
1279 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
e70625d6 1280 if (myIsZeroToOneDepth)
1281 {
1282 theOutMx.ChangeValue (2, 2) = Elem_t (-1.0) / (theFar - theNear);
1283 theOutMx.ChangeValue (2, 3) = -theNear / (theFar - theNear);
1284 }
1285 else
1286 {
1287 theOutMx.ChangeValue (2, 2) = Elem_t (-2.0) / (theFar - theNear);
1288 theOutMx.ChangeValue (2, 3) = - (theFar + theNear) / (theFar - theNear);
1289 }
b5ac8292 1290
1291 // row 3
197ac94e 1292 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
1293 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
1294 theOutMx.ChangeValue (3, 2) = Elem_t (0.0);
1295 theOutMx.ChangeValue (3, 3) = Elem_t (1.0);
b5ac8292 1296}
1297
1298// =======================================================================
1299// function : PerspectiveProj
1300// purpose :
1301// =======================================================================
197ac94e 1302template <typename Elem_t>
b40cdc2b 1303void Graphic3d_Camera::perspectiveProj (NCollection_Mat4<Elem_t>& theOutMx,
1304 const Aspect_FrustumLRBT<Elem_t>& theLRBT,
197ac94e 1305 const Elem_t theNear,
e70625d6 1306 const Elem_t theFar) const
b5ac8292 1307{
1308 // column 0
b40cdc2b 1309 theOutMx.ChangeValue (0, 0) = (Elem_t (2.0) * theNear) / (theLRBT.Right - theLRBT.Left);
197ac94e 1310 theOutMx.ChangeValue (1, 0) = Elem_t (0.0);
1311 theOutMx.ChangeValue (2, 0) = Elem_t (0.0);
1312 theOutMx.ChangeValue (3, 0) = Elem_t (0.0);
b5ac8292 1313
1314 // column 1
197ac94e 1315 theOutMx.ChangeValue (0, 1) = Elem_t (0.0);
b40cdc2b 1316 theOutMx.ChangeValue (1, 1) = (Elem_t (2.0) * theNear) / (theLRBT.Top - theLRBT.Bottom);
197ac94e 1317 theOutMx.ChangeValue (2, 1) = Elem_t (0.0);
1318 theOutMx.ChangeValue (3, 1) = Elem_t (0.0);
b5ac8292 1319
1320 // column 2
b40cdc2b 1321 theOutMx.ChangeValue (0, 2) = (theLRBT.Right + theLRBT.Left) / (theLRBT.Right - theLRBT.Left);
1322 theOutMx.ChangeValue (1, 2) = (theLRBT.Top + theLRBT.Bottom) / (theLRBT.Top - theLRBT.Bottom);
e70625d6 1323 if (myIsZeroToOneDepth)
1324 {
1325 theOutMx.ChangeValue (2, 2) = theFar / (theNear - theFar);
1326 }
1327 else
1328 {
1329 theOutMx.ChangeValue (2, 2) = -(theFar + theNear) / (theFar - theNear);
1330 }
197ac94e 1331 theOutMx.ChangeValue (3, 2) = Elem_t (-1.0);
b5ac8292 1332
1333 // column 3
197ac94e 1334 theOutMx.ChangeValue (0, 3) = Elem_t (0.0);
1335 theOutMx.ChangeValue (1, 3) = Elem_t (0.0);
e70625d6 1336 if (myIsZeroToOneDepth)
1337 {
1338 theOutMx.ChangeValue (2, 3) = -(theFar * theNear) / (theFar - theNear);
1339 }
1340 else
1341 {
1342 theOutMx.ChangeValue (2, 3) = -(Elem_t (2.0) * theFar * theNear) / (theFar - theNear);
1343 }
197ac94e 1344 theOutMx.ChangeValue (3, 3) = Elem_t (0.0);
b5ac8292 1345}
1346
1347// =======================================================================
1348// function : StereoEyeProj
1349// purpose :
1350// =======================================================================
197ac94e 1351template <typename Elem_t>
b40cdc2b 1352void Graphic3d_Camera::stereoEyeProj (NCollection_Mat4<Elem_t>& theOutMx,
1353 const Aspect_FrustumLRBT<Elem_t>& theLRBT,
197ac94e 1354 const Elem_t theNear,
1355 const Elem_t theFar,
1356 const Elem_t theIOD,
1357 const Elem_t theZFocus,
e70625d6 1358 const Aspect_Eye theEyeIndex) const
b5ac8292 1359{
b40cdc2b 1360 Elem_t aDx = theEyeIndex == Aspect_Eye_Left ? Elem_t (0.5) * theIOD : Elem_t (-0.5) * theIOD;
197ac94e 1361 Elem_t aDXStereoShift = aDx * theNear / theZFocus;
b5ac8292 1362
1363 // construct eye projection matrix
b40cdc2b 1364 Aspect_FrustumLRBT<Elem_t> aLRBT = theLRBT;
1365 aLRBT.Left = theLRBT.Left + aDXStereoShift;
1366 aLRBT.Right = theLRBT.Right + aDXStereoShift;
1367 perspectiveProj (theOutMx, aLRBT, theNear, theFar);
b5ac8292 1368}
1369
1370// =======================================================================
1371// function : LookOrientation
1372// purpose :
1373// =======================================================================
197ac94e 1374template <typename Elem_t>
1375void Graphic3d_Camera::LookOrientation (const NCollection_Vec3<Elem_t>& theEye,
607e5e62 1376 const NCollection_Vec3<Elem_t>& theFwdDir,
197ac94e 1377 const NCollection_Vec3<Elem_t>& theUpDir,
1378 const NCollection_Vec3<Elem_t>& theAxialScale,
1379 NCollection_Mat4<Elem_t>& theOutMx)
b5ac8292 1380{
607e5e62 1381 NCollection_Vec3<Elem_t> aForward = theFwdDir;
b5ac8292 1382 aForward.Normalize();
1383
1384 // side = forward x up
197ac94e 1385 NCollection_Vec3<Elem_t> aSide = NCollection_Vec3<Elem_t>::Cross (aForward, theUpDir);
b5ac8292 1386 aSide.Normalize();
1387
1388 // recompute up as: up = side x forward
197ac94e 1389 NCollection_Vec3<Elem_t> anUp = NCollection_Vec3<Elem_t>::Cross (aSide, aForward);
b5ac8292 1390
197ac94e 1391 NCollection_Mat4<Elem_t> aLookMx;
b5ac8292 1392 aLookMx.SetRow (0, aSide);
1393 aLookMx.SetRow (1, anUp);
1394 aLookMx.SetRow (2, -aForward);
1395
197ac94e 1396 theOutMx.InitIdentity();
1397 theOutMx.Multiply (aLookMx);
b5ac8292 1398 theOutMx.Translate (-theEye);
1399
197ac94e 1400 NCollection_Mat4<Elem_t> anAxialScaleMx;
b5ac8292 1401 anAxialScaleMx.ChangeValue (0, 0) = theAxialScale.x();
1402 anAxialScaleMx.ChangeValue (1, 1) = theAxialScale.y();
1403 anAxialScaleMx.ChangeValue (2, 2) = theAxialScale.z();
1404
1405 theOutMx.Multiply (anAxialScaleMx);
1406}
6bc6a6fc 1407
f3a53980 1408// =======================================================================
1409// function : FitMinMax
1410// purpose :
1411// =======================================================================
1412bool Graphic3d_Camera::FitMinMax (const Bnd_Box& theBox,
1413 const Standard_Real theResolution,
1414 const bool theToEnlargeIfLine)
1415{
1416 // Check bounding box for validness
1417 if (theBox.IsVoid())
1418 {
1419 return false; // bounding box is out of bounds...
1420 }
1421
1422 // Apply "axial scaling" to the bounding points.
1423 // It is not the best approach to make this scaling as a part of fit all operation,
1424 // but the axial scale is integrated into camera orientation matrix and the other
1425 // option is to perform frustum plane adjustment algorithm in view camera space,
1426 // which will lead to a number of additional world-view space conversions and
1427 // loosing precision as well.
1428 const gp_Pnt aBndMin = theBox.CornerMin().XYZ().Multiplied (myAxialScale);
1429 const gp_Pnt aBndMax = theBox.CornerMax().XYZ().Multiplied (myAxialScale);
1430 if (aBndMax.IsEqual (aBndMin, RealEpsilon()))
1431 {
1432 return false; // nothing to fit all
1433 }
1434
1435 // Prepare camera frustum planes.
1436 gp_Pln aFrustumPlaneArray[6];
1437 NCollection_Array1<gp_Pln> aFrustumPlane (aFrustumPlaneArray[0], 1, 6);
1438 Frustum (aFrustumPlane[1], aFrustumPlane[2], aFrustumPlane[3],
1439 aFrustumPlane[4], aFrustumPlane[5], aFrustumPlane[6]);
1440
1441 // Prepare camera up, side, direction vectors.
1442 const gp_Dir aCamUp = OrthogonalizedUp();
1443 const gp_Dir aCamDir = Direction();
1444 const gp_Dir aCamSide = aCamDir ^ aCamUp;
1445
1446 // Prepare scene bounding box parameters.
1447 const gp_Pnt aBndCenter = (aBndMin.XYZ() + aBndMax.XYZ()) / 2.0;
1448
1449 gp_Pnt aBndCornerArray[8];
1450 NCollection_Array1<gp_Pnt> aBndCorner (aBndCornerArray[0], 1, 8);
1451 aBndCorner[1].SetCoord (aBndMin.X(), aBndMin.Y(), aBndMin.Z());
1452 aBndCorner[2].SetCoord (aBndMin.X(), aBndMin.Y(), aBndMax.Z());
1453 aBndCorner[3].SetCoord (aBndMin.X(), aBndMax.Y(), aBndMin.Z());
1454 aBndCorner[4].SetCoord (aBndMin.X(), aBndMax.Y(), aBndMax.Z());
1455 aBndCorner[5].SetCoord (aBndMax.X(), aBndMin.Y(), aBndMin.Z());
1456 aBndCorner[6].SetCoord (aBndMax.X(), aBndMin.Y(), aBndMax.Z());
1457 aBndCorner[7].SetCoord (aBndMax.X(), aBndMax.Y(), aBndMin.Z());
1458 aBndCorner[8].SetCoord (aBndMax.X(), aBndMax.Y(), aBndMax.Z());
1459
1460 // Perspective-correct camera projection vector, matching the bounding box is determined geometrically.
1461 // Knowing the initial shape of a frustum it is possible to match it to a bounding box.
1462 // Then, knowing the relation of camera projection vector to the frustum shape it is possible to
1463 // set up perspective-correct camera projection matching the bounding box.
1464 // These steps support non-asymmetric transformations of view-projection space provided by camera.
1465 // The zooming can be done by calculating view plane size matching the bounding box at center of
1466 // the bounding box. The only limitation here is that the scale of camera should define size of
1467 // its view plane passing through the camera center, and the center of camera should be on the
1468 // same line with the center of bounding box.
1469
1470 // The following method is applied:
1471 // 1) Determine normalized asymmetry of camera projection vector by frustum planes.
1472 // 2) Determine new location of frustum planes, "matching" the bounding box.
1473 // 3) Determine new camera projection vector using the normalized asymmetry.
1474 // 4) Determine new zooming in view space.
1475
1476 // 1. Determine normalized projection asymmetry (if any).
1477 Standard_Real anAssymX = Tan (( aCamSide).Angle (aFrustumPlane[1].Axis().Direction()))
1478 - Tan ((-aCamSide).Angle (aFrustumPlane[2].Axis().Direction()));
1479 Standard_Real anAssymY = Tan (( aCamUp) .Angle (aFrustumPlane[3].Axis().Direction()))
1480 - Tan ((-aCamUp) .Angle (aFrustumPlane[4].Axis().Direction()));
1481
1482 // 2. Determine how far should be the frustum planes placed from center
1483 // of bounding box, in order to match the bounding box closely.
1484 Standard_Real aFitDistanceArray[6];
1485 NCollection_Array1<Standard_Real> aFitDistance (aFitDistanceArray[0], 1, 6);
1486 aFitDistance.Init (0.0);
1487 for (Standard_Integer anI = aFrustumPlane.Lower(); anI <= aFrustumPlane.Upper(); ++anI)
1488 {
1489 // Measure distances from center of bounding box to its corners towards the frustum plane.
1490 const gp_Dir& aPlaneN = aFrustumPlane[anI].Axis().Direction();
1491
1492 Standard_Real& aFitDist = aFitDistance[anI];
1493 for (Standard_Integer aJ = aBndCorner.Lower(); aJ <= aBndCorner.Upper(); ++aJ)
1494 {
1495 aFitDist = Max (aFitDist, gp_Vec (aBndCenter, aBndCorner[aJ]).Dot (aPlaneN));
1496 }
1497 }
1498 // The center of camera is placed on the same line with center of bounding box.
1499 // The view plane section crosses the bounding box at its center.
1500 // To compute view plane size, evaluate coefficients converting "point -> plane distance"
1501 // into view section size between the point and the frustum plane.
1502 // proj
1503 // /|\ right half of frame //
1504 // | //
1505 // point o<-- distance * coeff -->//---- (view plane section)
1506 // \ //
1507 // (distance) //
1508 // ~ //
1509 // (distance) //
1510 // \/\//
1511 // \//
1512 // //
1513 // (frustum plane)
1514 aFitDistance[1] *= Sqrt(1 + Pow (Tan ( aCamSide .Angle (aFrustumPlane[1].Axis().Direction())), 2.0));
1515 aFitDistance[2] *= Sqrt(1 + Pow (Tan ((-aCamSide).Angle (aFrustumPlane[2].Axis().Direction())), 2.0));
1516 aFitDistance[3] *= Sqrt(1 + Pow (Tan ( aCamUp .Angle (aFrustumPlane[3].Axis().Direction())), 2.0));
1517 aFitDistance[4] *= Sqrt(1 + Pow (Tan ((-aCamUp) .Angle (aFrustumPlane[4].Axis().Direction())), 2.0));
1518 aFitDistance[5] *= Sqrt(1 + Pow (Tan ( aCamDir .Angle (aFrustumPlane[5].Axis().Direction())), 2.0));
1519 aFitDistance[6] *= Sqrt(1 + Pow (Tan ((-aCamDir) .Angle (aFrustumPlane[6].Axis().Direction())), 2.0));
1520
1521 Standard_Real aViewSizeXv = aFitDistance[1] + aFitDistance[2];
1522 Standard_Real aViewSizeYv = aFitDistance[3] + aFitDistance[4];
1523 Standard_Real aViewSizeZv = aFitDistance[5] + aFitDistance[6];
1524
1525 // 3. Place center of camera on the same line with center of bounding
1526 // box applying corresponding projection asymmetry (if any).
1527 Standard_Real anAssymXv = anAssymX * aViewSizeXv * 0.5;
1528 Standard_Real anAssymYv = anAssymY * aViewSizeYv * 0.5;
1529 Standard_Real anOffsetXv = (aFitDistance[2] - aFitDistance[1]) * 0.5 + anAssymXv;
1530 Standard_Real anOffsetYv = (aFitDistance[4] - aFitDistance[3]) * 0.5 + anAssymYv;
1531 gp_Vec aTranslateSide = gp_Vec (aCamSide) * anOffsetXv;
1532 gp_Vec aTranslateUp = gp_Vec (aCamUp) * anOffsetYv;
1533 gp_Pnt aCamNewCenter = aBndCenter.Translated (aTranslateSide).Translated (aTranslateUp);
1534
1535 gp_Trsf aCenterTrsf;
1536 aCenterTrsf.SetTranslation (Center(), aCamNewCenter);
1537 Transform (aCenterTrsf);
1538 SetDistance (aFitDistance[6] + aFitDistance[5]);
1539
1540 if (aViewSizeXv < theResolution
1541 && aViewSizeYv < theResolution)
1542 {
1543 // Bounding box collapses to a point or thin line going in depth of the screen
1544 if (aViewSizeXv < theResolution || !theToEnlargeIfLine)
1545 {
1546 return false; // This is just one point or line and zooming has no effect.
1547 }
1548
1549 // Looking along line and "theToEnlargeIfLine" is requested.
1550 // Fit view to see whole scene on rotation.
1551 aViewSizeXv = aViewSizeZv;
1552 aViewSizeYv = aViewSizeZv;
1553 }
1554
1555 const Standard_Real anAspect = Aspect();
1556 if (anAspect > 1.0)
1557 {
1558 SetScale (Max (aViewSizeXv / anAspect, aViewSizeYv));
1559 }
1560 else
1561 {
1562 SetScale (Max (aViewSizeXv, aViewSizeYv * anAspect));
1563 }
1564 return true;
1565}
1566
6bc6a6fc 1567//=============================================================================
1568//function : ZFitAll
1569//purpose :
1570//=============================================================================
10dbdf34 1571bool Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor,
1572 const Bnd_Box& theMinMax,
1573 const Bnd_Box& theGraphicBB,
1574 Standard_Real& theZNear,
1575 Standard_Real& theZFar) const
6bc6a6fc 1576{
1577 Standard_ASSERT_RAISE (theScaleFactor > 0.0, "Zero or negative scale factor is not allowed.");
1578
ea764884 1579 // Method changes zNear and zFar parameters of camera so as to fit graphical structures
1580 // by their graphical boundaries. It precisely fits min max boundaries of primary application
1581 // objects (second argument), while it can sacrifice the real graphical boundaries of the
1582 // scene with infinite or helper objects (third argument) for the sake of perspective projection.
ed063270 1583 if (theGraphicBB.IsVoid())
6bc6a6fc 1584 {
10dbdf34 1585 theZNear = DEFAULT_ZNEAR;
1586 theZFar = DEFAULT_ZFAR;
1587 return false;
6bc6a6fc 1588 }
1589
ea764884 1590 // Measure depth of boundary points from camera eye.
ed063270 1591 NCollection_Sequence<gp_Pnt> aPntsToMeasure;
1592
ea764884 1593 Standard_Real aGraphicBB[6];
ed063270 1594 theGraphicBB.Get (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2], aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]);
1595
1596 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[2]));
1597 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[1], aGraphicBB[5]));
1598 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[2]));
1599 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[0], aGraphicBB[4], aGraphicBB[5]));
1600 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[2]));
1601 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[1], aGraphicBB[5]));
1602 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[2]));
1603 aPntsToMeasure.Append (gp_Pnt (aGraphicBB[3], aGraphicBB[4], aGraphicBB[5]));
1604
5a19c303 1605 Standard_Boolean isFiniteMinMax = !theMinMax.IsVoid() && !theMinMax.IsWhole();
1606
1607 if (isFiniteMinMax)
6bc6a6fc 1608 {
ea764884 1609 Standard_Real aMinMax[6];
ed063270 1610 theMinMax.Get (aMinMax[0], aMinMax[1], aMinMax[2], aMinMax[3], aMinMax[4], aMinMax[5]);
1611
1612 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[2]));
1613 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[1], aMinMax[5]));
1614 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[2]));
1615 aPntsToMeasure.Append (gp_Pnt (aMinMax[0], aMinMax[4], aMinMax[5]));
1616 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[2]));
1617 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[1], aMinMax[5]));
1618 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[2]));
1619 aPntsToMeasure.Append (gp_Pnt (aMinMax[3], aMinMax[4], aMinMax[5]));
1620 }
6bc6a6fc 1621
ea764884 1622 // Camera eye plane.
6bc6a6fc 1623 gp_Dir aCamDir = Direction();
1624 gp_Pnt aCamEye = myEye;
1625 gp_Pln aCamPln (aCamEye, aCamDir);
1626
5a19c303 1627 Standard_Real aModelMinDist = RealLast();
1628 Standard_Real aModelMaxDist = RealFirst();
1629 Standard_Real aGraphMinDist = RealLast();
1630 Standard_Real aGraphMaxDist = RealFirst();
6bc6a6fc 1631
1632 const gp_XYZ& anAxialScale = myAxialScale;
1633
ea764884 1634 // Get minimum and maximum distances to the eye plane.
ed063270 1635 Standard_Integer aCounter = 0;
1636 NCollection_Sequence<gp_Pnt>::Iterator aPntIt(aPntsToMeasure);
1637 for (; aPntIt.More(); aPntIt.Next())
6bc6a6fc 1638 {
ed063270 1639 gp_Pnt aMeasurePnt = aPntIt.Value();
6bc6a6fc 1640
1641 aMeasurePnt = gp_Pnt (aMeasurePnt.X() * anAxialScale.X(),
ed063270 1642 aMeasurePnt.Y() * anAxialScale.Y(),
1643 aMeasurePnt.Z() * anAxialScale.Z());
6bc6a6fc 1644
1645 Standard_Real aDistance = aCamPln.Distance (aMeasurePnt);
1646
ea764884 1647 // Check if the camera is intruded into the scene.
607e5e62 1648 gp_Vec aVecToMeasurePnt (aCamEye, aMeasurePnt);
1649 if (aVecToMeasurePnt.Magnitude() > gp::Resolution()
1650 && aCamDir.IsOpposite (aVecToMeasurePnt, M_PI * 0.5))
6bc6a6fc 1651 {
1652 aDistance *= -1;
1653 }
1654
ea764884 1655 // The first eight points are from theGraphicBB, the last eight points are from theMinMax (can be absent).
5a19c303 1656 Standard_Real& aChangeMinDist = aCounter >= 8 ? aModelMinDist : aGraphMinDist;
1657 Standard_Real& aChangeMaxDist = aCounter >= 8 ? aModelMaxDist : aGraphMaxDist;
6bc6a6fc 1658 aChangeMinDist = Min (aDistance, aChangeMinDist);
1659 aChangeMaxDist = Max (aDistance, aChangeMaxDist);
ed063270 1660 aCounter++;
6bc6a6fc 1661 }
1662
ea764884 1663 // Compute depth of bounding box center.
5a19c303 1664 Standard_Real aMidDepth = (aGraphMinDist + aGraphMaxDist) * 0.5;
1665 Standard_Real aHalfDepth = (aGraphMaxDist - aGraphMinDist) * 0.5;
6bc6a6fc 1666
ea764884 1667 // Compute enlarged or shrank near and far z ranges.
35c4a17c 1668 Standard_Real aZNear = aMidDepth - aHalfDepth * theScaleFactor;
1669 Standard_Real aZFar = aMidDepth + aHalfDepth * theScaleFactor;
6bc6a6fc 1670
1671 if (!IsOrthographic())
1672 {
ea764884 1673 // Everything is behind the perspective camera.
1674 if (aZFar < zEpsilon())
6bc6a6fc 1675 {
10dbdf34 1676 theZNear = DEFAULT_ZNEAR;
1677 theZFar = DEFAULT_ZFAR;
1678 return false;
6bc6a6fc 1679 }
6bc6a6fc 1680 }
1681
ea764884 1682 //
1683 // Consider clipping errors due to double to single precision floating-point conversion.
1684 //
1685
1686 // Model to view transformation performs translation of points against eye position
1687 // in three dimensions. Both point coordinate and eye position values are converted from
1688 // double to single precision floating point numbers producing conversion errors.
1689 // Epsilon (Mod) * 3.0 should safely compensate precision error for z coordinate after
1690 // translation assuming that the:
1691 // Epsilon (Eye.Mod()) * 3.0 > Epsilon (Eye.X()) + Epsilon (Eye.Y()) + Epsilon (Eye.Z()).
1692 Standard_Real aEyeConf = 3.0 * zEpsilon (myEye.XYZ().Modulus());
1693
1694 // Model to view transformation performs rotation of points according to view direction.
1695 // New z coordinate is computed as a multiplication of point's x, y, z coordinates by the
1696 // "forward" direction vector's x, y, z coordinates. Both point's and "z" direction vector's
1697 // values are converted from double to single precision floating point numbers producing
1698 // conversion errors.
1699 // Epsilon (Mod) * 6.0 should safely compensate the precision errors for the multiplication
1700 // of point coordinates by direction vector.
1701 gp_Pnt aGraphicMin = theGraphicBB.CornerMin();
1702 gp_Pnt aGraphicMax = theGraphicBB.CornerMax();
1703
1704 Standard_Real aModelConf = 6.0 * zEpsilon (aGraphicMin.XYZ().Modulus()) +
1705 6.0 * zEpsilon (aGraphicMax.XYZ().Modulus());
1706
1707 // Compensate floating point conversion errors by increasing zNear, zFar to avoid clipping.
1708 aZNear -= zEpsilon (aZNear) + aEyeConf + aModelConf;
1709 aZFar += zEpsilon (aZFar) + aEyeConf + aModelConf;
1710
1711 if (!IsOrthographic())
6bc6a6fc 1712 {
5a19c303 1713 // For perspective projection, the value of z in normalized device coordinates is non-linear
1714 // function of eye z coordinate. For fixed-point depth representation resolution of z in
1715 // model-view space will grow towards zFar plane and its scale depends mostly on how far is zNear
1716 // against camera's eye. The purpose of the code below is to select most appropriate zNear distance
1717 // to balance between clipping (less zNear, more chances to observe closely small models without clipping)
1718 // and resolution of depth. A well applicable criteria to this is a ratio between resolution of z at center
1719 // of model boundaries and the distance to that center point. The ratio is chosen empirically and validated
1720 // by tests database. It is considered to be ~0.001 (0.1%) for 24 bit depth buffer, for less depth bitness
1721 // the zNear will be placed similarly giving lower resolution.
1722 // Approximation of the formula for respectively large z range is:
1723 // zNear = [z * (1 + k) / (k * c)],
1724 // where:
1725 // z - distance to center of model boundaries;
1726 // k - chosen ratio, c - capacity of depth buffer;
1727 // k = 0.001, k * c = 1677.216, (1 + k) / (k * c) ~ 5.97E-4
1728 //
1729 // The function uses center of model boundaries computed from "theMinMax" boundaries (instead of using real
1730 // graphical boundaries of all displayed objects). That means that it can sacrifice resolution of presentation
1731 // of non primary ("infinite") application graphical objects in favor of better perspective projection of the
1732 // small applicative objects measured with "theMinMax" values.
1733 Standard_Real aZRange = isFiniteMinMax ? aModelMaxDist - aModelMinDist : aGraphMaxDist - aGraphMinDist;
1734 Standard_Real aZMin = isFiniteMinMax ? aModelMinDist : aGraphMinDist;
1735 Standard_Real aZ = aZMin < 0 ? aZRange / 2.0 : aZRange / 2.0 + aZMin;
1736 Standard_Real aZNearMin = aZ * 5.97E-4;
1737 if (aZNear < aZNearMin)
1738 {
1739 // Clip zNear according to the minimum value matching the quality.
1740 aZNear = aZNearMin;
607e5e62 1741 if (aZFar < aZNear)
1742 {
1743 aZFar = aZNear;
1744 }
5a19c303 1745 }
1746 else
1747 {
1748 // Compensate zNear conversion errors for perspective projection.
1749 aZNear -= aZFar * zEpsilon (aZNear) / (aZFar - zEpsilon (aZNear));
1750 }
1751
1752 // Compensate zFar conversion errors for perspective projection.
1753 aZFar += zEpsilon (aZFar);
ea764884 1754
1755 // Ensure that after all the zNear is not a negative value.
1756 if (aZNear < zEpsilon())
1757 {
1758 aZNear = zEpsilon();
1759 }
607e5e62 1760 Standard_ASSERT_RAISE (aZFar > aZNear, "ZFar should be greater than ZNear");
6bc6a6fc 1761 }
1762
10dbdf34 1763 theZNear = aZNear;
1764 theZFar = aZFar;
607e5e62 1765 Standard_ASSERT_RAISE (aZFar > aZNear, "ZFar should be greater than ZNear");
10dbdf34 1766 return true;
6bc6a6fc 1767}
1beb58d7 1768
1769//=============================================================================
1770//function : Interpolate
1771//purpose :
1772//=============================================================================
026aec18 1773void Graphic3d_Camera::Interpolate (const Handle(Graphic3d_Camera)& theStart,
1774 const Handle(Graphic3d_Camera)& theEnd,
1775 const double theT,
1776 Handle(Graphic3d_Camera)& theCamera)
1beb58d7 1777{
1778 if (Abs (theT - 1.0) < Precision::Confusion())
1779 {
1780 // just copy end-point transformation
026aec18 1781 theCamera->Copy (theEnd);
1beb58d7 1782 return;
1783 }
1784
026aec18 1785 theCamera->Copy (theStart);
1beb58d7 1786 if (Abs (theT - 0.0) < Precision::Confusion())
1787 {
1788 return;
1789 }
1790
1791 // apply rotation
1792 {
026aec18 1793 gp_Ax3 aCamStart = cameraToAx3 (*theStart);
1794 gp_Ax3 aCamEnd = cameraToAx3 (*theEnd);
1beb58d7 1795 gp_Trsf aTrsfStart, aTrsfEnd;
1796 aTrsfStart.SetTransformation (aCamStart, gp::XOY());
1797 aTrsfEnd .SetTransformation (aCamEnd, gp::XOY());
1798
1799 gp_Quaternion aRotStart = aTrsfStart.GetRotation();
1800 gp_Quaternion aRotEnd = aTrsfEnd .GetRotation();
1801 gp_Quaternion aRotDelta = aRotEnd * aRotStart.Inverted();
1802 gp_Quaternion aRot = gp_QuaternionNLerp::Interpolate (gp_Quaternion(), aRotDelta, theT);
1803 gp_Trsf aTrsfRot;
1804 aTrsfRot.SetRotation (aRot);
1805 theCamera->Transform (aTrsfRot);
1806 }
1807
1808 // apply translation
1809 {
026aec18 1810 gp_XYZ aCenter = NCollection_Lerp<gp_XYZ>::Interpolate (theStart->Center().XYZ(), theEnd->Center().XYZ(), theT);
1811 gp_XYZ anEye = NCollection_Lerp<gp_XYZ>::Interpolate (theStart->Eye().XYZ(), theEnd->Eye().XYZ(), theT);
1beb58d7 1812 gp_XYZ anAnchor = aCenter;
1813 Standard_Real aKc = 0.0;
1814
026aec18 1815 const Standard_Real aDeltaCenter = theStart->Center().Distance (theEnd->Center());
1816 const Standard_Real aDeltaEye = theStart->Eye() .Distance (theEnd->Eye());
1beb58d7 1817 if (aDeltaEye <= gp::Resolution())
1818 {
1819 anAnchor = anEye;
1820 aKc = 1.0;
1821 }
1822 else if (aDeltaCenter > gp::Resolution())
1823 {
1824 aKc = aDeltaCenter / (aDeltaCenter + aDeltaEye);
1825
026aec18 1826 const gp_XYZ anAnchorStart = NCollection_Lerp<gp_XYZ>::Interpolate (theStart->Center().XYZ(), theStart->Eye().XYZ(), aKc);
1827 const gp_XYZ anAnchorEnd = NCollection_Lerp<gp_XYZ>::Interpolate (theEnd ->Center().XYZ(), theEnd ->Eye().XYZ(), aKc);
1beb58d7 1828 anAnchor = NCollection_Lerp<gp_XYZ>::Interpolate (anAnchorStart, anAnchorEnd, theT);
1829 }
1830
1831 const gp_Vec aDirEyeToCenter = theCamera->Direction();
026aec18 1832 const Standard_Real aDistEyeCenterStart = theStart->Eye().Distance (theStart->Center());
1833 const Standard_Real aDistEyeCenterEnd = theEnd ->Eye().Distance (theEnd ->Center());
1beb58d7 1834 const Standard_Real aDistEyeCenter = NCollection_Lerp<Standard_Real>::Interpolate (aDistEyeCenterStart, aDistEyeCenterEnd, theT);
1835 aCenter = anAnchor + aDirEyeToCenter.XYZ() * aDistEyeCenter * aKc;
1836 anEye = anAnchor - aDirEyeToCenter.XYZ() * aDistEyeCenter * (1.0 - aKc);
1837
607e5e62 1838 theCamera->SetEyeAndCenter (anEye, aCenter);
1beb58d7 1839 }
1840
1841 // apply scaling
026aec18 1842 if (Abs(theStart->Scale() - theEnd->Scale()) > Precision::Confusion()
1843 && theStart->IsOrthographic())
1beb58d7 1844 {
026aec18 1845 const Standard_Real aScale = NCollection_Lerp<Standard_Real>::Interpolate (theStart->Scale(), theEnd->Scale(), theT);
1beb58d7 1846 theCamera->SetScale (aScale);
1847 }
1848}
30a1b24e 1849
1850//=======================================================================
1851//function : FrustumPoints
1852//purpose :
1853//=======================================================================
9ad4ff93 1854void Graphic3d_Camera::FrustumPoints (NCollection_Array1<Graphic3d_Vec3d>& thePoints,
1855 const Graphic3d_Mat4d& theModelWorld) const
30a1b24e 1856{
1857 if (thePoints.Length() != FrustumVerticesNB)
1858 {
1859 thePoints.Resize (0, FrustumVerticesNB, Standard_False);
1860 }
1861
1862 const Graphic3d_Mat4d& aProjectionMat = ProjectionMatrix();
9ad4ff93 1863 const Graphic3d_Mat4d aWorldViewMat = OrientationMatrix() * theModelWorld;
30a1b24e 1864
1865 Standard_Real nLeft = 0.0, nRight = 0.0, nTop = 0.0, nBottom = 0.0;
1866 Standard_Real fLeft = 0.0, fRight = 0.0, fTop = 0.0, fBottom = 0.0;
e70625d6 1867 Standard_Real aNear = myZNear, aFar = myZFar;
30a1b24e 1868 if (!IsOrthographic())
1869 {
1870 // handle perspective projection
30a1b24e 1871 // Near plane
1872 nLeft = aNear * (aProjectionMat.GetValue (0, 2) - 1.0) / aProjectionMat.GetValue (0, 0);
1873 nRight = aNear * (aProjectionMat.GetValue (0, 2) + 1.0) / aProjectionMat.GetValue (0, 0);
1874 nTop = aNear * (aProjectionMat.GetValue (1, 2) + 1.0) / aProjectionMat.GetValue (1, 1);
1875 nBottom = aNear * (aProjectionMat.GetValue (1, 2) - 1.0) / aProjectionMat.GetValue (1, 1);
1876 // Far plane
1877 fLeft = aFar * (aProjectionMat.GetValue (0, 2) - 1.0) / aProjectionMat.GetValue (0, 0);
1878 fRight = aFar * (aProjectionMat.GetValue (0, 2) + 1.0) / aProjectionMat.GetValue (0, 0);
1879 fTop = aFar * (aProjectionMat.GetValue (1, 2) + 1.0) / aProjectionMat.GetValue (1, 1);
1880 fBottom = aFar * (aProjectionMat.GetValue (1, 2) - 1.0) / aProjectionMat.GetValue (1, 1);
1881 }
1882 else
1883 {
1884 // handle orthographic projection
30a1b24e 1885 // Near plane
1886 nLeft = ( 1.0 + aProjectionMat.GetValue (0, 3)) / (-aProjectionMat.GetValue (0, 0));
1887 fLeft = nLeft;
1888 nRight = ( 1.0 - aProjectionMat.GetValue (0, 3)) / aProjectionMat.GetValue (0, 0);
1889 fRight = nRight;
1890 nTop = ( 1.0 - aProjectionMat.GetValue (1, 3)) / aProjectionMat.GetValue (1, 1);
1891 fTop = nTop;
1892 nBottom = (-1.0 - aProjectionMat.GetValue (1, 3)) / aProjectionMat.GetValue (1, 1);
1893 fBottom = nBottom;
1894 }
1895
1896 Graphic3d_Vec4d aLeftTopNear (nLeft, nTop, -aNear, 1.0), aRightBottomFar (fRight, fBottom, -aFar, 1.0);
1897 Graphic3d_Vec4d aLeftBottomNear (nLeft, nBottom, -aNear, 1.0), aRightTopFar (fRight, fTop, -aFar, 1.0);
1898 Graphic3d_Vec4d aRightBottomNear (nRight, nBottom, -aNear, 1.0), aLeftTopFar (fLeft, fTop, -aFar, 1.0);
1899 Graphic3d_Vec4d aRightTopNear (nRight, nTop, -aNear, 1.0), aLeftBottomFar (fLeft, fBottom, -aFar, 1.0);
1900
1901 Graphic3d_Mat4d anInvWorldView;
1902 aWorldViewMat.Inverted (anInvWorldView);
1903
1904 Graphic3d_Vec4d aTmpPnt;
1905 aTmpPnt = anInvWorldView * aLeftTopNear;
1906 thePoints.SetValue (FrustumVert_LeftTopNear, aTmpPnt.xyz() / aTmpPnt.w());
1907 aTmpPnt = anInvWorldView * aRightBottomFar;
1908 thePoints.SetValue (FrustumVert_RightBottomFar, aTmpPnt.xyz() / aTmpPnt.w());
1909 aTmpPnt = anInvWorldView * aLeftBottomNear;
1910 thePoints.SetValue (FrustumVert_LeftBottomNear, aTmpPnt.xyz() / aTmpPnt.w());
1911 aTmpPnt = anInvWorldView * aRightTopFar;
1912 thePoints.SetValue (FrustumVert_RightTopFar, aTmpPnt.xyz() / aTmpPnt.w());
1913 aTmpPnt = anInvWorldView * aRightBottomNear;
1914 thePoints.SetValue (FrustumVert_RightBottomNear, aTmpPnt.xyz() / aTmpPnt.w());
1915 aTmpPnt = anInvWorldView * aLeftTopFar;
1916 thePoints.SetValue (FrustumVert_LeftTopFar, aTmpPnt.xyz() / aTmpPnt.w());
1917 aTmpPnt = anInvWorldView * aRightTopNear;
1918 thePoints.SetValue (FrustumVert_RightTopNear, aTmpPnt.xyz() / aTmpPnt.w());
1919 aTmpPnt = anInvWorldView * aLeftBottomFar;
1920 thePoints.SetValue (FrustumVert_LeftBottomFar, aTmpPnt.xyz() / aTmpPnt.w());
1921}
bc73b006 1922
1923//=======================================================================
1924//function : DumpJson
1925//purpose :
1926//=======================================================================
1927void Graphic3d_Camera::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
1928{
1929 OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
1930
1931 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myUp)
1932 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myDirection)
1933 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myEye)
1934
1935 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDistance)
a5162275 1936
1937 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myAxialScale)
1938 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myProjType)
1939 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myFOVy)
1940 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myZNear)
1941 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myZFar)
1942 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAspect)
1943
1944 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myScale)
1945 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myZFocus)
1946 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myZFocusType)
1947
1948 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIOD)
1949 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIODType)
1950
1951 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myTile)
1952 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myMatricesD)
1953 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myMatricesF)
1954 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myWorldViewProjState)
bc73b006 1955}