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