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