shadowlightopenscenegraph

OpenSceneGraph just cast shadow for one of the lights in the scene


I am trying to put different lights in a scene and have them cast shadows simultaneously. The problem is that every time I create a new osgShadow::ShadowMap for a light, the previous light stops casting shadow. I suspect that this has something to do with index or something, the same way every light has to have a setLightNum(x) defined. Below is the code used as reference for this image: printed image.

// * Copyright (c) 1982, 1986, 1990, 1991, 1993
// *      The Regents of the University of California.  All rights reserved.
// *
// * Redistribution and use in source and binary forms, with or without
// * modification, are permitted provided that the following conditions
// * are met:
// * 1. Redistributions of source code must retain the above copyright
// *    notice, this list of conditions and the following disclaimer.
// * 2. Redistributions in binary form must reproduce the above copyright
// *    notice, this list of conditions and the following disclaimer in the
// *    documentation and/or other materials provided with the distribution.
// * 3. All advertising materials mentioning features or use of this software
// *    must display the following acknowledgement:
// *      This product includes software developed by the University of
// *      California, Berkeley and its contributors.
// * 4. Neither the name of the University nor the names of its contributors
// *    may be used to endorse or promote products derived from this software
// *    without specific prior written permission.
// *
// * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
// * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
// * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// * SUCH DAMAGE.

#include <iostream>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osg/Node>
#include <osg/ref_ptr>
#include <osg/LightModel>
#include <osg/Geode>
#include <osg/ShapeDrawable>
#include <osg/Material>
#include <osg/Texture2D>
#include <osg/PositionAttitudeTransform>
#include <osg/Group>
#include <osg/MatrixTransform>
#include <osg/LightSource>
#include <osgShadow/ShadowedScene>
#include <osgShadow/ShadowMap>


#define LIGHT_CUTOFF_ANGLE 15
#define FILE_PATH_1 "tank.osg"
#define FILE_PATH_2 "rov.osg"


osg::Node* createLightSource(unsigned int num,
                             const osg::Vec3& trans,
                             const osg::Vec4& color)
{
    osg::ref_ptr<osg::Light> light = new osg::Light;
    light->setLightNum(num);
    light->setDiffuse(color);
    light->setPosition(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
    osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource;
    lightSource->setLight(light);
    osg::ref_ptr<osg::MatrixTransform> sourceTrans = new osg::MatrixTransform;
    sourceTrans->setMatrix(osg::Matrix::translate(trans));
    sourceTrans->addChild(lightSource.get());
    return sourceTrans.release();
}

int main(int argc, char const *argv[])
{
    // Set masks of shadow receivers and casters
    unsigned int rcvShadowMask = 0x1;
    unsigned int castShadowMask = 0x2;

    // Tank
    osg::ref_ptr<osg::MatrixTransform> tankNode = new osg::MatrixTransform;
    tankNode->addChild(osgDB::readNodeFile(FILE_PATH_1));
    tankNode->setMatrix(osg::Matrix::translate(0.0f, 0.0f, 0.0f));
    tankNode->setNodeMask(rcvShadowMask|castShadowMask);

    // ROV
    osg::ref_ptr<osg::MatrixTransform> rovNode = new osg::MatrixTransform;
    rovNode->addChild( osgDB::readNodeFile(FILE_PATH_2));
    rovNode->setMatrix(osg::Matrix::translate(5.0f, 5.0f, -1.0f));
    rovNode->setNodeMask(rcvShadowMask|castShadowMask);

    // Ambient light (taken from book)
    osg::ref_ptr<osg::LightSource> source0 = new osg::LightSource;
    source0->getLight()->setPosition(osg::Vec4(5.0, 5.0, 9.0, 0.0));
    source0->getLight()->setAmbient(osg::Vec4(0.2, 0.2, 0.2, 1.0));
    source0->getLight()->setDiffuse(osg::Vec4(0.8, 0.8, 0.8, 1.0));

    // We choose the famous and effective shadow mapping (osgShadow::ShadowMap) technique, and set its
    // necessary parameters including the light source, shadow texture's size, and unit:
    osg::ref_ptr<osgShadow::ShadowMap> sm0 = new osgShadow::ShadowMap;
    sm0->setLight(source0.get());
    sm0->setTextureSize(osg::Vec2s(1024, 1024));
    sm0->setTextureUnit(1);

    //Set the shadow scene's root node, and apply the technique instance, as well as shadow masks to it:
    osg::ref_ptr<osgShadow::ShadowedScene> root = new osgShadow::ShadowedScene;
    root->setShadowTechnique(sm0.get());
    root->setReceivesShadowTraversalMask(rcvShadowMask);
    root->setCastsShadowTraversalMask(castShadowMask);

    // Create a light state set
    osg::StateSet* state = root->getOrCreateStateSet();

/*     state->setMode(GL_LIGHTING, osg::StateAttribute::ON);
    state->setMode(GL_LIGHT0, osg::StateAttribute::ON); */
    state->setMode(GL_LIGHT1, osg::StateAttribute::ON);
/*     state->setMode(GL_LIGHT2, osg::StateAttribute::ON);
    state->setMode(GL_LIGHT3, osg::StateAttribute::ON); */

    // 1st Light Cone
     osg::ref_ptr<osg::Light> light1 = new osg::Light();
    light1->setAmbient(osg::Vec4(0.1, 0.1, 0.1, 0.5));
    light1->setPosition(osg::Vec4(4.0, 4.0, 9.0, 1.0));
    light1->setDirection(osg::Vec3(0, 0, -1)); 
    light1->setSpotCutoff(LIGHT_CUTOFF_ANGLE);
    light1->setLightNum(1);
    osg::ref_ptr<osg::LightSource> source1 = new osg::LightSource();
    source1->setLight(light1.get());

    // We may have many lights, but only one of them will cast shadows so far.
    // Uncomment the ShadowMap lines to see this behavior.
/*     osg::ref_ptr<osgShadow::ShadowMap> sm1 = new osgShadow::ShadowMap;
    sm1->setLight(source1.get());   
    sm1->setTextureSize(osg::Vec2s(1024, 1024));
    sm1->setTextureUnit(1);
    root->setShadowTechnique(sm1.get());  */

    // Add all models and the light source to the root
    root->addChild(tankNode.get());
    root->addChild(rovNode.get());
    root->addChild(source0.get());
    root->addChild(source1.get());

    // Start the viewer
    osgViewer::Viewer viewer;
    viewer.setSceneData(root.get());
    return viewer.run();
}

Why I am not getting a shadow for every light? What am I missing here?

Thank you in advance!


Solution

  • You are using a wrong method for this. To allow use multiple lights use:

    osgShadow::ViewDependentShadowMap* sm0 = new osgShadow::ViewDependentShadowMap;

    insted of

        osg::ref_ptr<osgShadow::ShadowMap> sm0 = new osgShadow::ShadowMap;
        sm0->setLight(source0.get());
        sm0->setTextureSize(osg::Vec2s(1024, 1024));
        sm0->setTextureUnit(1);
    

    See: http://www.openscenegraph.org/index.php/documentation/guides/programming-guides/108-shadows