0027836: Visualization, TKOpenGl - gradient background is lost at some camera positions
[occt.git] / src / Graphic3d / Graphic3d_TransformPers.hxx
CommitLineData
825aa485 1// Created on: 2015-06-18
2// Created by: Anton POLETAEV
3// Copyright (c) 2015 OPEN CASCADE SAS
4//
5// This file is part of Open CASCADE Technology software library.
6//
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
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#ifndef _Graphic3d_TransformPers_HeaderFile
17#define _Graphic3d_TransformPers_HeaderFile
18
19#include <Bnd_Box.hxx>
20#include <BVH_Box.hxx>
3fe9ce0e 21#include <Graphic3d_Camera.hxx>
825aa485 22#include <Graphic3d_TransformUtils.hxx>
23#include <Graphic3d_TransModeFlags.hxx>
24#include <NCollection_Mat4.hxx>
25#include <NCollection_Vec4.hxx>
26
27//! Class for keeping and computing transformation persistence.
28class Graphic3d_TransformPers
29{
30public:
31
32 DEFINE_STANDARD_ALLOC
33
34 //! Default constructor.
35 Graphic3d_TransformPers()
36 : Flags (Graphic3d_TMF_None),
37 Point (0.0, 0.0, 0.0) {}
38
39 //! Transformation persistence mode flags.
40 Graphic3d_TransModeFlags Flags;
41
42 //! Reference point for transformation.
43 Graphic3d_Vec3d Point;
44
45public:
46
47 //! Apply transformation to bounding box of presentation.
3fe9ce0e 48 //! @param theCamera [in] camera definition
825aa485 49 //! @param theProjection [in] the projection transformation matrix.
50 //! @param theWorldView [in] the world view transformation matrix.
51 //! @param theViewportWidth [in] the width of viewport (for 2d persistence).
52 //! @param theViewportHeight [in] the height of viewport (for 2d persistence).
53 //! @param theBoundingBox [in/out] the bounding box to transform.
54 template<class T>
3fe9ce0e 55 void Apply (const Handle(Graphic3d_Camera)& theCamera,
56 const NCollection_Mat4<T>& theProjection,
825aa485 57 const NCollection_Mat4<T>& theWorldView,
58 const Standard_Integer theViewportWidth,
59 const Standard_Integer theViewportHeight,
60 Bnd_Box& theBoundingBox) const;
61
62 //! Apply transformation to bounding box of presentation
3fe9ce0e 63 //! @param theCamera [in] camera definition
825aa485 64 //! @param theProjection [in] the projection transformation matrix.
65 //! @param theWorldView [in] the world view transformation matrix.
66 //! @param theViewportWidth [in] the width of viewport (for 2d persistence).
67 //! @param theViewportHeight [in] the height of viewport (for 2d persistence).
68 //! @param theBoundingBox [in/out] the bounding box to transform.
69 template<class T>
3fe9ce0e 70 void Apply (const Handle(Graphic3d_Camera)& theCamera,
71 const NCollection_Mat4<T>& theProjection,
825aa485 72 const NCollection_Mat4<T>& theWorldView,
73 const Standard_Integer theViewportWidth,
74 const Standard_Integer theViewportHeight,
75 BVH_Box<T, 4>& theBoundingBox) const;
76
77 //! Compute transformation.
78 //! Computed matrix can be applied to model world transformation
79 //! of an object to implement effect of transformation persistence.
3fe9ce0e 80 //! @param theCamera [in] camera definition
825aa485 81 //! @param theProjection [in] the projection transformation matrix.
82 //! @param theWorldView [in] the world view transformation matrix.
83 //! @param theViewportWidth [in] the width of viewport (for 2d persistence).
84 //! @param theViewportHeight [in] the height of viewport (for 2d persistence).
85 //! @return transformation matrix to be applied to model world transformation of an object.
86 template<class T>
3fe9ce0e 87 NCollection_Mat4<T> Compute (const Handle(Graphic3d_Camera)& theCamera,
88 const NCollection_Mat4<T>& theProjection,
825aa485 89 const NCollection_Mat4<T>& theWorldView,
90 const Standard_Integer theViewportWidth,
91 const Standard_Integer theViewportHeight) const;
92
71d8ccc7 93 //! Apply transformation persistence on specified matrices.
94 //! @param theCamera camera definition
95 //! @param theProjection projection matrix to modify
96 //! @param theWorldView world-view matrix to modify
97 //! @param theViewportWidth viewport width
98 //! @param theViewportHeight viewport height
825aa485 99 template<class T>
3fe9ce0e 100 void Apply (const Handle(Graphic3d_Camera)& theCamera,
101 NCollection_Mat4<T>& theProjection,
825aa485 102 NCollection_Mat4<T>& theWorldView,
103 const Standard_Integer theViewportWidth,
104 const Standard_Integer theViewportHeight) const;
71d8ccc7 105
106 //! Return true if transformation persistence alters projection matrix.
107 bool AltersProjectionMatrix() const
108 {
109 return (Flags & Graphic3d_TMF_PanPers) != 0;
110 }
111
825aa485 112};
113
114// =======================================================================
115// function : Apply
116// purpose : Apply transformation to world view and projection matrices.
117// =======================================================================
118template<class T>
3fe9ce0e 119void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
120 NCollection_Mat4<T>& theProjection,
825aa485 121 NCollection_Mat4<T>& theWorldView,
122 const Standard_Integer theViewportWidth,
123 const Standard_Integer theViewportHeight) const
124{
150ed3d5 125 (void )theViewportWidth;
71d8ccc7 126 if (Flags == Graphic3d_TMF_None
127 || theViewportHeight == 0)
825aa485 128 {
129 return;
130 }
131
3bffef55 132 const Standard_Integer aVPSizeY = theCamera->Tile().IsValid() ? theCamera->Tile().TotalSize.y() : theViewportHeight;
3fe9ce0e 133 if (Flags == Graphic3d_TMF_TriedronPers)
134 {
135 // reset Z focus for trihedron persistence
136 const Standard_Real aFocus = theCamera->IsOrthographic()
137 ? theCamera->Distance()
138 : (theCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative
139 ? Standard_Real(theCamera->ZFocus() * theCamera->Distance())
140 : Standard_Real(theCamera->ZFocus()));
141
142 // scale factor to pixels
143 const gp_XYZ aViewDim = theCamera->ViewDimensions (aFocus);
3bffef55 144 const Standard_Real aScale = Abs(aViewDim.Y()) / Standard_Real(aVPSizeY);
3fe9ce0e 145
146 // offset from the corner
147 const Standard_Real anOffset = Point.z() * aScale;
148
149 const gp_Dir aForward (theCamera->Center().XYZ() - theCamera->Eye().XYZ());
150 gp_XYZ aCenter = theCamera->Center().XYZ() + aForward.XYZ() * (aFocus - theCamera->Distance());
151 if (Point.x() != 0.0)
152 {
153 const gp_Dir aSide = aForward.Crossed (theCamera->Up());
154 if (Point.x() > 0.0)
155 {
156 aCenter += aSide.XYZ() * (Abs(aViewDim.X()) * 0.5 - anOffset);
157 }
158 else
159 {
160 aCenter -= aSide.XYZ() * (Abs(aViewDim.X()) * 0.5 - anOffset);
161 }
162 }
163 if (Point.y() != 0.0)
164 {
165 if (Point.y() > 0.0)
166 {
167 aCenter += theCamera->Up().XYZ() * (Abs(aViewDim.Y()) * 0.5 - anOffset);
168 }
169 else
170 {
171 aCenter -= theCamera->Up().XYZ() * (Abs(aViewDim.Y()) * 0.5 - anOffset);
172 }
173 }
174
175 Graphic3d_TransformUtils::Translate (theWorldView, T(aCenter.X()), T(aCenter.Y()), T(aCenter.Z()));
176 Graphic3d_TransformUtils::Scale (theWorldView, T(aScale), T(aScale), T(aScale));
177 return;
178 }
150ed3d5 179 else if (Flags == Graphic3d_TMF_2d)
825aa485 180 {
150ed3d5 181 const Standard_Real aFocus = theCamera->IsOrthographic()
182 ? theCamera->Distance()
183 : (theCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative
184 ? Standard_Real(theCamera->ZFocus() * theCamera->Distance())
185 : Standard_Real(theCamera->ZFocus()));
186
187 // scale factor to pixels
188 const gp_XYZ aViewDim = theCamera->ViewDimensions (aFocus);
3bffef55 189 const Standard_Real aScale = Abs(aViewDim.Y()) / Standard_Real(aVPSizeY);
150ed3d5 190 gp_XYZ aCenter (0.0, 0.0, -aFocus);
191 if (Point.x() != 0.0)
825aa485 192 {
150ed3d5 193 aCenter.SetX (-aViewDim.X() * 0.5 + Point.z() * aScale);
194 if (Point.x() > 0.0)
195 {
196 aCenter.SetX (-aCenter.X());
197 }
825aa485 198 }
150ed3d5 199 if (Point.y() != 0.0)
825aa485 200 {
150ed3d5 201 aCenter.SetY (-aViewDim.Y() * 0.5 + Point.z() * aScale);
202 if (Point.y() > 0.0)
203 {
204 aCenter.SetY (-aCenter.Y());
205 }
825aa485 206 }
207
825aa485 208 theWorldView.InitIdentity();
150ed3d5 209 Graphic3d_TransformUtils::Translate (theWorldView, T(aCenter.X()), T(aCenter.Y()), T(aCenter.Z()));
210 Graphic3d_TransformUtils::Scale (theWorldView, T(aScale), T(aScale), T(aScale));
211 return;
825aa485 212 }
150ed3d5 213
825aa485 214 {
215 // Compute reference point for transformation in untransformed projection space.
216 NCollection_Vec4<T> aRefPoint (static_cast<T> (Point.x()),
217 static_cast<T> (Point.y()),
218 static_cast<T> (Point.z()),
219 static_cast<T> (1.0));
220 NCollection_Vec4<T> aRefPointProj;
221 if ((Flags & Graphic3d_TMF_PanPers) != Graphic3d_TMF_PanPers)
222 {
223 aRefPointProj = theProjection * (theWorldView * aRefPoint);
224 aRefPointProj /= aRefPointProj.w();
225 }
226
227 // Prevent zooming.
3fe9ce0e 228 if ((Flags & Graphic3d_TMF_ZoomPers) != 0)
91d96372 229 {
1d92133e 230 const T aSize = static_cast<T> (1.0);
231 const Standard_Integer aViewport[4] = { 0, 0, theViewportHeight, theViewportHeight };
232 NCollection_Mat4<T> aWorldView;
233 aWorldView.InitIdentity();
234
235 NCollection_Vec3<T> aWinCoordsRefPoint;
236 Graphic3d_TransformUtils::Project (static_cast<T> (Point.x()),
237 static_cast<T> (Point.y()),
238 static_cast<T> (Point.z()),
239 theWorldView, theProjection, aViewport,
240 aWinCoordsRefPoint.x(), aWinCoordsRefPoint.y(), aWinCoordsRefPoint.z());
241
242 NCollection_Vec3<T> anUnProj1;
243 Graphic3d_TransformUtils::UnProject (aWinCoordsRefPoint.x(), aWinCoordsRefPoint.y(), aWinCoordsRefPoint.z(),
244 aWorldView, theProjection, aViewport,
245 anUnProj1.x(), anUnProj1.y(), anUnProj1.z());
246
247 NCollection_Vec3<T> anUnProj2;
248 Graphic3d_TransformUtils::UnProject (aWinCoordsRefPoint.x(), aWinCoordsRefPoint.y() + aSize, aWinCoordsRefPoint.z(),
249 aWorldView, theProjection, aViewport,
250 anUnProj2.x(), anUnProj2.y(), anUnProj2.z());
251
252 const T aScale = (anUnProj2.y() - anUnProj1.y()) / aSize;
253
254 Graphic3d_TransformUtils::Scale (theWorldView, aScale, aScale, aScale);
825aa485 255 }
256
257 // Prevent translation by nullifying translation component.
3fe9ce0e 258 if ((Flags & Graphic3d_TMF_PanPers) != 0)
825aa485 259 {
260 theWorldView .SetValue (0, 3, static_cast<T> (0.0));
261 theWorldView .SetValue (1, 3, static_cast<T> (0.0));
262 theWorldView .SetValue (2, 3, static_cast<T> (0.0));
263 theProjection.SetValue (0, 3, static_cast<T> (0.0));
264 theProjection.SetValue (1, 3, static_cast<T> (0.0));
265 theProjection.SetValue (2, 3, static_cast<T> (0.0));
266 }
267
825aa485 268 // Prevent rotation by nullifying rotation component.
269 if (Flags & Graphic3d_TMF_RotatePers)
270 {
271 theWorldView.SetValue (0, 0, static_cast<T> (1.0));
272 theWorldView.SetValue (1, 0, static_cast<T> (0.0));
273 theWorldView.SetValue (2, 0, static_cast<T> (0.0));
274
275 theWorldView.SetValue (0, 1, static_cast<T> (0.0));
276 theWorldView.SetValue (1, 1, static_cast<T> (1.0));
277 theWorldView.SetValue (2, 1, static_cast<T> (0.0));
278
279 theWorldView.SetValue (0, 2, static_cast<T> (0.0));
280 theWorldView.SetValue (1, 2, static_cast<T> (0.0));
281 theWorldView.SetValue (2, 2, static_cast<T> (1.0));
282 }
283
3fe9ce0e 284 if ((Flags & Graphic3d_TMF_PanPers) != Graphic3d_TMF_PanPers)
825aa485 285 {
286 NCollection_Mat4<T> anUnviewMat;
287
288 if (!(theProjection * theWorldView).Inverted (anUnviewMat))
289 {
290 Standard_ProgramError::Raise ("Graphic3d_TransformPers::Apply, can not inverse world view projection matrix.");
291 }
292
293 // Move to reference point location in transformed view projection space.
294 aRefPoint = anUnviewMat * aRefPointProj;
295 aRefPoint /= aRefPoint.w();
296
297 Graphic3d_TransformUtils::Translate<T> (theWorldView, aRefPoint.x(), aRefPoint.y(), aRefPoint.z());
298 }
299 }
300}
301
302// =======================================================================
303// function : Apply
304// purpose : Apply transformation to bounding box of presentation.
305// =======================================================================
306template<class T>
3fe9ce0e 307void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
308 const NCollection_Mat4<T>& theProjection,
825aa485 309 const NCollection_Mat4<T>& theWorldView,
310 const Standard_Integer theViewportWidth,
311 const Standard_Integer theViewportHeight,
312 Bnd_Box& theBoundingBox) const
313{
3fe9ce0e 314 if (theBoundingBox.IsVoid())
315 {
316 return;
317 }
318
825aa485 319 T aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
320
321 theBoundingBox.Get (aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
322
323 typename BVH_Box<T, 4>::BVH_VecNt aMin (aXmin, aYmin, aZmin, static_cast<T> (1.0));
324 typename BVH_Box<T, 4>::BVH_VecNt aMax (aXmax, aYmax, aZmax, static_cast<T> (1.0));
325 BVH_Box<T, 4> aBBox (aMin, aMax);
326
3fe9ce0e 327 Apply (theCamera, theProjection, theWorldView, theViewportWidth, theViewportHeight, aBBox);
825aa485 328
329 theBoundingBox = Bnd_Box();
330 theBoundingBox.Update (aBBox.CornerMin().x(), aBBox.CornerMin().y(), aBBox.CornerMin().z(),
331 aBBox.CornerMax().x(), aBBox.CornerMax().y(), aBBox.CornerMax().z());
332}
333
334// =======================================================================
335// function : Apply
336// purpose : Apply transformation to bounding box of presentation.
337// =======================================================================
338template<class T>
3fe9ce0e 339void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
340 const NCollection_Mat4<T>& theProjection,
825aa485 341 const NCollection_Mat4<T>& theWorldView,
342 const Standard_Integer theViewportWidth,
343 const Standard_Integer theViewportHeight,
344 BVH_Box<T, 4>& theBoundingBox) const
345{
3fe9ce0e 346 NCollection_Mat4<T> aTPers = Compute (theCamera, theProjection, theWorldView, theViewportWidth, theViewportHeight);
347 if (aTPers.IsIdentity()
348 || !theBoundingBox.IsValid())
825aa485 349 {
350 return;
351 }
352
353 const typename BVH_Box<T, 4>::BVH_VecNt& aMin = theBoundingBox.CornerMin();
354 const typename BVH_Box<T, 4>::BVH_VecNt& aMax = theBoundingBox.CornerMax();
355
356 typename BVH_Box<T, 4>::BVH_VecNt anArrayOfCorners[8];
357 anArrayOfCorners[0] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMin.z(), static_cast<T> (1.0));
358 anArrayOfCorners[1] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMax.z(), static_cast<T> (1.0));
359 anArrayOfCorners[2] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMin.z(), static_cast<T> (1.0));
360 anArrayOfCorners[3] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMax.z(), static_cast<T> (1.0));
361 anArrayOfCorners[4] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMin.z(), static_cast<T> (1.0));
362 anArrayOfCorners[5] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMax.z(), static_cast<T> (1.0));
363 anArrayOfCorners[6] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMin.z(), static_cast<T> (1.0));
364 anArrayOfCorners[7] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMax.z(), static_cast<T> (1.0));
365
366 theBoundingBox.Clear();
367 for (Standard_Integer anIt = 0; anIt < 8; ++anIt)
368 {
369 typename BVH_Box<T, 4>::BVH_VecNt& aCorner = anArrayOfCorners[anIt];
370 aCorner = aTPers * aCorner;
371 aCorner /= aCorner.w();
372 theBoundingBox.Add (aCorner);
373 }
374}
375
376// =======================================================================
377// function : Compute
378// purpose : Compute transformation.
379// =======================================================================
380template<class T>
3fe9ce0e 381NCollection_Mat4<T> Graphic3d_TransformPers::Compute (const Handle(Graphic3d_Camera)& theCamera,
382 const NCollection_Mat4<T>& theProjection,
825aa485 383 const NCollection_Mat4<T>& theWorldView,
384 const Standard_Integer theViewportWidth,
385 const Standard_Integer theViewportHeight) const
386{
387 if (Flags == Graphic3d_TMF_None)
388 {
389 return NCollection_Mat4<T>();
390 }
391
71d8ccc7 392 NCollection_Mat4<T> aProjection (theProjection);
393 NCollection_Mat4<T> aWorldView (theWorldView);
825aa485 394 NCollection_Mat4<T> anUnviewMat;
71d8ccc7 395 if (AltersProjectionMatrix())
396 {
397 // destructive transformation persistence which directly modifies projection matrix
398 if (!(theProjection * theWorldView).Inverted (anUnviewMat))
399 {
400 return NCollection_Mat4<T>();
401 }
402
403 Apply (theCamera, aProjection, aWorldView, theViewportWidth, theViewportHeight);
404 return anUnviewMat * (aProjection * aWorldView);
405 }
825aa485 406
71d8ccc7 407 if (!theWorldView.Inverted (anUnviewMat))
825aa485 408 {
409 return NCollection_Mat4<T>();
410 }
411
71d8ccc7 412 // compute only world-view matrix difference to avoid floating point instability
413 // caused by projection matrix modifications outside of this algorithm (e.g. by Z-fit)
3fe9ce0e 414 Apply (theCamera, aProjection, aWorldView, theViewportWidth, theViewportHeight);
71d8ccc7 415 return anUnviewMat * aWorldView;
825aa485 416}
417
418#endif // _Graphic3d_TransformPers_HeaderFile