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