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 #ifndef _Graphic3d_CullingTool_HeaderFile 17 #define _Graphic3d_CullingTool_HeaderFile 18 19 #include <Graphic3d_Camera.hxx> 20 #include <Graphic3d_Vec4.hxx> 21 #include <Graphic3d_WorldViewProjState.hxx> 22 23 //! Graphic3d_CullingTool class provides a possibility to store parameters of view volume, 24 //! such as its vertices and equations, and contains methods detecting if given AABB overlaps view volume. 25 class Graphic3d_CullingTool 26 { 27 public: 28 //! Auxiliary structure holding non-persistent culling options. 29 struct CullingContext 30 { 31 Standard_Real DistCull; //!< culling distance 32 Standard_Real SizeCull2; //!< squared culling size 33 34 //! Empty constructor. CullingContextGraphic3d_CullingTool::CullingContext35 CullingContext() : DistCull (-1.0), SizeCull2 (-1.0) {} 36 }; 37 38 //! Auxiliary structure representing 3D plane. 39 struct Plane 40 { 41 //! Creates default plane. PlaneGraphic3d_CullingTool::Plane42 Plane() 43 : Origin (0.0, 0.0, 0.0), 44 Normal (0.0, 0.0, 1.0) {} 45 46 //! Creates plane with specific parameters. PlaneGraphic3d_CullingTool::Plane47 Plane (const Graphic3d_Vec3d& theOrigin, 48 const Graphic3d_Vec3d& theNormal) 49 : Origin (theOrigin), 50 Normal (theNormal) {} 51 52 Graphic3d_Vec3d Origin; 53 Graphic3d_Vec3d Normal; 54 }; 55 56 public: 57 58 //! Creates an empty selector object with parallel projection type by default. 59 Standard_EXPORT Graphic3d_CullingTool(); 60 61 //! Retrieves view volume's planes equations and its vertices from projection and world-view matrices. 62 //! @param theCamera [in] camera definition 63 //! @param theModelWorld [in] optional object transformation for computing frustum in object local coordinate system 64 Standard_EXPORT void SetViewVolume (const Handle(Graphic3d_Camera)& theCamera, 65 const Graphic3d_Mat4d& theModelWorld = Graphic3d_Mat4d()); 66 67 Standard_EXPORT void SetViewportSize (Standard_Integer theViewportWidth, 68 Standard_Integer theViewportHeight, 69 Standard_Real theResolutionRatio); 70 71 //! Setup distance culling. 72 Standard_EXPORT void SetCullingDistance (CullingContext& theCtx, 73 Standard_Real theDistance) const; 74 75 //! Setup size culling. 76 Standard_EXPORT void SetCullingSize (CullingContext& theCtx, 77 Standard_Real theSize) const; 78 79 //! Caches view volume's vertices projections along its normals and AABBs dimensions. 80 //! Must be called at the beginning of each BVH tree traverse loop. 81 Standard_EXPORT void CacheClipPtsProjections(); 82 83 //! Checks whether given AABB should be entirely culled or not. 84 //! @param theCtx [in] culling properties 85 //! @param theMinPnt [in] maximum point of AABB 86 //! @param theMaxPnt [in] minimum point of AABB 87 //! @param theIsInside [out] flag indicating if AABB is fully inside; initial value should be set to TRUE 88 //! @return TRUE if AABB is completely outside of view frustum or culled by size/distance; 89 //! FALSE in case of partial or complete overlap (use theIsInside to distinguish) IsCulled(const CullingContext & theCtx,const Graphic3d_Vec3d & theMinPnt,const Graphic3d_Vec3d & theMaxPnt,Standard_Boolean * theIsInside=NULL) const90 bool IsCulled (const CullingContext& theCtx, 91 const Graphic3d_Vec3d& theMinPnt, 92 const Graphic3d_Vec3d& theMaxPnt, 93 Standard_Boolean* theIsInside = NULL) const 94 { 95 return IsOutFrustum(theMinPnt, theMaxPnt, theIsInside) 96 || IsTooDistant(theCtx, theMinPnt, theMaxPnt, theIsInside) 97 || IsTooSmall (theCtx, theMinPnt, theMaxPnt); 98 } 99 100 //! Return the camera definition. Handle(Graphic3d_Camera)101 const Handle(Graphic3d_Camera)& Camera() const { return myCamera; } 102 103 //! Returns current projection matrix. ProjectionMatrix() const104 const Graphic3d_Mat4d& ProjectionMatrix() const 105 { 106 return myProjectionMat; 107 } 108 109 //! Returns current world view transformation matrix. WorldViewMatrix() const110 const Graphic3d_Mat4d& WorldViewMatrix() const 111 { 112 return myWorldViewMat; 113 } 114 ViewportWidth() const115 Standard_Integer ViewportWidth() const 116 { 117 return myViewportWidth; 118 } 119 ViewportHeight() const120 Standard_Integer ViewportHeight() const 121 { 122 return myViewportHeight; 123 } 124 125 //! Returns state of current world view projection transformation matrices. WorldViewProjState() const126 const Graphic3d_WorldViewProjState& WorldViewProjState() const 127 { 128 return myWorldViewProjState; 129 } 130 131 //! Returns camera eye position. CameraEye() const132 const Graphic3d_Vec3d& CameraEye() const { return myCamEye; } 133 134 //! Returns camera direction. CameraDirection() const135 const Graphic3d_Vec3d& CameraDirection() const { return myCamDir; } 136 137 public: 138 139 //! Calculates signed distance from plane to point. 140 //! @param theNormal [in] the plane's normal. 141 //! @param thePnt [in] 142 Standard_EXPORT Standard_Real SignedPlanePointDistance (const Graphic3d_Vec4d& theNormal, 143 const Graphic3d_Vec4d& thePnt); 144 145 //! Detects if AABB overlaps view volume using separating axis theorem (SAT). 146 //! @param theMinPnt [in] maximum point of AABB 147 //! @param theMaxPnt [in] minimum point of AABB 148 //! @param theIsInside [out] flag indicating if AABB is fully inside; initial value should be set to TRUE 149 //! @return TRUE if AABB is completely outside of view frustum; 150 //! FALSE in case of partial or complete overlap (use theIsInside to distinguish) 151 //! @sa SelectMgr_Frustum::hasOverlap() IsOutFrustum(const Graphic3d_Vec3d & theMinPnt,const Graphic3d_Vec3d & theMaxPnt,Standard_Boolean * theIsInside=NULL) const152 bool IsOutFrustum (const Graphic3d_Vec3d& theMinPnt, 153 const Graphic3d_Vec3d& theMaxPnt, 154 Standard_Boolean* theIsInside = NULL) const 155 { 156 // E1 157 // |_ E0 158 // / 159 // E2 160 if (theMinPnt[0] > myMaxOrthoProjectionPts[0] // E0 test (x axis) 161 || theMaxPnt[0] < myMinOrthoProjectionPts[0] 162 || theMinPnt[1] > myMaxOrthoProjectionPts[1] // E1 test (y axis) 163 || theMaxPnt[1] < myMinOrthoProjectionPts[1] 164 || theMinPnt[2] > myMaxOrthoProjectionPts[2] // E2 test (z axis) 165 || theMaxPnt[2] < myMinOrthoProjectionPts[2]) 166 { 167 return true; 168 } 169 if (theIsInside != NULL 170 && *theIsInside) 171 { 172 *theIsInside = theMinPnt[0] >= myMinOrthoProjectionPts[0] // E0 test (x axis) 173 && theMaxPnt[0] <= myMaxOrthoProjectionPts[0] 174 && theMinPnt[1] >= myMinOrthoProjectionPts[1] // E1 test (y axis) 175 && theMaxPnt[1] <= myMaxOrthoProjectionPts[1] 176 && theMinPnt[1] >= myMinOrthoProjectionPts[2] // E2 test (z axis) 177 && theMaxPnt[1] <= myMaxOrthoProjectionPts[2]; 178 } 179 180 const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1; 181 for (Standard_Integer aPlaneIter = 0; aPlaneIter < PlanesNB - 1; aPlaneIter += anIncFactor) 182 { 183 // frustum normals 184 const Graphic3d_Vec3d& anAxis = myClipPlanes[aPlaneIter].Normal; 185 const Graphic3d_Vec3d aPVertex (anAxis.x() > 0.0 ? theMaxPnt.x() : theMinPnt.x(), 186 anAxis.y() > 0.0 ? theMaxPnt.y() : theMinPnt.y(), 187 anAxis.z() > 0.0 ? theMaxPnt.z() : theMinPnt.z()); 188 const Standard_Real aPnt0 = aPVertex.Dot (anAxis); 189 if (theIsInside == NULL 190 && aPnt0 >= myMinClipProjectionPts[aPlaneIter] 191 && aPnt0 <= myMaxClipProjectionPts[aPlaneIter]) 192 { 193 continue; 194 } 195 196 const Graphic3d_Vec3d aNVertex (anAxis.x() > 0.0 ? theMinPnt.x() : theMaxPnt.x(), 197 anAxis.y() > 0.0 ? theMinPnt.y() : theMaxPnt.y(), 198 anAxis.z() > 0.0 ? theMinPnt.z() : theMaxPnt.z()); 199 const Standard_Real aPnt1 = aNVertex.Dot (anAxis); 200 201 const Standard_Real aBoxProjMin = aPnt0 < aPnt1 ? aPnt0 : aPnt1; 202 const Standard_Real aBoxProjMax = aPnt0 > aPnt1 ? aPnt0 : aPnt1; 203 if (aBoxProjMin > myMaxClipProjectionPts[aPlaneIter] 204 || aBoxProjMax < myMinClipProjectionPts[aPlaneIter]) 205 { 206 return true; 207 } 208 209 if (theIsInside != NULL 210 && *theIsInside) 211 { 212 *theIsInside = aBoxProjMin >= myMinClipProjectionPts[aPlaneIter] 213 && aBoxProjMax <= myMaxClipProjectionPts[aPlaneIter]; 214 } 215 } 216 return false; 217 } 218 219 //! Returns TRUE if given AABB should be discarded by distance culling criterion. 220 //! @param theMinPnt [in] maximum point of AABB 221 //! @param theMaxPnt [in] minimum point of AABB 222 //! @param theIsInside [out] flag indicating if AABB is fully inside; initial value should be set to TRUE 223 //! @return TRUE if AABB is completely behind culling distance; 224 //! FALSE in case of partial or complete overlap (use theIsInside to distinguish) IsTooDistant(const CullingContext & theCtx,const Graphic3d_Vec3d & theMinPnt,const Graphic3d_Vec3d & theMaxPnt,Standard_Boolean * theIsInside=NULL) const225 bool IsTooDistant (const CullingContext& theCtx, 226 const Graphic3d_Vec3d& theMinPnt, 227 const Graphic3d_Vec3d& theMaxPnt, 228 Standard_Boolean* theIsInside = NULL) const 229 { 230 if (theCtx.DistCull <= 0.0) 231 { 232 return false; 233 } 234 235 // check distance to the bounding sphere as fast approximation 236 const Graphic3d_Vec3d aSphereCenter = (theMinPnt + theMaxPnt) * 0.5; 237 const Standard_Real aSphereRadius = (theMaxPnt - theMinPnt).maxComp() * 0.5; 238 const Standard_Real aDistToCenter = (aSphereCenter - myCamEye).Modulus(); 239 if ((aDistToCenter - aSphereRadius) > theCtx.DistCull) 240 { 241 // clip if closest point is behind culling distance 242 return true; 243 } 244 if (theIsInside != NULL 245 && *theIsInside) 246 { 247 // check if farthest point is before culling distance 248 *theIsInside = (aDistToCenter + aSphereRadius) <= theCtx.DistCull; 249 } 250 return false; 251 } 252 253 //! Returns TRUE if given AABB should be discarded by size culling criterion. IsTooSmall(const CullingContext & theCtx,const Graphic3d_Vec3d & theMinPnt,const Graphic3d_Vec3d & theMaxPnt) const254 bool IsTooSmall (const CullingContext& theCtx, 255 const Graphic3d_Vec3d& theMinPnt, 256 const Graphic3d_Vec3d& theMaxPnt) const 257 { 258 if (theCtx.SizeCull2 <= 0.0) 259 { 260 return false; 261 } 262 263 const Standard_Real aBoxDiag2 = (theMaxPnt - theMinPnt).SquareModulus(); 264 if (myIsProjectionParallel) 265 { 266 return aBoxDiag2 < theCtx.SizeCull2; 267 } 268 269 // note that distances behind the Eye (aBndDist < 0) are not scaled correctly here, 270 // but majority of such objects should be culled by frustum 271 const Graphic3d_Vec3d aBndCenter = (theMinPnt + theMaxPnt) * 0.5; 272 const Standard_Real aBndDist = (aBndCenter - myCamEye).Dot (myCamDir); 273 return aBoxDiag2 < theCtx.SizeCull2 * aBndDist * aBndDist; 274 } 275 276 protected: 277 278 //! Enumerates planes of view volume. 279 enum 280 { 281 Plane_Left, 282 Plane_Right, 283 Plane_Bottom, 284 Plane_Top, 285 Plane_Near, 286 Plane_Far, 287 PlanesNB 288 }; 289 290 protected: 291 292 Plane myClipPlanes[PlanesNB]; //!< Planes 293 NCollection_Array1<Graphic3d_Vec3d> myClipVerts; //!< Vertices 294 295 Handle(Graphic3d_Camera) myCamera; //!< camera definition 296 297 // for caching clip points projections onto viewing area normals once per traverse 298 // ORDER: LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR 299 Standard_Real myMaxClipProjectionPts[PlanesNB]; //!< Max view volume's vertices projections onto its normals 300 Standard_Real myMinClipProjectionPts[PlanesNB]; //!< Min view volume's vertices projections onto its normals 301 302 // for caching clip points projections onto AABB normals once per traverse 303 // ORDER: E0, E1, E2 304 Standard_Real myMaxOrthoProjectionPts[3]; //!< Max view volume's vertices projections onto normalized dimensions of AABB 305 Standard_Real myMinOrthoProjectionPts[3]; //!< Min view volume's vertices projections onto normalized dimensions of AABB 306 307 Standard_Boolean myIsProjectionParallel; 308 309 Graphic3d_Mat4d myProjectionMat; 310 Graphic3d_Mat4d myWorldViewMat; 311 312 Standard_Integer myViewportWidth; 313 Standard_Integer myViewportHeight; 314 315 Graphic3d_WorldViewProjState myWorldViewProjState; //!< State of world view projection matrices. 316 317 Graphic3d_Vec3d myCamEye; //!< camera eye position for distance culling 318 Graphic3d_Vec3d myCamDir; //!< camera direction for size culling 319 Standard_Real myCamScale; //!< camera scale for size culling 320 Standard_Real myPixelSize; //!< pixel size for size culling 321 322 }; 323 324 #endif // _Graphic3d_CullingTool_HeaderFile 325