root/OpenSceneGraph/trunk/src/osgShadow/ShadowMap.cpp @ 6952

Revision 6952, 11.1 kB (checked in by robert, 8 years ago)

Removed ParallelSplitShadowMap? as its currently a non op.

  • 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/ShadowMap>
15#include <osgShadow/ShadowedScene>
16#include <osg/Notify>
17#include <osg/ComputeBoundsVisitor>
18#include <osg/PolygonOffset>
19#include <osg/CullFace>
20#include <osg/io_utils>
21
22using namespace osgShadow;
23
24
25//////////////////////////////////////////////////////////////////
26// fragment shader
27//
28static const char fragmentShaderSource_noBaseTexture[] =
29    "uniform sampler2DShadow shadowTexture; \n"
30    "uniform vec2 ambientBias; \n"
31    "\n"
32    "void main(void) \n"
33    "{ \n"
34    "    gl_FragColor = gl_Color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[0] ) * ambientBias.y); \n"
35    "}\n";
36
37//////////////////////////////////////////////////////////////////
38// fragment shader
39//
40static const char fragmentShaderSource_withBaseTexture[] =
41    "uniform sampler2D baseTexture; \n"
42    "uniform sampler2DShadow shadowTexture; \n"
43    "uniform vec2 ambientBias; \n"
44    "\n"
45    "void main(void) \n"
46    "{ \n"
47    "    vec4 color = gl_Color * texture2D( baseTexture, gl_TexCoord[0].xy ); \n"
48    "    gl_FragColor = color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[1] ) * ambientBias.y); \n"
49    "}\n";
50
51ShadowMap::ShadowMap():
52    _textureUnit(1)
53{
54}
55
56ShadowMap::ShadowMap(const ShadowMap& copy, const osg::CopyOp& copyop):
57    ShadowTechnique(copy,copyop),
58    _textureUnit(copy._textureUnit)
59{
60}
61
62void ShadowMap::setTextureUnit(unsigned int unit)
63{
64    _textureUnit = unit;
65}
66
67void ShadowMap::init()
68{
69    if (!_shadowedScene) return;
70
71    unsigned int tex_width = 1024;
72    unsigned int tex_height = 1024;
73   
74    _texture = new osg::Texture2D;
75    _texture->setTextureSize(tex_width, tex_height);
76    _texture->setInternalFormat(GL_DEPTH_COMPONENT);
77    _texture->setShadowComparison(true);
78    _texture->setShadowTextureMode(osg::Texture2D::LUMINANCE);
79    _texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
80    _texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
81
82    // set up the render to texture camera.
83    {
84        // create the camera
85        _camera = new osg::Camera;
86
87        _camera->setCullCallback(new CameraCullCallback(this));
88
89        _camera->setClearMask(GL_DEPTH_BUFFER_BIT);
90        //_camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
91        _camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
92        _camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
93
94        // set viewport
95        _camera->setViewport(0,0,tex_width,tex_height);
96
97        // set the camera to render before the main camera.
98        _camera->setRenderOrder(osg::Camera::PRE_RENDER);
99
100        // tell the camera to use OpenGL frame buffer object where supported.
101        _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
102        //_camera->setRenderTargetImplementation(osg::Camera::SEPERATE_WINDOW);
103
104        // attach the texture and use it as the color buffer.
105        _camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get());
106
107        osg::StateSet* stateset = _camera->getOrCreateStateSet();
108
109        float factor = 0.0f;
110        float units = 1.0f;
111
112        osg::ref_ptr<osg::PolygonOffset> polygon_offset = new osg::PolygonOffset;
113        polygon_offset->setFactor(factor);
114        polygon_offset->setUnits(units);
115        stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
116        stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
117
118        osg::ref_ptr<osg::CullFace> cull_face = new osg::CullFace;
119        cull_face->setMode(osg::CullFace::FRONT);
120        stateset->setAttribute(cull_face.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
121        stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
122       
123    }
124   
125    {
126        _stateset = new osg::StateSet;       
127        _stateset->setTextureAttributeAndModes(_textureUnit,_texture.get(),osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
128        _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
129        _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
130        _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
131        _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON);
132       
133        _texgen = new osg::TexGen;
134
135#if 1
136        osg::Program* program = new osg::Program;
137        _stateset->setAttribute(program);
138
139        if (_textureUnit==0)
140        {
141            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture);
142            program->addShader(fragment_shader);
143
144            osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)_textureUnit);
145            _stateset->addUniform(shadowTextureSampler);
146        }
147        else
148        {
149            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture);
150            program->addShader(fragment_shader);
151
152            osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
153            _stateset->addUniform(baseTextureSampler);
154
155            osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)_textureUnit);
156            _stateset->addUniform(shadowTextureSampler);
157        }
158       
159        osg::Uniform* ambientBias = new osg::Uniform("ambientBias",osg::Vec2(0.3f,1.2f));
160        _stateset->addUniform(ambientBias);
161
162#endif
163    }
164   
165    _dirty = false;
166}
167
168
169void ShadowMap::update(osg::NodeVisitor& nv)
170{
171    _shadowedScene->osg::Group::traverse(nv);
172}
173
174void ShadowMap::cull(osgUtil::CullVisitor& cv)
175{
176    // record the traversal mask on entry so we can reapply it later.
177    unsigned int traversalMask = cv.getTraversalMask();
178
179    osgUtil::RenderStage* orig_rs = cv.getRenderStage();
180
181    // do traversal of shadow recieving scene which does need to be decorated by the shadow map
182    {
183        cv.pushStateSet(_stateset.get());
184   
185        _shadowedScene->osg::Group::traverse(cv);
186       
187        cv.popStateSet();
188
189    }
190   
191    // need to compute view frustum for RTT camera.
192    // 1) get the light position
193    // 2) get the center and extents of the view frustum
194
195    const osg::Light* selectLight = 0;
196    osg::Vec4 lightpos;
197
198    osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList();
199    for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
200        itr != aml.end();
201        ++itr)
202    {
203        const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get());
204        if (light)
205        {
206            osg::RefMatrix* matrix = itr->second.get();
207            if (matrix) lightpos = light->getPosition() * (*matrix);
208            else lightpos = light->getPosition();
209
210            selectLight = light;
211        }
212    }
213   
214    osg::Matrix eyeToWorld;
215    eyeToWorld.invert(*cv.getModelViewMatrix());
216   
217    lightpos = lightpos * eyeToWorld;
218
219    if (selectLight)
220    {
221
222        // get the bounds of the model.   
223        osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
224        cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask());
225       
226        _shadowedScene->osg::Group::traverse(cbbv);
227       
228        osg::BoundingBox bb = cbbv.getBoundingBox();
229       
230        if (lightpos[3]!=0.0)
231        {
232            osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z());
233
234            float centerDistance = (position-bb.center()).length();
235
236            float znear = centerDistance-bb.radius();
237            float zfar  = centerDistance+bb.radius();
238            float zNearRatio = 0.001f;
239            if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;
240
241            float top   = (bb.radius()/centerDistance)*znear;
242            float right = top;
243
244            _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
245            _camera->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar);
246            _camera->setViewMatrixAsLookAt(position,bb.center(),osg::Vec3(0.0f,1.0f,0.0f));
247           
248
249            // compute the matrix which takes a vertex from local coords into tex coords
250            // will use this later to specify osg::TexGen..
251            osg::Matrix MVPT = _camera->getViewMatrix() *
252                               _camera->getProjectionMatrix() *
253                               osg::Matrix::translate(1.0,1.0,1.0) *
254                               osg::Matrix::scale(0.5f,0.5f,0.5f);
255                               
256            _texgen->setMode(osg::TexGen::EYE_LINEAR);
257            _texgen->setPlanesFromMatrix(MVPT);
258        }
259        else
260        {
261            // make an orthographic projection
262            osg::Vec3 lightDir(lightpos.x(), lightpos.y(), lightpos.z());
263            lightDir.normalize();
264
265            // set the position far away along the light direction
266            osg::Vec3 position = lightDir * bb.radius()  * 20;
267
268            float centerDistance = (position-bb.center()).length();
269
270            float znear = centerDistance-bb.radius();
271            float zfar  = centerDistance+bb.radius();
272            float zNearRatio = 0.001f;
273            if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;
274
275            float top   = bb.radius();
276            float right = top;
277
278            _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
279            _camera->setProjectionMatrixAsOrtho(-right, right, -top, top, znear, zfar);
280            _camera->setViewMatrixAsLookAt(position,bb.center(),osg::Vec3(0.0f,1.0f,0.0f));
281           
282
283            // compute the matrix which takes a vertex from local coords into tex coords
284            // will use this later to specify osg::TexGen..
285            osg::Matrix MVPT = _camera->getViewMatrix() *
286                               _camera->getProjectionMatrix() *
287                               osg::Matrix::translate(1.0,1.0,1.0) *
288                               osg::Matrix::scale(0.5f,0.5f,0.5f);
289                               
290            _texgen->setMode(osg::TexGen::EYE_LINEAR);
291            _texgen->setPlanesFromMatrix(MVPT);
292        }
293
294
295        cv.setTraversalMask( traversalMask &
296                             getShadowedScene()->getCastsShadowTraversalMask() );
297
298        // do RTT camera traversal
299        _camera->accept(cv);
300
301        orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(_textureUnit, cv.getModelViewMatrix(), _texgen.get());
302    }
303
304
305    // reapply the original traversal mask
306    cv.setTraversalMask( traversalMask );
307}
308
309void ShadowMap::cleanSceneGraph()
310{
311}
Note: See TracBrowser for help on using the browser.