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

Revision 13041, 8.9 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/ShadowTexture>
15#include <osgShadow/ShadowedScene>
16#include <osg/Notify>
17#include <osg/ComputeBoundsVisitor>
18#include <osg/io_utils>
19
20using namespace osgShadow;
21
22ShadowTexture::ShadowTexture():
23    _textureUnit(1)
24{
25}
26
27ShadowTexture::ShadowTexture(const ShadowTexture& copy, const osg::CopyOp& copyop):
28    ShadowTechnique(copy,copyop),
29    _textureUnit(copy._textureUnit)
30{
31}
32
33void ShadowTexture::setTextureUnit(unsigned int unit)
34{
35    _textureUnit = unit;
36}
37
38void ShadowTexture::init()
39{
40    if (!_shadowedScene) return;
41
42    unsigned int tex_width = 512;
43    unsigned int tex_height = 512;
44
45    _texture = new osg::Texture2D;
46    _texture->setTextureSize(tex_width, tex_height);
47    _texture->setInternalFormat(GL_RGB);
48    _texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
49    _texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
50    _texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER);
51    _texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER);
52    _texture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
53
54    // set up the render to texture camera.
55    {
56        // create the camera
57        _camera = new osg::Camera;
58
59        _camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
60
61        _camera->setCullCallback(new CameraCullCallback(this));
62
63        // set viewport
64        _camera->setViewport(0,0,tex_width,tex_height);
65
66        // set the camera to render before the main camera.
67        _camera->setRenderOrder(osg::Camera::PRE_RENDER);
68
69        // tell the camera to use OpenGL frame buffer object where supported.
70        _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
71        //_camera->setRenderTargetImplementation(osg::Camera::SEPERATE_WINDOW);
72
73        // attach the texture and use it as the color buffer.
74        _camera->attach(osg::Camera::COLOR_BUFFER, _texture.get());
75
76        _material = new osg::Material;
77        _material->setAmbient(osg::Material::FRONT_AND_BACK,osg::Vec4(0.0f,0.0f,0.0f,1.0f));
78        _material->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(0.0f,0.0f,0.0f,1.0f));
79        _material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(0.0f,0.0f,0.0f,1.0f));
80        _material->setShininess(osg::Material::FRONT_AND_BACK,0.0f);
81
82        osg::StateSet* stateset = _camera->getOrCreateStateSet();
83        stateset->setAttribute(_material.get(),osg::StateAttribute::OVERRIDE);
84
85    }
86
87    {
88        _stateset = new osg::StateSet;
89        _stateset->setTextureAttributeAndModes(_textureUnit,_texture.get(),osg::StateAttribute::ON);
90        _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
91        _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
92        _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
93        _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON);
94
95        _texgen = new osg::TexGen;
96    }
97
98    _dirty = false;
99}
100
101
102void ShadowTexture::update(osg::NodeVisitor& nv)
103{
104    _shadowedScene->osg::Group::traverse(nv);
105}
106
107void ShadowTexture::cull(osgUtil::CullVisitor& cv)
108{
109    // record the traversal mask on entry so we can reapply it later.
110    unsigned int traversalMask = cv.getTraversalMask();
111
112    osgUtil::RenderStage* orig_rs = cv.getRenderStage();
113
114    // do traversal of shadow casting scene which does not need to be decorated by the shadow texture
115    {
116        cv.setTraversalMask( traversalMask &
117                             getShadowedScene()->getCastsShadowTraversalMask() );
118
119        _shadowedScene->osg::Group::traverse(cv);
120    }
121
122    // do traversal of shadow receiving scene which does need to be decorated by the shadow texture
123    {
124        cv.pushStateSet(_stateset.get());
125
126        cv.setTraversalMask( traversalMask &
127                             getShadowedScene()->getReceivesShadowTraversalMask() );
128
129        _shadowedScene->osg::Group::traverse(cv);
130
131        cv.popStateSet();
132
133    }
134
135    // need to compute view frustum for RTT camera.
136    // 1) get the light position
137    // 2) get the center and extents of the view frustum
138
139    const osg::Light* selectLight = 0;
140    osg::Vec4 lightpos;
141
142    osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList();
143    for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
144        itr != aml.end();
145        ++itr)
146    {
147        const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get());
148        if (light)
149        {
150            osg::RefMatrix* matrix = itr->second.get();
151            if (matrix) lightpos = light->getPosition() * (*matrix);
152            else lightpos = light->getPosition();
153
154            selectLight = light;
155        }
156    }
157
158    osg::Matrix eyeToWorld;
159    eyeToWorld.invert(*cv.getModelViewMatrix());
160
161    lightpos = lightpos * eyeToWorld;
162
163    if (selectLight)
164    {
165
166        // get the bounds of the model.
167        osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
168        cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask());
169
170        _shadowedScene->osg::Group::traverse(cbbv);
171
172        osg::BoundingBox bb = cbbv.getBoundingBox();
173
174        if (lightpos[3]!=0.0)
175        {
176            osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z());
177
178            float centerDistance = (position-bb.center()).length();
179
180            float znear = centerDistance-bb.radius();
181            float zfar  = centerDistance+bb.radius();
182            float zNearRatio = 0.001f;
183            if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;
184
185            float top   = (bb.radius()/centerDistance)*znear;
186            float right = top;
187
188            _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
189            _camera->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar);
190            _camera->setViewMatrixAsLookAt(position,bb.center(),computeOrthogonalVector(bb.center()-position));
191
192
193            // compute the matrix which takes a vertex from local coords into tex coords
194            // will use this later to specify osg::TexGen..
195            osg::Matrix MVPT = _camera->getViewMatrix() *
196                               _camera->getProjectionMatrix() *
197                               osg::Matrix::translate(1.0,1.0,1.0) *
198                               osg::Matrix::scale(0.5f,0.5f,0.5f);
199
200            _texgen->setMode(osg::TexGen::EYE_LINEAR);
201            _texgen->setPlanesFromMatrix(MVPT);
202        }
203        else
204        {
205            // make an orthographic projection
206            osg::Vec3 lightDir(lightpos.x(), lightpos.y(), lightpos.z());
207            lightDir.normalize();
208
209            // set the position far away along the light direction
210            osg::Vec3 position = bb.center() + lightDir * bb.radius() * 2.0;
211
212            float centerDistance = (position-bb.center()).length();
213
214            float znear = centerDistance-bb.radius();
215            float zfar  = centerDistance+bb.radius();
216            float zNearRatio = 0.001f;
217            if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;
218
219            float top   = bb.radius();
220            float right = top;
221
222            _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
223            _camera->setProjectionMatrixAsOrtho(-right, right, -top, top, znear, zfar);
224            _camera->setViewMatrixAsLookAt(position,bb.center(),computeOrthogonalVector(lightDir));
225
226
227            // compute the matrix which takes a vertex from local coords into tex coords
228            // will use this later to specify osg::TexGen..
229            osg::Matrix MVPT = _camera->getViewMatrix() *
230                               _camera->getProjectionMatrix() *
231                               osg::Matrix::translate(1.0,1.0,1.0) *
232                               osg::Matrix::scale(0.5f,0.5f,0.5f);
233
234            _texgen->setMode(osg::TexGen::EYE_LINEAR);
235            _texgen->setPlanesFromMatrix(MVPT);
236        }
237
238
239        cv.setTraversalMask( traversalMask &
240                             getShadowedScene()->getCastsShadowTraversalMask() );
241
242        // do RTT camera traversal
243        _camera->accept(cv);
244
245        orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(_textureUnit, cv.getModelViewMatrix(), _texgen.get());
246    }
247
248
249
250
251
252    // reapply the original traversal mask
253    cv.setTraversalMask( traversalMask );
254}
255
256void ShadowTexture::cleanSceneGraph()
257{
258}
Note: See TracBrowser for help on using the browser.