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

Revision 7690, 22.3 kB (checked in by robert, 7 years ago)

Tweaked the abmient lighting contribution so that the OpenGL vertex lighting has
the ambient light source switched off, and use the fragment shader to add this
contribution back in.

  • 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#include <iostream>
25//for debug
26#include <osg/LightSource>
27#include <osg/PolygonMode>
28#include <osg/Geometry>
29#include <osgDB/ReadFile>
30#include <osgText/Text>
31
32    //////////////////////////////////////////////////////////////////
33    // fragment shader
34    //
35    static const char fragmentShaderSource_noBaseTexture[] =
36        "uniform sampler2DShadow osgShadow_shadowTexture; \n"
37        "uniform vec2 osgShadow_ambientBias; \n"
38        "\n"
39        "void main(void) \n"
40        "{ \n"
41        "    gl_FragColor = gl_Color * (osgShadow_ambientBias.x + shadow2DProj( osgShadow_shadowTexture, gl_TexCoord[0] ) * osgShadow_ambientBias.y); \n"
42        "}\n";
43
44    //////////////////////////////////////////////////////////////////
45    // fragment shader
46    //
47    static const char fragmentShaderSource_withBaseTexture[] =
48        "uniform sampler2D osgShadow_baseTexture; \n"
49        "uniform sampler2DShadow osgShadow_shadowTexture; \n"
50        "uniform vec2 osgShadow_ambientBias; \n"
51        "\n"
52        "void main(void) \n"
53        "{ \n"
54        "    vec4 color = gl_Color * texture2D( osgShadow_baseTexture, gl_TexCoord[0].xy ); \n"
55        "    gl_FragColor = color * (osgShadow_ambientBias.x + shadow2DProj( osgShadow_shadowTexture, gl_TexCoord[1] ) * osgShadow_ambientBias.y); \n"
56        "}\n";
57
58    //////////////////////////////////////////////////////////////////
59    // fragment shader
60    //
61    static const char fragmentShaderSource_debugHUD_texcoord[] =
62        "uniform sampler2D osgShadow_shadowTexture; \n"
63        " \n"
64        "void main(void) \n"
65        "{ \n"
66        "   vec4 texCoord = gl_TexCoord[1].xyzw; \n"
67        "   float value = texCoord.z / texCoord.w; \n"
68        "   gl_FragColor = vec4( value, value, value, 1.0 ); \n"
69        "} \n";
70
71    static const char fragmentShaderSource_debugHUD[] =
72        "uniform sampler2D osgShadow_shadowTexture; \n"
73        " \n"
74        "void main(void) \n"
75        "{ \n"
76        "   vec4 texResult = texture2D(osgShadow_shadowTexture, gl_TexCoord[0].st ); \n"
77        "   float value = texResult.r + 0.5; \n"
78        "   gl_FragColor = vec4( value, value, value, 0.8 ); \n"
79        "} \n";
80
81    ShadowMap::ShadowMap():
82    _baseTextureUnit(0),
83        _shadowTextureUnit(1),
84        _ambientBias(0.5f,0.5f),
85        _textureSize(1024,1024)
86    {
87    }
88
89    ShadowMap::ShadowMap(const ShadowMap& copy, const osg::CopyOp& copyop):
90    ShadowTechnique(copy,copyop),
91        _baseTextureUnit(copy._baseTextureUnit),
92        _shadowTextureUnit(copy._shadowTextureUnit),
93        _ambientBias(copy._ambientBias),
94        _textureSize(copy._textureSize)
95    {
96    }
97
98    void ShadowMap::setTextureUnit(unsigned int unit)
99    {
100        _shadowTextureUnit = unit;
101    }
102
103    void ShadowMap::setAmbientBias(const osg::Vec2& ambientBias)
104    {
105        _ambientBias = ambientBias;
106    }
107
108    void ShadowMap::setTextureSize(const osg::Vec2s& textureSize)
109    {
110        _textureSize = textureSize;
111        dirty();
112    }
113
114    void ShadowMap::setLight(osg::Light* light)
115    {
116        _light = light;
117    }
118
119
120    void ShadowMap::setLight(osg::LightSource* ls)
121    {
122        _ls = ls;
123        _light = _ls->getLight();
124    }
125
126    void ShadowMap::createUniforms()
127    {
128        _uniformList.clear();
129
130        osg::Uniform* baseTextureSampler = new osg::Uniform("osgShadow_baseTexture",(int)_baseTextureUnit);
131        _uniformList.push_back(baseTextureSampler);
132
133        osg::Uniform* shadowTextureSampler = new osg::Uniform("osgShadow_shadowTexture",(int)_shadowTextureUnit);
134        _uniformList.push_back(shadowTextureSampler);
135
136        _ambientBiasUniform = new osg::Uniform("osgShadow_ambientBias",_ambientBias);
137        _uniformList.push_back(_ambientBiasUniform.get());
138
139    }
140
141    void ShadowMap::createShaders()
142    {
143        // if we are not given shaders, use the default
144        if( _shaderList.empty() )
145        {
146            if (_shadowTextureUnit==0)
147            {
148                osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture);
149                _shaderList.push_back(fragment_shader);
150            }
151            else
152            {
153                osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture);
154                _shaderList.push_back(fragment_shader);
155
156            }
157        }
158    }
159
160    void ShadowMap::init()
161    {
162        if (!_shadowedScene) return;
163
164        _texture = new osg::Texture2D;
165        _texture->setTextureSize(_textureSize.x(), _textureSize.y());
166        _texture->setInternalFormat(GL_DEPTH_COMPONENT);
167        _texture->setShadowComparison(true);
168        _texture->setShadowTextureMode(osg::Texture2D::LUMINANCE);
169        _texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
170        _texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
171
172        // the shadow comparison should fail if object is outside the texture
173        _texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER);
174        _texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER);
175        _texture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
176
177        // set up the render to texture camera.
178        {
179            // create the camera
180            _camera = new osg::Camera;
181
182            _camera->setCullCallback(new CameraCullCallback(this));
183
184            _camera->setClearMask(GL_DEPTH_BUFFER_BIT);
185            //_camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
186            _camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
187            _camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
188
189            // set viewport
190            _camera->setViewport(0,0,_textureSize.x(),_textureSize.y());
191
192            // set the camera to render before the main camera.
193            _camera->setRenderOrder(osg::Camera::PRE_RENDER);
194
195            // tell the camera to use OpenGL frame buffer object where supported.
196            _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
197            //_camera->setRenderTargetImplementation(osg::Camera::SEPERATE_WINDOW);
198
199            // attach the texture and use it as the color buffer.
200            _camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get());
201
202            osg::StateSet* stateset = _camera->getOrCreateStateSet();
203
204
205#if 1
206            // cull front faces so that only backfaces contribute to depth map
207
208            osg::ref_ptr<osg::CullFace> cull_face = new osg::CullFace;
209            cull_face->setMode(osg::CullFace::FRONT);
210            stateset->setAttribute(cull_face.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
211            stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
212
213            // negative polygonoffset - move the backface nearer to the eye point so that backfaces
214            // shadow themselves
215            float factor = -1.0f;
216            float units = -1.0f;
217
218            osg::ref_ptr<osg::PolygonOffset> polygon_offset = new osg::PolygonOffset;
219            polygon_offset->setFactor(factor);
220            polygon_offset->setUnits(units);
221            stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
222            stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
223#else
224            // disabling cull faces so that only front and backfaces contribute to depth map
225            stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
226
227            // negative polygonoffset - move the backface nearer to the eye point
228            // so that front faces do not shadow themselves.
229            float factor = 1.0f;
230            float units = 1.0f;
231
232            osg::ref_ptr<osg::PolygonOffset> polygon_offset = new osg::PolygonOffset;
233            polygon_offset->setFactor(factor);
234            polygon_offset->setUnits(units);
235            stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
236            stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
237#endif
238        }
239
240        {
241            _stateset = new osg::StateSet;       
242            _stateset->setTextureAttributeAndModes(_shadowTextureUnit,_texture.get(),osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
243            _stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
244            _stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
245            _stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
246            _stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON);
247
248            _texgen = new osg::TexGen;
249
250            // add Program, when empty of Shaders then we are using fixed functionality
251            _program = new osg::Program;
252            _stateset->setAttribute(_program.get());
253
254            // create default shaders if needed
255            createShaders();
256
257            // add the shader list to the program
258            for(ShaderList::const_iterator itr=_shaderList.begin();
259                itr!=_shaderList.end();
260                ++itr)
261            {
262                _program->addShader(itr->get());
263            }
264
265            // create own uniforms
266            createUniforms();
267
268            // add the uniform list to the stateset
269            for(UniformList::const_iterator itr=_uniformList.begin();
270                itr!=_uniformList.end();
271                ++itr)
272            {
273                _stateset->addUniform(itr->get());
274            }
275
276            {
277                // fake texture for baseTexture, add a fake texture
278                // we support by default at least one texture layer
279                // without this fake texture we can not support
280                // textured and not textured scene
281
282                // TODO: at the moment the PSSM supports just one texture layer in the GLSL shader, multitexture are
283                //       not yet supported !
284
285                osg::Image* image = new osg::Image;
286                // allocate the image data, noPixels x 1 x 1 with 4 rgba floats - equivilant to a Vec4!
287                int noPixels = 1;
288                image->allocateImage(noPixels,1,1,GL_RGBA,GL_FLOAT);
289                image->setInternalTextureFormat(GL_RGBA);
290                // fill in the image data.
291                osg::Vec4* dataPtr = (osg::Vec4*)image->data();
292                osg::Vec4 color(1,1,1,1);
293                *dataPtr = color;
294                // make fake texture
295                osg::Texture2D* fakeTex = new osg::Texture2D;
296                fakeTex->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER);
297                fakeTex->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER);
298                fakeTex->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
299                fakeTex->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
300                fakeTex->setImage(image);
301                // add fake texture
302                _stateset->setTextureAttribute(_baseTextureUnit,fakeTex,osg::StateAttribute::ON);
303                _stateset->setTextureMode(_baseTextureUnit,GL_TEXTURE_1D,osg::StateAttribute::OFF);
304                _stateset->setTextureMode(_baseTextureUnit,GL_TEXTURE_2D,osg::StateAttribute::ON);
305                _stateset->setTextureMode(_baseTextureUnit,GL_TEXTURE_3D,osg::StateAttribute::OFF);
306            }
307        }
308
309        _dirty = false;
310    }
311
312
313    void ShadowMap::update(osg::NodeVisitor& nv)
314    {
315        _shadowedScene->osg::Group::traverse(nv);
316    }
317
318    void ShadowMap::cull(osgUtil::CullVisitor& cv)
319    {
320        // record the traversal mask on entry so we can reapply it later.
321        unsigned int traversalMask = cv.getTraversalMask();
322
323        osgUtil::RenderStage* orig_rs = cv.getRenderStage();
324
325        // do traversal of shadow receiving scene which does need to be decorated by the shadow map
326        {
327            cv.pushStateSet(_stateset.get());
328
329            _shadowedScene->osg::Group::traverse(cv);
330
331            cv.popStateSet();
332
333        }
334
335        // need to compute view frustum for RTT camera.
336        // 1) get the light position
337        // 2) get the center and extents of the view frustum
338
339        const osg::Light* selectLight = 0;
340        osg::Vec4 lightpos;
341        osg::Vec3 lightDir;
342
343        //MR testing giving a specific light
344        osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList();
345        for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
346            itr != aml.end();
347            ++itr)
348        {
349            const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get());
350            if (light)
351            {
352                if( _light.valid()) {
353                    if( _light.get() == light )
354                        selectLight = light;
355                    else
356                        continue;
357                }
358                else
359                    selectLight = light;
360
361                osg::RefMatrix* matrix = itr->second.get();
362                if (matrix)
363                {
364                    lightpos = light->getPosition() * (*matrix);
365                    lightDir = light->getDirection() * (*matrix);
366                }
367                else 
368                {
369                    lightpos = light->getPosition();
370                    lightDir = light->getDirection();
371                }
372
373            }
374        }
375       
376        osg::Matrix eyeToWorld;
377        eyeToWorld.invert(*cv.getModelViewMatrix());
378
379        lightpos = lightpos * eyeToWorld;
380        //MR do we do this for the direction also ? preliminary Yes, but still no good result
381        lightDir = lightDir * eyeToWorld;
382        lightDir.normalize();
383
384        if (selectLight)
385        {
386
387            // set to ambient on light to black so that the ambient bias uniform can take it's affect
388            const_cast<osg::Light*>(selectLight)->setAmbient(osg::Vec4(0.0f,0.0f,0.0f,1.0f));
389
390            //std::cout<<"----- VxOSG::ShadowMap selectLight spot cutoff "<<selectLight->getSpotCutoff()<<std::endl;
391
392            if(selectLight->getSpotCutoff() < 180.0f)   // spotlight, then we don't need the bounding box
393            {
394                osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z());
395                float spotAngle = selectLight->getSpotCutoff();
396                _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
397                _camera->setProjectionMatrixAsPerspective(spotAngle, 1.0, 0.1, 1000.0);
398                _camera->setViewMatrixAsLookAt(position,position+lightDir,osg::Vec3(0.0f,1.0f,0.0f));
399            }
400            else
401            {
402                // get the bounds of the model.   
403                osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
404                cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask());
405
406                _shadowedScene->osg::Group::traverse(cbbv);
407
408                osg::BoundingBox bb = cbbv.getBoundingBox();
409
410                if (lightpos[3]!=0.0)   // point light
411                {
412                    osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z());
413
414                    float centerDistance = (position-bb.center()).length();
415
416                    float znear = centerDistance-bb.radius();
417                    float zfar  = centerDistance+bb.radius();
418                    float zNearRatio = 0.001f;
419                    if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;
420
421                    float top   = (bb.radius()/centerDistance)*znear;
422                    float right = top;
423
424                    _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
425                    _camera->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar);
426                    _camera->setViewMatrixAsLookAt(position,bb.center(),osg::Vec3(0.0f,1.0f,0.0f));
427                }
428                else    // directional light
429                {
430                    // make an orthographic projection
431                    osg::Vec3 lightDir(lightpos.x(), lightpos.y(), lightpos.z());
432                    lightDir.normalize();
433
434                    // set the position far away along the light direction
435                    osg::Vec3 position = lightDir * bb.radius()  * 20;
436
437                    float centerDistance = (position-bb.center()).length();
438
439                    float znear = centerDistance-bb.radius();
440                    float zfar  = centerDistance+bb.radius();
441                    float zNearRatio = 0.001f;
442                    if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;
443
444                    float top   = bb.radius();
445                    float right = top;
446
447                    _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
448                    _camera->setProjectionMatrixAsOrtho(-right, right, -top, top, znear, zfar);
449                    _camera->setViewMatrixAsLookAt(position,bb.center(),osg::Vec3(0.0f,1.0f,0.0f));
450                }
451
452
453            }
454                // compute the matrix which takes a vertex from local coords into tex coords
455                // will use this later to specify osg::TexGen..
456                osg::Matrix MVPT = _camera->getViewMatrix() *
457                    _camera->getProjectionMatrix() *
458                    osg::Matrix::translate(1.0,1.0,1.0) *
459                    osg::Matrix::scale(0.5f,0.5f,0.5f);
460
461                _texgen->setMode(osg::TexGen::EYE_LINEAR);
462                _texgen->setPlanesFromMatrix(MVPT);
463
464            cv.setTraversalMask( traversalMask &
465                getShadowedScene()->getCastsShadowTraversalMask() );
466
467            // do RTT camera traversal
468            _camera->accept(cv);
469
470            orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(_shadowTextureUnit, cv.getModelViewMatrix(), _texgen.get());
471        } // if(selectLight)
472
473
474        // reapply the original traversal mask
475        cv.setTraversalMask( traversalMask );
476    }
477
478    void ShadowMap::cleanSceneGraph()
479    {
480    }
481
482    ///////////////////// Debug Methods
483
484    osg::ref_ptr<osg::Camera> ShadowMap::makeDebugHUD()
485    {
486        osg::ref_ptr<osg::Camera> camera = new osg::Camera;
487
488        osg::Vec2 size(1280, 1024);
489        // set the projection matrix
490        camera->setProjectionMatrix(osg::Matrix::ortho2D(0,size.x(),0,size.y()));
491
492        // set the view matrix   
493        camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
494        camera->setViewMatrix(osg::Matrix::identity());
495
496        // only clear the depth buffer
497        camera->setClearMask(GL_DEPTH_BUFFER_BIT);
498        camera->setClearColor(osg::Vec4(0.2f, 0.3f, 0.5f, 0.2f));
499        //camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
500
501        // draw subgraph after main camera view.
502        camera->setRenderOrder(osg::Camera::POST_RENDER);
503
504        // we don't want the camera to grab event focus from the viewers main camera(s).
505        camera->setAllowEventFocus(false);
506
507        osg::Geode* geode = new osg::Geode;
508
509        osg::Vec3 position(10.0f,size.y()-100.0f,0.0f);
510        osg::Vec3 delta(0.0f,-120.0f,0.0f);
511        float lenght = 300.0f;
512
513        // turn the text off to avoid linking with osgText
514#if 0
515        std::string timesFont("fonts/arial.ttf");
516
517        {
518            osgText::Text* text = new  osgText::Text;
519            geode->addDrawable( text );
520
521            text->setFont(timesFont);
522            text->setPosition(position);
523            text->setText("Shadow Map HUD");
524
525            position += delta;
526        }
527#endif
528       
529        osg::Vec3 widthVec(lenght, 0.0f, 0.0f);
530        osg::Vec3 depthVec(0.0f,lenght, 0.0f);
531        osg::Vec3 centerBase( 10.0f + lenght/2, size.y()-lenght/2, 0.0f);
532        centerBase += delta;
533       
534        geode->addDrawable( osg::createTexturedQuadGeometry( centerBase-widthVec*0.5f-depthVec*0.5f,
535                                                             widthVec, depthVec) );
536
537        osg::StateSet* stateset = geode->getOrCreateStateSet();
538
539        stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
540        stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
541        //stateset->setAttribute(new osg::PolygonOffset(1.0f,1.0f),osg::StateAttribute::ON);
542        stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
543
544        // test with regular texture
545        //stateset->setTextureAttributeAndModes(_baseTextureUnit, new osg::Texture2D(osgDB::readImageFile("Images/lz.rgb")));
546
547        stateset->setTextureAttributeAndModes(_shadowTextureUnit,_texture.get(),osg::StateAttribute::ON);
548       
549        //test to check the texture coordinates generated during shadow pass
550#if 0
551        stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
552        stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
553        stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
554        stateset->setTextureMode(_shadowTextureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON);
555
556        // create TexGen node
557        osg::ref_ptr<osg::TexGenNode> texGenNode = new osg::TexGenNode;
558        texGenNode->setTextureUnit(_shadowTextureUnit);
559        texGenNode->setTexGen(_texgen.get());
560        camera->addChild(texGenNode.get());
561#endif
562        //shader for correct display
563
564        osg::ref_ptr<osg::Program> program = new osg::Program;
565        stateset->setAttribute(program.get());
566       
567        osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_debugHUD);
568        program->addShader(fragment_shader);
569
570        camera->addChild(geode);
571
572        return camera;
573    }
574
575    //////////////////////// End Debug Section
Note: See TracBrowser for help on using the browser.