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

Revision 7412, 11.4 kB (checked in by robert, 7 years ago)

From Paul Martsz, changed the Texture clamping mode to CLAMP_TO_EDGE

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