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