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

Revision 6991, 11.2 kB (checked in by robert, 7 years ago)

Added ShadowMap::s/getAmbientBias, updated NEWS and wrappers

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