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

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

Made the local shaders definitions static const char to avoid multiple definiations

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