root/OpenSceneGraph/trunk/src/osgSim/LightPointNode.cpp @ 13041

Revision 13041, 12.8 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
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
14#include <osgSim/LightPointNode>
15#include <osgSim/LightPointSystem>
16
17#include "LightPointDrawable.h"
18#include "LightPointSpriteDrawable.h"
19
20#include <osg/Timer>
21#include <osg/BoundingBox>
22#include <osg/BlendFunc>
23#include <osg/Material>
24#include <osg/PointSprite>
25
26#include <osgUtil/CullVisitor>
27
28#include <typeinfo>
29
30namespace osgSim
31{
32
33osg::StateSet* getSingletonLightPointSystemSet()
34{
35    static osg::ref_ptr<osg::StateSet> s_stateset = 0;
36    if (!s_stateset)
37    {
38        s_stateset = new osg::StateSet;
39        // force light point nodes to be drawn after everything else by picking a rendering bin number after
40        // the transparent bin.
41        s_stateset->setRenderBinDetails(20,"DepthSortedBin");
42    }
43    return s_stateset.get();
44}
45
46
47LightPointNode::LightPointNode():
48    _minPixelSize(0.0f),
49    _maxPixelSize(30.0f),
50    _maxVisibleDistance2(FLT_MAX),
51    _lightSystem(0),
52    _pointSprites(false)
53{
54    setStateSet(getSingletonLightPointSystemSet());
55}
56
57/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
58LightPointNode::LightPointNode(const LightPointNode& lpn,const osg::CopyOp& copyop):
59    osg::Node(lpn,copyop),
60    _lightPointList(lpn._lightPointList),
61    _minPixelSize(lpn._minPixelSize),
62    _maxPixelSize(lpn._maxPixelSize),
63    _maxVisibleDistance2(lpn._maxVisibleDistance2),
64    _lightSystem(lpn._lightSystem),
65    _pointSprites(lpn._pointSprites)
66{
67}
68
69unsigned int LightPointNode::addLightPoint(const LightPoint& lp)
70{
71    unsigned int num = _lightPointList.size();
72    _lightPointList.push_back(lp);
73    dirtyBound();
74    return num;
75}
76
77void LightPointNode::removeLightPoint(unsigned int pos)
78{
79    if (pos<_lightPointList.size())
80    {
81        _lightPointList.erase(_lightPointList.begin()+pos);
82        dirtyBound();
83    }
84    dirtyBound();
85}
86
87osg::BoundingSphere LightPointNode::computeBound() const
88{
89    osg::BoundingSphere bsphere;
90    bsphere.init();
91    _bbox.init();
92
93    if (_lightPointList.empty())
94    {
95        return bsphere;
96    }
97
98
99    LightPointList::const_iterator itr;
100    for(itr=_lightPointList.begin();
101        itr!=_lightPointList.end();
102        ++itr)
103    {
104        _bbox.expandBy(itr->_position);
105    }
106
107
108    bsphere.set(_bbox.center(),0.0f);
109
110    for(itr=_lightPointList.begin();
111        itr!=_lightPointList.end();
112        ++itr)
113    {
114        osg::Vec3 dv(itr->_position-bsphere.center());
115        float radius = dv.length()+itr->_radius;
116        if (bsphere.radius()<radius) bsphere.radius()=radius;
117    }
118
119    bsphere.radius()+=1.0f;
120    return bsphere;
121}
122
123
124void LightPointNode::traverse(osg::NodeVisitor& nv)
125{
126    if (_lightPointList.empty())
127    {
128        // no light points so no op.
129        return;
130    }
131
132    //#define USE_TIMER
133    #ifdef USE_TIMER
134    osg::Timer timer;
135    osg::Timer_t t1=0,t2=0,t3=0,t4=0,t5=0,t6=0,t7=0,t8=0;
136    #endif
137
138
139#ifdef USE_TIMER
140    t1 = timer.tick();
141#endif
142
143    osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
144
145#ifdef USE_TIMER
146    t2 = timer.tick();
147#endif
148
149
150    // should we disable small feature culling here?
151    if (cv /*&& !cv->isCulled(_bbox)*/)
152    {
153
154        osg::Matrix matrix = *(cv->getModelViewMatrix());
155        osg::RefMatrix& projection = *(cv->getProjectionMatrix());
156        osgUtil::StateGraph* rg = cv->getCurrentStateGraph();
157
158        if (rg->leaves_empty())
159        {
160            // this is first leaf to be added to StateGraph
161            // and therefore should not already know current render bin,
162            // so need to add it.
163            cv->getCurrentRenderBin()->addStateGraph(rg);
164        }
165
166#ifdef USE_TIMER
167        t3 = timer.tick();
168#endif
169
170
171        LightPointDrawable* drawable = NULL;
172        osg::Referenced* object = rg->getUserData();
173        if (object)
174        {
175            if (typeid(*object)==typeid(LightPointDrawable))
176            {
177                // resuse the user data attached to the render graph.
178                drawable = static_cast<LightPointDrawable*>(object);
179
180            }
181            else if (typeid(*object)==typeid(LightPointSpriteDrawable))
182            {
183                drawable = static_cast<LightPointSpriteDrawable*>(object);
184            }
185            else
186            {
187                // will need to replace UserData.
188                OSG_WARN << "Warning: Replacing osgUtil::StateGraph::_userData to support osgSim::LightPointNode, may have undefined results."<<std::endl;
189            }
190        }
191
192        if (!drawable)
193        {
194            drawable = _pointSprites ? new LightPointSpriteDrawable : new LightPointDrawable;
195            rg->setUserData(drawable);
196
197            if (cv->getFrameStamp())
198            {
199                drawable->setSimulationTime(cv->getFrameStamp()->getSimulationTime());
200            }
201        }
202
203        // search for a drawable in the RenderLeaf list equal to the attached the one attached to StateGraph user data
204        // as this will be our special light point drawable.
205        osgUtil::StateGraph::LeafList::iterator litr;
206        for(litr = rg->_leaves.begin();
207            litr != rg->_leaves.end() && (*litr)->_drawable.get()!=drawable;
208            ++litr)
209        {}
210
211        if (litr == rg->_leaves.end())
212        {
213            // haven't found the drawable added in the RenderLeaf list, therefore this may be the
214            // first time through LightPointNode in this frame, so need to add drawable into the StateGraph RenderLeaf list
215            // and update its time signatures.
216
217            drawable->reset();
218            rg->addLeaf(new osgUtil::RenderLeaf(drawable,&projection,NULL,FLT_MAX));
219
220            // need to update the drawable's frame count.
221            if (cv->getFrameStamp())
222            {
223                drawable->updateSimulationTime(cv->getFrameStamp()->getSimulationTime());
224            }
225
226        }
227
228#ifdef USE_TIMER
229        t4 = timer.tick();
230#endif
231
232
233#ifdef USE_TIMER
234        t7 = timer.tick();
235#endif
236
237
238        if (cv->getComputeNearFarMode() != osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR)
239            cv->updateCalculatedNearFar(matrix,_bbox);
240
241
242        const float minimumIntensity = 1.0f/256.0f;
243        const osg::Vec3 eyePoint = cv->getEyeLocal();
244
245        double time=drawable->getSimulationTime();
246        double timeInterval=drawable->getSimulationTimeInterval();
247
248        const osg::Polytope clipvol(cv->getCurrentCullingSet().getFrustum());
249        const bool computeClipping = false;//(clipvol.getCurrentMask()!=0);
250
251        //LightPointDrawable::ColorPosition cp;
252        for(LightPointList::iterator itr=_lightPointList.begin();
253            itr!=_lightPointList.end();
254            ++itr)
255        {
256            const LightPoint& lp = *itr;
257
258            if (!lp._on) continue;
259
260            const osg::Vec3& position = lp._position;
261
262            // skip light point if it is not contianed in the view frustum.
263            if (computeClipping && !clipvol.contains(position)) continue;
264
265            // delta vector between eyepoint and light point.
266            osg::Vec3 dv(eyePoint-position);
267
268            float intensity = (_lightSystem.valid()) ? _lightSystem->getIntensity() : lp._intensity;
269
270            // slip light point if its intensity is 0.0 or negative.
271            if (intensity<=minimumIntensity) continue;
272
273            // (SIB) Clip on distance, if close to limit, add transparancy
274            float distanceFactor = 1.0f;
275            if (_maxVisibleDistance2!=FLT_MAX)
276            {
277                if (dv.length2()>_maxVisibleDistance2) continue;
278                else if (_maxVisibleDistance2 > 0)
279                    distanceFactor = 1.0f - osg::square(dv.length2() / _maxVisibleDistance2);
280            }
281
282            osg::Vec4 color = lp._color;
283
284            // check the sector.
285            if (lp._sector.valid())
286            {
287                intensity *= (*lp._sector)(dv);
288
289                // skip light point if it is intensity is 0.0 or negative.
290                if (intensity<=minimumIntensity) continue;
291
292            }
293
294            // temporary accounting of intensity.
295            //color *= intensity;
296
297            // check the blink sequence.
298            bool doBlink = lp._blinkSequence.valid();
299            if (doBlink && _lightSystem.valid())
300                doBlink = (_lightSystem->getAnimationState() == LightPointSystem::ANIMATION_ON);
301
302            if (doBlink)
303            {
304                osg::Vec4 bs = lp._blinkSequence->color(time,timeInterval);
305                color[0] *= bs[0];
306                color[1] *= bs[1];
307                color[2] *= bs[2];
308                color[3] *= bs[3];
309            }
310
311            // if alpha value is less than the min intentsity then skip
312            if (color[3]<=minimumIntensity) continue;
313
314            float pixelSize = cv->pixelSize(position,lp._radius);
315
316            //            cout << "pixelsize = "<<pixelSize<<endl;
317
318            // adjust pixel size to account for intensity.
319            if (intensity!=1.0) pixelSize *= sqrt(intensity);
320
321            // adjust alpha to account for max range (Fade on distance)
322            color[3] *= distanceFactor;
323
324            // round up to the minimum pixel size if required.
325            float orgPixelSize = pixelSize;
326            if (pixelSize<_minPixelSize) pixelSize = _minPixelSize;
327
328            osg::Vec3 xpos(position*matrix);
329
330            if (lp._blendingMode==LightPoint::BLENDED)
331            {
332                if (pixelSize<1.0f)
333                {
334                    // need to use alpha blending...
335                    color[3] *= pixelSize;
336                    // color[3] *= osg::square(pixelSize);
337
338                    if (color[3]<=minimumIntensity) continue;
339
340                    drawable->addBlendedLightPoint(0, xpos,color);
341                }
342                else if (pixelSize<_maxPixelSize)
343                {
344
345                    unsigned int lowerBoundPixelSize = (unsigned int)pixelSize;
346                    float remainder = osg::square(pixelSize-(float)lowerBoundPixelSize);
347
348                    // (SIB) Add transparency if pixel is clamped to minpixelsize
349                    if (orgPixelSize<_minPixelSize)
350                        color[3] *= (2.0/3.0) + (1.0/3.0) * sqrt(orgPixelSize / pixelSize);
351
352                    drawable->addBlendedLightPoint(lowerBoundPixelSize-1, xpos,color);
353                    color[3] *= remainder;
354                    drawable->addBlendedLightPoint(lowerBoundPixelSize, xpos,color);
355                }
356                else // use a billboard geometry.
357                {
358                    drawable->addBlendedLightPoint((unsigned int)(_maxPixelSize-1.0), xpos,color);
359                }
360            }
361            else // ADDITIVE blending.
362            {
363                if (pixelSize<1.0f)
364                {
365                    // need to use alpha blending...
366                    color[3] *= pixelSize;
367                    // color[3] *= osg::square(pixelSize);
368
369                    if (color[3]<=minimumIntensity) continue;
370
371                    drawable->addAdditiveLightPoint(0, xpos,color);
372                }
373                else if (pixelSize<_maxPixelSize)
374                {
375
376                    unsigned int lowerBoundPixelSize = (unsigned int)pixelSize;
377                    float remainder = osg::square(pixelSize-(float)lowerBoundPixelSize);
378
379                    // (SIB) Add transparency if pixel is clamped to minpixelsize
380                    if (orgPixelSize<_minPixelSize)
381                        color[3] *= (2.0/3.0) + (1.0/3.0) * sqrt(orgPixelSize / pixelSize);
382
383                    float alpha = color[3];
384                    color[3] = alpha*(1.0f-remainder);
385                    drawable->addAdditiveLightPoint(lowerBoundPixelSize-1, xpos,color);
386                    color[3] = alpha*remainder;
387                    drawable->addAdditiveLightPoint(lowerBoundPixelSize, xpos,color);
388                }
389                else // use a billboard geometry.
390                {
391                    drawable->addAdditiveLightPoint((unsigned int)(_maxPixelSize-1.0), xpos,color);
392                }
393            }
394        }
395
396#ifdef USE_TIMER
397        t8 = timer.tick();
398#endif
399
400    }
401#ifdef USE_TIMER
402    cout << "compute"<<endl;
403    cout << "  t2-t1="<<t2-t1<<endl;
404    cout << "  t4-t3="<<t4-t3<<endl;
405    cout << "  t6-t5="<<t6-t5<<endl;
406    cout << "  t8-t7="<<t8-t7<<endl;
407    cout << "_lightPointList.size()="<<_lightPointList.size()<<endl;
408    cout << "  t8-t7/size = "<<(float)(t8-t7)/(float)_lightPointList.size()<<endl;
409#endif
410}
411
412
413} // end of namespace
Note: See TracBrowser for help on using the browser.