1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12 */
13 #include <osg/ClusterCullingCallback>
14 #include <osg/TriangleFunctor>
15 #include <osg/CullSettings>
16 
17 using namespace osg;
18 
19 
20 ///////////////////////////////////////////////////////////////////////////////////////////
21 //
22 //  Cluster culling callback
23 //
24 
ClusterCullingCallback()25 ClusterCullingCallback::ClusterCullingCallback():
26     _radius(-1.0f),
27     _deviation(-1.0f)
28 {
29 }
30 
ClusterCullingCallback(const ClusterCullingCallback & ccc,const CopyOp & copyop)31 ClusterCullingCallback::ClusterCullingCallback(const ClusterCullingCallback& ccc,const CopyOp& copyop):
32     Drawable::CullCallback(ccc,copyop),
33     _controlPoint(ccc._controlPoint),
34     _normal(ccc._normal),
35     _radius(ccc._radius),
36     _deviation(ccc._deviation)
37 {
38 }
39 
ClusterCullingCallback(const osg::Vec3 & controlPoint,const osg::Vec3 & normal,float deviation)40 ClusterCullingCallback::ClusterCullingCallback(const osg::Vec3& controlPoint, const osg::Vec3& normal, float deviation):
41     _controlPoint(controlPoint),
42     _normal(normal),
43     _radius(-1.0f),
44     _deviation(deviation)
45 {
46 }
47 
ClusterCullingCallback(const osg::Drawable * drawable)48 ClusterCullingCallback::ClusterCullingCallback(const osg::Drawable* drawable)
49 {
50     computeFrom(drawable);
51 }
52 
53 struct ComputeAveragesFunctor
54 {
55 
ComputeAveragesFunctorComputeAveragesFunctor56     ComputeAveragesFunctor():
57         _num(0) {}
58 
operator ()ComputeAveragesFunctor59     inline void operator() ( const osg::Vec3 &v1, const osg::Vec3 &v2, const osg::Vec3 &v3, bool)
60     {
61         // calc orientation of triangle.
62         osg::Vec3d normal = (v2-v1)^(v3-v1);
63         if (normal.normalize()!=0.0f)
64         {
65             _normal += normal;
66         }
67         _center += v1;
68         _center += v2;
69         _center += v3;
70 
71         ++_num;
72 
73     }
74 
centerComputeAveragesFunctor75     osg::Vec3 center() { return _center /  (double)(3*_num); }
normalComputeAveragesFunctor76     osg::Vec3 normal() { _normal.normalize(); return _normal; }
77 
78     unsigned int _num;
79     Vec3d _center;
80     Vec3d _normal;
81 };
82 
83 struct ComputeDeviationFunctor
84 {
85 
ComputeDeviationFunctorComputeDeviationFunctor86     ComputeDeviationFunctor():
87         _deviation(1.0),
88         _radius2(0.0) {}
89 
setComputeDeviationFunctor90     void set(const osg::Vec3& center,const osg::Vec3& normal)
91     {
92         _center = center;
93         _normal = normal;
94     }
95 
operator ()ComputeDeviationFunctor96     inline void operator() ( const osg::Vec3 &v1, const osg::Vec3 &v2, const osg::Vec3 &v3, bool)
97     {
98         // calc orientation of triangle.
99         osg::Vec3 normal = (v2-v1)^(v3-v1);
100         if (normal.normalize()!=0.0f)
101         {
102             _deviation = osg::minimum(_normal*normal,_deviation);
103         }
104         _radius2 = osg::maximum((v1-_center).length2(),_radius2);
105         _radius2 = osg::maximum((v2-_center).length2(),_radius2);
106         _radius2 = osg::maximum((v3-_center).length2(),_radius2);
107 
108     }
109     osg::Vec3 _center;
110     osg::Vec3 _normal;
111     float _deviation;
112     float _radius2;
113 };
114 
115 
computeFrom(const osg::Drawable * drawable)116 void ClusterCullingCallback::computeFrom(const osg::Drawable* drawable)
117 {
118     TriangleFunctor<ComputeAveragesFunctor> caf;
119     drawable->accept(caf);
120 
121     _controlPoint = caf.center();
122     _normal = caf.normal();
123 
124     TriangleFunctor<ComputeDeviationFunctor> cdf;
125     cdf.set(_controlPoint,_normal);
126     drawable->accept(cdf);
127 
128 //    OSG_NOTICE<<"ClusterCullingCallback::computeFrom() _controlPoint="<<_controlPoint<<std::endl;
129 //    OSG_NOTICE<<"                                      _normal="<<_normal<<std::endl;
130 //    OSG_NOTICE<<"                                      cdf._deviation="<<cdf._deviation<<std::endl;
131 
132 
133     if (_normal.length2()==0.0) _deviation = -1.0f;
134     else
135     {
136         float angle = acosf(cdf._deviation)+osg::PI*0.5f;
137         if (angle<osg::PI) _deviation = cosf(angle);
138         else _deviation = -1.0f;
139     }
140 
141     _radius = sqrtf(cdf._radius2);
142 }
143 
set(const osg::Vec3 & controlPoint,const osg::Vec3 & normal,float deviation,float radius)144 void ClusterCullingCallback::set(const osg::Vec3& controlPoint, const osg::Vec3& normal, float deviation, float radius)
145 {
146     _controlPoint = controlPoint;
147     _normal = normal;
148     _deviation = deviation;
149     _radius = radius;
150 }
151 
transform(const osg::Matrixd & matrix)152 void ClusterCullingCallback::transform(const osg::Matrixd& matrix)
153 {
154     _controlPoint = Vec3d(_controlPoint)*matrix;
155     _normal = Matrixd::transform3x3(Matrixd::inverse(matrix),Vec3d(_normal));
156     _normal.normalize();
157 }
158 
159 
cull(osg::NodeVisitor * nv,osg::Drawable *,osg::State *) const160 bool ClusterCullingCallback::cull(osg::NodeVisitor* nv, osg::Drawable* , osg::State*) const
161 {
162     CullSettings* cs = dynamic_cast<CullSettings*>(nv);
163     if (cs && !(cs->getCullingMode() & CullSettings::CLUSTER_CULLING))
164     {
165         // cluster culling switched off cull settings.
166         return false;
167     }
168 
169     if (_deviation<=-1.0f)
170     {
171         // cluster culling switch off by deviation.
172         return false;
173     }
174 
175     osg::Vec3 eye_cp = nv->getViewPoint() - _controlPoint;
176     float radius = eye_cp.length();
177 
178     if (radius<_radius)
179     {
180         return false;
181     }
182 
183 
184     float deviation = (eye_cp * _normal)/radius;
185 
186 //    OSG_NOTICE<<"ClusterCullingCallback::cull() _normal="<<_normal<<" _controlPointtest="<<_controlPoint<<" eye_cp="<<eye_cp<<std::endl;
187 //    OSG_NOTICE<<"                             deviation="<<deviation<<" _deviation="<<_deviation<<" test="<<(deviation < _deviation)<<std::endl;
188 
189     return deviation < _deviation;
190 }
191 
192 
operator ()(Node * node,NodeVisitor * nv)193 void ClusterCullingCallback::operator()(Node* node, NodeVisitor* nv)
194 {
195     if (nv)
196     {
197         if (cull(nv,0,static_cast<State *>(0))) return;
198 
199         traverse(node,nv);
200     }
201 }
202