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