0030640: Visualization, Graphic3d_Camera - add option creating Projection matrix...
[occt.git] / src / Graphic3d / Graphic3d_CullingTool.cxx
1 // Created on: 2013-12-25
2 // Created by: Varvara POSKONINA
3 // Copyright (c) 1999-2014 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 #include <Graphic3d_CullingTool.hxx>
17
18 #include <Precision.hxx>
19
20 #include <limits>
21
22 // =======================================================================
23 // function : Graphic3d_CullingTool
24 // purpose  :
25 // =======================================================================
26 Graphic3d_CullingTool::Graphic3d_CullingTool()
27 : myClipVerts (0, Graphic3d_Camera::FrustumVerticesNB),
28   myIsProjectionParallel (Standard_True),
29   myCamScale (1.0),
30   myPixelSize (1.0)
31 {
32   //
33 }
34
35 // =======================================================================
36 // function : SetViewVolume
37 // purpose  :
38 // =======================================================================
39 void Graphic3d_CullingTool::SetViewVolume (const Handle(Graphic3d_Camera)& theCamera,
40                                            const Graphic3d_Mat4d& theModelWorld)
41 {
42   const bool hasModelTrsf = !theModelWorld.IsIdentity();
43   if (!myWorldViewProjState.IsChanged (theCamera->WorldViewProjState())
44    && !hasModelTrsf)
45   {
46     return;
47   }
48
49   myIsProjectionParallel = theCamera->IsOrthographic();
50   const gp_Dir aCamDir = theCamera->Direction();
51
52   myCamera             = theCamera;
53   myProjectionMat      = theCamera->ProjectionMatrix();
54   myWorldViewMat       = theCamera->OrientationMatrix();
55   myWorldViewProjState = theCamera->WorldViewProjState();
56   myCamEye.SetValues (theCamera->Eye().X(), theCamera->Eye().Y(), theCamera->Eye().Z());
57   myCamDir.SetValues (aCamDir.X(), aCamDir.Y(), aCamDir.Z());
58   if (hasModelTrsf)
59   {
60     Graphic3d_Mat4d aModelInv;
61     theModelWorld.Inverted (aModelInv);
62     myCamEye = (aModelInv * Graphic3d_Vec4d (myCamEye, 1.0)).xyz();
63     myCamDir = (aModelInv * Graphic3d_Vec4d (myCamDir, 0.0)).xyz();
64   }
65   myCamScale = theCamera->IsOrthographic()
66              ? theCamera->Scale()
67              : 2.0 * Tan (theCamera->FOVy() * M_PI / 360.0); // same as theCamera->Scale()/theCamera->Distance()
68
69   // Compute frustum points
70   theCamera->FrustumPoints (myClipVerts, theModelWorld);
71
72   // Compute frustum planes
73   // Vertices go in order:
74   // 0, 2, 1
75   const Standard_Integer aLookup1[] = { 0, 1, 0 };
76   const Standard_Integer aLookup2[] = { 0, 0, 1 };
77   Standard_Integer aShifts[]        = { 0, 0, 0 };
78
79   // Planes go in order:
80   // LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR
81   for (Standard_Integer aFaceIdx = 0; aFaceIdx < 3; ++aFaceIdx)
82   {
83     for (Standard_Integer i = 0; i < 2; ++i)
84     {
85       Graphic3d_Vec3d aPlanePnts[3];
86       for (Standard_Integer aPntIter = 0; aPntIter < 3; ++aPntIter)
87       {
88         aShifts[aFaceIdx] = i;
89         aShifts[(aFaceIdx + 1) % 3] = aLookup1[aPntIter];
90         aShifts[(aFaceIdx + 2) % 3] = aLookup2[aPntIter];
91         
92         aPlanePnts[aPntIter] = myClipVerts[aShifts[0] * 2 * 2 + aShifts[1] * 2 + aShifts[2]];
93       }
94       
95       myClipPlanes[aFaceIdx * 2 + i].Origin = aPlanePnts[0];
96       myClipPlanes[aFaceIdx * 2 + i].Normal =
97         Graphic3d_Vec3d::Cross (aPlanePnts[1] - aPlanePnts[0],
98                                 aPlanePnts[2] - aPlanePnts[0]).Normalized() * (i == 0 ? -1.f : 1.f);
99     }
100   }
101 }
102
103 // =======================================================================
104 // function : SetViewportSize
105 // purpose  :
106 // =======================================================================
107 void Graphic3d_CullingTool::SetViewportSize (Standard_Integer theViewportWidth,
108                                              Standard_Integer theViewportHeight,
109                                              Standard_Real theResolutionRatio)
110 {
111   myViewportHeight = theViewportHeight > 0 ? theViewportHeight : 1;
112   myViewportWidth  = theViewportWidth  > 0 ? theViewportWidth  : 1;
113   myPixelSize = Max (theResolutionRatio / myViewportHeight,
114                      theResolutionRatio / myViewportWidth);
115 }
116
117 // =======================================================================
118 // function : SignedPlanePointDistance
119 // purpose  :
120 // =======================================================================
121 Standard_Real Graphic3d_CullingTool::SignedPlanePointDistance (const Graphic3d_Vec4d& theNormal,
122                                                                const Graphic3d_Vec4d& thePnt)
123 {
124   const Standard_Real aNormLength = std::sqrt (theNormal.x() * theNormal.x()
125                                              + theNormal.y() * theNormal.y()
126                                              + theNormal.z() * theNormal.z());
127
128   if (aNormLength < gp::Resolution())
129     return 0.0;
130
131   const Standard_Real anInvNormLength = 1.0 / aNormLength;
132   const Standard_Real aD  = theNormal.w() * anInvNormLength;
133   const Standard_Real anA = theNormal.x() * anInvNormLength;
134   const Standard_Real aB  = theNormal.y() * anInvNormLength;
135   const Standard_Real aC  = theNormal.z() * anInvNormLength;
136   return aD + (anA * thePnt.x() + aB * thePnt.y() + aC * thePnt.z());
137 }
138
139 // =======================================================================
140 // function : SetCullingDistance
141 // purpose  :
142 // =======================================================================
143 void Graphic3d_CullingTool::SetCullingDistance (CullingContext& theCtx,
144                                                 Standard_Real theDistance) const
145 {
146   theCtx.DistCull = -1.0;
147   if (!myIsProjectionParallel)
148   {
149     theCtx.DistCull = theDistance > 0.0 && !Precision::IsInfinite (theDistance)
150                     ? theDistance
151                     : -1.0;
152   }
153 }
154
155 // =======================================================================
156 // function : SetCullingSize
157 // purpose  :
158 // =======================================================================
159 void Graphic3d_CullingTool::SetCullingSize (CullingContext& theCtx,
160                                             Standard_Real theSize) const
161 {
162   theCtx.SizeCull2 = -1.0;
163   if (theSize > 0.0 && !Precision::IsInfinite (theSize))
164   {
165     theCtx.SizeCull2 = myPixelSize * theSize;
166     theCtx.SizeCull2 *= myCamScale;
167     theCtx.SizeCull2 *= theCtx.SizeCull2;
168   }
169 }
170
171 // =======================================================================
172 // function : CacheClipPtsProjections
173 // purpose  :
174 // =======================================================================
175 void Graphic3d_CullingTool::CacheClipPtsProjections()
176 {
177   // project frustum onto its own normals
178   const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
179   for (Standard_Integer aPlaneIter = 0; aPlaneIter < PlanesNB - 1; aPlaneIter += anIncFactor)
180   {
181     Standard_Real aMaxProj = -std::numeric_limits<Standard_Real>::max();
182     Standard_Real aMinProj =  std::numeric_limits<Standard_Real>::max();
183     for (Standard_Integer aCornerIter = 0; aCornerIter < Graphic3d_Camera::FrustumVerticesNB; ++aCornerIter)
184     {
185       Standard_Real aProjection = myClipVerts[aCornerIter].Dot (myClipPlanes[aPlaneIter].Normal);
186       aMaxProj = Max (aProjection, aMaxProj);
187       aMinProj = Min (aProjection, aMinProj);
188     }
189     myMaxClipProjectionPts[aPlaneIter] = aMaxProj;
190     myMinClipProjectionPts[aPlaneIter] = aMinProj;
191   }
192
193   // project frustum onto main axes
194   Graphic3d_Vec3d anAxes[] = { Graphic3d_Vec3d (1.0, 0.0, 0.0),
195                                Graphic3d_Vec3d (0.0, 1.0, 0.0),
196                                Graphic3d_Vec3d (0.0, 0.0, 1.0) };
197   for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
198   {
199     Standard_Real aMaxProj = -std::numeric_limits<Standard_Real>::max();
200     Standard_Real aMinProj =  std::numeric_limits<Standard_Real>::max();
201     for (Standard_Integer aCornerIter = 0; aCornerIter < Graphic3d_Camera::FrustumVerticesNB; ++aCornerIter)
202     {
203       Standard_Real aProjection = myClipVerts[aCornerIter].Dot (anAxes[aDim]);
204       aMaxProj = Max (aProjection, aMaxProj);
205       aMinProj = Min (aProjection, aMinProj);
206     }
207     myMaxOrthoProjectionPts[aDim] = aMaxProj;
208     myMinOrthoProjectionPts[aDim] = aMinProj;
209   }
210 }