root/OpenSceneGraph/trunk/src/osgShadow/ShadowVolume.cpp @ 13041

Revision 13041, 13.1 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 <osgShadow/ShadowVolume>
15#include <osgShadow/ShadowedScene>
16#include <osg/Notify>
17
18#include <osg/LightModel>
19#include <osg/Depth>
20#include <osg/BlendFunc>
21#include <osg/Camera>
22#include <osg/Stencil>
23#include <osg/StencilTwoSided>
24#include <osg/CullFace>
25#include <osg/Geometry>
26#include <osg/ComputeBoundsVisitor>
27#include <osg/io_utils>
28
29using namespace osgShadow;
30
31
32///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
33//
34//   ShadowVolume
35//
36ShadowVolume::ShadowVolume():
37    _drawMode(osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED),
38    _dynamicShadowVolumes(false)
39{
40    // _drawMode = osgShadow::ShadowVolumeGeometry::GEOMETRY;
41
42    OSG_INFO<<"Warning: osgShadow::ShadowVolume technique is still in development, with current limitations that make it unsuitable for deployment. Please contact the osg-users for an update of developements."<<std::endl;
43}
44
45ShadowVolume::ShadowVolume(const ShadowVolume& sv, const osg::CopyOp& copyop):
46    ShadowTechnique(sv,copyop),
47    _drawMode(sv._drawMode),
48    _dynamicShadowVolumes(sv._dynamicShadowVolumes)
49{
50}
51
52ShadowVolume::~ShadowVolume()
53{
54}
55
56void ShadowVolume::setDrawMode(osgShadow::ShadowVolumeGeometry::DrawMode drawMode)
57{
58    if (_drawMode == drawMode) return;
59
60    _drawMode = drawMode;
61
62    dirty();
63}
64
65void ShadowVolume::setDynamicShadowVolumes(bool dynamicShadowVolumes)
66{
67    _dynamicShadowVolumes = dynamicShadowVolumes;
68}
69
70
71void ShadowVolume::init()
72{
73    if (!_shadowedScene) return;
74
75    // get the bounds of the model.
76    osg::ComputeBoundsVisitor cbbv;
77    _shadowedScene->osg::Group::traverse(cbbv);
78
79
80    osg::Vec4 ambient(0.2,0.2,0.2,1.0);
81    osg::Vec4 diffuse(0.8,0.8,0.8,1.0);
82    osg::Vec4 zero_colour(0.0,0.0,0.0,1.0);
83
84    osg::Vec4 lightpos;
85    lightpos.set(0.5f,0.25f,0.8f,0.0f);
86
87    // set up the occluder
88    _occluder = new osgShadow::OccluderGeometry;
89    _occluder->computeOccluderGeometry(_shadowedScene);
90//    cbbv.getPolytope(_occluder->getBoundingPolytope(),0.001);
91    cbbv.getBase(_occluder->getBoundingPolytope(),0.001);
92
93
94    // set up shadow volume
95    _shadowVolume = new osgShadow::ShadowVolumeGeometry;
96    _shadowVolume->setUseDisplayList(!_dynamicShadowVolumes);
97    _shadowVolume->setDrawMode(_drawMode);
98    _occluder->computeShadowVolumeGeometry(lightpos, *_shadowVolume);
99
100    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
101    _shadowedScene->addChild(geode.get());
102    int shadowVolumeBin = 1000;
103
104    if (_drawMode == osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED)
105    {
106        OSG_NOTICE<<"STENCIL_TWO_SIDED selected"<<std::endl;
107
108        osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
109        ss_sv1->setRenderBinDetails(shadowVolumeBin, "RenderBin");
110        geode->addDrawable(_shadowVolume.get());
111    }
112    else
113    {
114        OSG_NOTICE<<"STENCIL_TWO_PASSES selecteted"<<std::endl;
115
116        osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
117        ss_sv1->setRenderBinDetails(shadowVolumeBin, "RenderBin");
118        geode->addDrawable(_shadowVolume.get());
119    }
120
121    {
122
123        // first group, render the depth buffer + ambient light contribution
124        {
125            _ss1 = new osg::StateSet;
126
127            osg::LightModel* lm1 = new osg::LightModel;
128            lm1->setAmbientIntensity(ambient);
129            _ss1->setAttribute(lm1);
130
131            _ambientLight = new osg::Light;
132            _ambientLight->setAmbient(ambient);
133            _ambientLight->setDiffuse(zero_colour);
134            _ss1->setAttributeAndModes(_ambientLight.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
135
136            _ss1->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
137        }
138
139        {
140            _mainShadowStateSet = new osg::StateSet;
141
142            osg::Depth* depth = new osg::Depth;
143            depth->setWriteMask(false);
144            depth->setFunction(osg::Depth::LEQUAL);
145            _mainShadowStateSet->setAttribute(depth);
146            _mainShadowStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
147        }
148
149        {
150            _shadowVolumeStateSet = new osg::StateSet;
151
152            osg::Depth* depth = new osg::Depth;
153            depth->setWriteMask(false);
154            depth->setFunction(osg::Depth::LEQUAL);
155            _shadowVolumeStateSet->setAttribute(depth);
156            _shadowVolumeStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
157            _shadowVolumeStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
158
159
160            if (_drawMode == osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED)
161            {
162                osg::StencilTwoSided* stencil = new osg::StencilTwoSided;
163                stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS,0,~0u);
164                stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::DECR_WRAP);
165                stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS,0,~0u);
166                stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::INCR_WRAP);
167
168                osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);
169
170                _shadowVolumeStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
171                _shadowVolumeStateSet->setAttribute(colourMask, osg::StateAttribute::OVERRIDE);
172                _shadowVolumeStateSet->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
173
174
175            }
176            else
177            {
178                osg::Stencil* stencil = new osg::Stencil;
179                stencil->setFunction(osg::Stencil::ALWAYS,0,~0u);
180                stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
181
182                osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);
183
184                _shadowVolumeStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON);
185                _shadowVolumeStateSet->setAttribute(colourMask);
186                _shadowVolumeStateSet->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
187            }
188        }
189
190
191        {
192            _shadowedSceneStateSet = new osg::StateSet;
193
194            osg::Depth* depth = new osg::Depth;
195            depth->setWriteMask(false);
196            depth->setFunction(osg::Depth::LEQUAL);
197            _shadowedSceneStateSet->setAttribute(depth);
198            _shadowedSceneStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
199            // _shadowedSceneStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
200
201            osg::LightModel* lm1 = new osg::LightModel;
202            lm1->setAmbientIntensity(zero_colour);
203            _shadowedSceneStateSet->setAttribute(lm1);
204
205            _diffuseLight = new osg::Light;
206            _diffuseLight->setAmbient(zero_colour);
207            _diffuseLight->setDiffuse(diffuse);
208
209            _shadowedSceneStateSet->setMode(GL_LIGHT0, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
210            _shadowedSceneStateSet->setAttribute(_diffuseLight.get());
211
212            // set up the stencil ops so that only operator on this mirrors stencil value.
213            osg::Stencil* stencil = new osg::Stencil;
214            stencil->setFunction(osg::Stencil::EQUAL,0,~0u);
215            stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
216            _shadowedSceneStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON);
217
218            osg::BlendFunc* blend = new osg::BlendFunc;
219            blend->setFunction(osg::BlendFunc::ONE, osg::BlendFunc::ONE);
220            _shadowedSceneStateSet->setAttributeAndModes(blend, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
221            // _shadowedSceneStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
222        }
223
224        _ss1->setThreadSafeRefUnref(true);
225        _mainShadowStateSet->setThreadSafeRefUnref(true);
226        _shadowVolumeStateSet->setThreadSafeRefUnref(true);
227        _shadowedSceneStateSet->setThreadSafeRefUnref(true);
228
229    }
230
231    _dirty = false;
232}
233
234void ShadowVolume::update(osg::NodeVisitor& nv)
235{
236    _shadowedScene->osg::Group::traverse(nv);
237}
238
239void ShadowVolume::cull(osgUtil::CullVisitor& cv)
240{
241
242    osg::ref_ptr<osgUtil::RenderBin> original_bin = cv.getCurrentRenderBin();
243
244    osg::ref_ptr<osgUtil::RenderBin> new_bin = original_bin->find_or_insert(0,"RenderBin");
245
246    cv.setCurrentRenderBin(new_bin.get());
247
248    _shadowedScene->osg::Group::traverse(cv);
249
250    cv.setCurrentRenderBin(original_bin.get());
251
252    osgUtil::RenderBin::RenderBinList::iterator itr =  new_bin->getRenderBinList().find(1000);
253    osg::ref_ptr<osgUtil::RenderBin> shadowVolumeBin;
254    if (itr != new_bin->getRenderBinList().end())
255    {
256        shadowVolumeBin = itr->second;
257
258        if (shadowVolumeBin.valid())
259        {
260            //OSG_NOTICE<<"Found shadow volume bin, now removing it"<<std::endl;
261            new_bin->getRenderBinList().erase(itr);
262        }
263    }
264
265    if (shadowVolumeBin.valid())
266    {
267        original_bin->setStateSet(_ss1.get());
268
269        osgUtil::RenderStage* orig_rs = cv.getRenderStage();
270        osgUtil::RenderStage* new_rs = new osgUtil::RenderStage;
271        orig_rs->addPostRenderStage(new_rs);
272
273        new_rs->setViewport(orig_rs->getViewport());
274        new_rs->setClearColor(orig_rs->getClearColor());
275        new_rs->setClearMask(GL_STENCIL_BUFFER_BIT);
276        new_rs->setDrawBuffer(orig_rs->getDrawBuffer(), orig_rs->getDrawBufferApplyMask());
277        new_rs->setReadBuffer(orig_rs->getReadBuffer(), orig_rs->getReadBufferApplyMask());
278        new_rs->setColorMask(orig_rs->getColorMask());
279
280        osg::Vec4 lightpos;
281
282        osg::ref_ptr<osgUtil::PositionalStateContainer> ps = new osgUtil::PositionalStateContainer;
283        new_rs->setPositionalStateContainer(ps.get());
284
285        const osg::Light* selectLight = 0;
286
287        osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList();
288        for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
289            itr != aml.end();
290            ++itr)
291        {
292            const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get());
293            if (light)
294            {
295                osg::RefMatrix* matrix = itr->second.get();
296                if (matrix) lightpos = light->getPosition() * (*matrix);
297                else lightpos = light->getPosition();
298
299                selectLight = light;
300            }
301            else
302            {
303                ps->addPositionedAttribute(itr->second.get(), itr->first.get());
304            }
305        }
306
307        _ambientLight->setPosition(lightpos);
308
309        orig_rs->addPositionedAttribute(0,_ambientLight.get());
310
311        _diffuseLight->setPosition(lightpos);
312        if (selectLight)
313        {
314            _ambientLight->setAmbient(selectLight->getAmbient());
315
316            _diffuseLight->setDiffuse(selectLight->getDiffuse());
317            _diffuseLight->setSpecular(selectLight->getSpecular());
318            _diffuseLight->setDirection(selectLight->getDirection());
319            _diffuseLight->setConstantAttenuation(selectLight->getConstantAttenuation());
320            _diffuseLight->setLinearAttenuation(selectLight->getLinearAttenuation());
321            _diffuseLight->setQuadraticAttenuation(selectLight->getQuadraticAttenuation());
322            _diffuseLight->setSpotExponent(selectLight->getSpotExponent());
323            _diffuseLight->setSpotCutoff(selectLight->getSpotCutoff());
324        }
325        ps->addPositionedAttribute(0, _diffuseLight.get());
326
327        if (_lightpos != lightpos && _dynamicShadowVolumes)
328        {
329            _lightpos = lightpos;
330
331            osg::Matrix eyeToWorld;
332            eyeToWorld.invert(*cv.getModelViewMatrix());
333
334            _occluder->computeShadowVolumeGeometry(lightpos * eyeToWorld, *_shadowVolume);
335        }
336
337        if (shadowVolumeBin.valid())
338        {
339            // new_rs->setStateSet(_mainShadowStateSet.get());
340            new_rs->getRenderBinList()[0] = shadowVolumeBin;
341            shadowVolumeBin->setStateSet(_shadowVolumeStateSet.get());
342
343            osg::ref_ptr<osgUtil::RenderBin> nested_bin = new_rs->find_or_insert(1,"RenderBin");
344            nested_bin->getRenderBinList()[0] = new_bin;
345            nested_bin->setStateSet(_shadowedSceneStateSet.get());
346        }
347    }
348
349
350}
351
352void ShadowVolume::cleanSceneGraph()
353{
354    OSG_NOTICE<<className()<<"::cleanSceneGraph()) not implemened yet, but almost."<<std::endl;
355}
Note: See TracBrowser for help on using the browser.