Thanks - using the correct node did the trick.

I am, however, completely baffled by the coordinates for the TexGen.

The following is a code snippet. The terrain coords are the standard -100 to 100 in both directions as used in the osgSpotlight example. In order to get the region covered by the texture to go from -50 to +50, the specification to ortho needs to be -150 to +50!!!

To get -100 to +100 it needs to be -300 to -100. The difference gives the width and the mean gives the left/bottom edge.

this gives a texture from -50 to +50
double left        = -150.0;
double right    =   50.0;
double bottom    = -150.0;
double top        =   50.0;
double znear    =   -1.0;
double zfar        =    1.0;

texgen->setPlanesFromMatrix(osg::Matrixd::lookAt(position, position+direction, up)*
                            osg::Matrixd::ortho(left,right,bottom,top,znear,zfar));

So I suppose the first question is:

am I using the correct method/matrices in order to get an exact geometry as specified in plan view.

and secondly

am I using them correctly.

I expect not. The answers may well be in the OpenGL refs, but am I away from my books at the moment. Thanks for any help.

Cheers
Alan


Robert Osfield wrote:
Hi Alan,

I think you should just need to attach the shadow texture stateset to the subgraph you want to shadow, looking through you code it looks like you are adding to the root of your scene graph, so it'll decoate everything below it including house etc.

Do you plan on moving the light source around at runtime?  If you only move the light source occassionally then you can probably get away with rendering the shadow using a RTT CameraNode that you switch on occassionally. 

You may also need to tile the shadow texture to avoid resolution artifacts, or make it view dependent, so that you only create a shadow texture for the portion of the scene you require. Over the coming months I'll be doing some work on stencil based shadows and seperate from this a view dependent view of OverlayNode.   There is a chance that I may be able to write the shadow API general enough to encompass other algorithms other than just stencil based shadows, and the view dependent code I develop for OverlayNode might just be appropriate to borrow for improvements to texture based shadow techniques ;-)

If you can wait for a couple of months for higher quality shadows then we might just be able to save you some effort, and in the short term you should be able to get your tree shadow working without too much effort, but expect quality issues once you get close to the terrain or work over a wide area - but since the solution might be comming you can move on to other work in the meantime.

Robert.

On 9/8/06, Alan Harris <[EMAIL PROTECTED]> wrote:
I have been trying to use a TexGen to create a ground level shadow
texture for a forest. The forests will eventually be defined by polygons
in the landscape and this appears to be the simplest route.

I have created a small example (attached - from osgSpotlight) that
creates a strip on the terrain. However, it also overlays any other
objects in the scene - in this case the house and the aircraft.

I of course want the shodown on the terrain and not over the house. Can
anyone help please.

A second problem is that I cannot relate the coordinates of the strip to
the landscape. The house and strip illustrate the difference. I aasume
that it is because I use ortho projection to maintain the shape on the
terrain.

Thanks.

--

Regards
Alan Harris

ReSoft Ltd
7 Church Lane
Flitton
BEDFORD, MK45 5EL, UK
Tel: +44 (0) 1525 862616
Email: [EMAIL PROTECTED]
Web: www.resoft.co.uk


#include <osg/Notify>
#include <osg/MatrixTransform>
#include <osg/ShapeDrawable>
#include <osg/PositionAttitudeTransform>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osg/Geode>
#include <osg/LightSource>
#include <osg/TexGenNode>
#include <osg/Matrix>

#include <osgUtil/Optimizer>

#include <osgDB/Registry>
#include <osgDB/ReadFile>

#include <osgProducer/Viewer>


// for the grid data..
//#include "../osghangglide/terrain_coords.h"
#include "terrain_coords.h"


osg::Image* createForestImage(const osg::Vec4& color, unsigned int size)
{
    osg::Image* image = new osg::Image;
    image->allocateImage(size,size,1,GL_RGBA,GL_UNSIGNED_BYTE);

    for(unsigned int r=0;r<size;++r)
    {
        unsigned char* ptr = image->data(0,r,0);
        for(unsigned int c=0;c<size;++c)
        {
            *ptr++ = (unsigned char)((color[0])*255.0f);
            *ptr++ = (unsigned char)((color[1])* 255.0f);
            *ptr++ = (unsigned char)((color[2])*255.0f);
            *ptr++ = (unsigned char)((color[3])*255.0f);
        }
    }
    return image;
}

osg::StateSet* createForestDecoratorState(unsigned int textureUnit)
{
    osg::StateSet* stateset = new osg::StateSet;

    osg::Vec4 centerColour(0.5f,0.5f,0.5f,1.0f);
    osg::Vec4 borderColour(1.0f,1.0f,1.0f,1.0f);

    // set up forest texture
    osg::Texture2D* texture = new osg::Texture2D();
    texture->setImage(createForestImage(centerColour, 64));
    texture->setBorderColor(osg::Vec4(borderColour));
    texture->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_BORDER);
    texture->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_BORDER);
    texture->setWrap(osg::Texture::WRAP_R,osg::Texture::CLAMP_TO_BORDER);

    stateset->setTextureAttributeAndModes(textureUnit, texture, osg::StateAttribute::ON);

    // set up tex gens
    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_S, osg::StateAttribute::ON);
    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_T, osg::StateAttribute::ON);
    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_R, osg::StateAttribute::ON);
    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_Q, osg::StateAttribute::ON);

    return stateset;
}

osg::Node* createForestBaseNode(unsigned int textureUnit)
{
    osg::Group* group = new osg::Group;

        osg::Vec3 position(0.0f,0.0f,0.0f);
        osg::Vec3 direction( 0.0f,0.0f,-1.0f);
    osg::Vec3 up(0.0f,1.0f,0.0f);

    osg::TexGenNode* texgenNode = new osg::TexGenNode;
    texgenNode->setTextureUnit(textureUnit);
    osg::TexGen* texgen = texgenNode->getTexGen();
    texgen->setMode(osg::TexGen::EYE_LINEAR);
//    texgen->setPlanesFromMatrix(osg::Matrixd::lookAt(position, position+direction, up)*
//                                osg::Matrixd::perspective(60.0,1.0, 0.1,100));

    texgen->setPlanesFromMatrix(osg::Matrixd::lookAt(position, position+direction, up)*
                                osg::Matrixd::ortho(0.0,20.0,-190.0,90.0,0.1,100));

    group->addChild(texgenNode);

    return group;

}

osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime)
{
    // set up the animation path
    osg::AnimationPath* animationPath = new osg::AnimationPath;
    animationPath->setLoopMode(osg::AnimationPath::LOOP);

    int numSamples = 40;
    float yaw = 0.0f;
    float yaw_delta = 2.0f*osg::PI/((float)numSamples-1.0f);
    float roll = osg::inDegrees( 30.0f);

    double time=0.0f;
    double time_delta = looptime/(double)numSamples;
    for(int i=0;i<numSamples;++i)
    {
        osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius, 0.0f));
        osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0))*osg::Quat(-(yaw+osg::inDegrees(90.0f)),osg::Vec3(0.0,0.0,1.0)));

        animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));

        yaw += yaw_delta;
        time += time_delta;

    }
    return animationPath;
}

osg::Node* createBase(const osg::Vec3& center,float radius)
{

    osg::Geode* geode = new osg::Geode;

    // set up the texture of the base.
    osg::StateSet* stateset = new osg::StateSet();
    osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
    if (image)
    {
        osg::Texture2D* texture = new osg::Texture2D;
        texture->setImage(image);
        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
    }

    geode->setStateSet( stateset );


    osg::HeightField* grid = new osg::HeightField;
    grid->allocate(38,39);
    grid->setOrigin(center+osg::Vec3(-radius,-radius,0.0f));
    grid->setXInterval(radius*2.0f/(float)(38-1));
    grid->setYInterval(radius*2.0f/(float)(39-1));

    float minHeight = FLT_MAX;
    float maxHeight = -FLT_MAX;


    unsigned int r;
    for(r=0;r<39;++r)
    {
        for(unsigned int c=0;c<38;++c)
        {
            float h = vertex[r+c*39][2];
            if (h>maxHeight) maxHeight=h;
            if (h<minHeight) minHeight=h;
        }
    }

    float hieghtScale = radius*0.5f/(maxHeight-minHeight);
    float hieghtOffset = -(minHeight+maxHeight)* 0.5f;

    for(r=0;r<39;++r)
    {
        for(unsigned int c=0;c<38;++c)
        {
            float h = vertex[r+c*39][2];
            grid->setHeight(c,r,(h+hieghtOffset)*hieghtScale);
        }
    }

    geode->addDrawable(new osg::ShapeDrawable(grid));

    osg::Group* group = new osg::Group;
    group->addChild(geode);
    group->addChild(createForestBaseNode(1));

    return group;

}

osg::Node* createMovingModel(const osg::Vec3& center, float radius)
{
    float animationLength = 10.0f;

    osg::AnimationPath* animationPath = createAnimationPath(center,radius,animationLength);

    osg::Group* model = new osg::Group;

    osg::Node* cessna = osgDB::readNodeFile("cessna.osg");
    if (cessna)
    {
        const osg::BoundingSphere& bs = cessna->getBound();

        float size = radius/bs.radius()*0.3f;
        osg::MatrixTransform* positioned = new osg::MatrixTransform;
        positioned->setDataVariance(osg::Object::STATIC);
        positioned->setMatrix(osg::Matrix::translate(- bs.center())*
                              osg::Matrix::scale(size,size,size)*
                              osg::Matrix::rotate(osg::inDegrees(180.0f),0.0f,0.0f,2.0f));

        positioned->addChild(cessna);

        osg::MatrixTransform* xform = new osg::MatrixTransform;
        xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,2.0));
        xform->addChild(positioned);

        model->addChild(xform);
    }

    return model;
}

osg::Node* createHouse()
{
    // create the Geode (Geometry Node) to contain all our osg::Geometry objects.
    osg::Geode* geode = new osg::Geode();

        double  x0, x1, x2, y0, y1, y2, z0, z1, z2;
        x0      = 0.0;
        x1      = 20.0;
        x2      = 10.0;
        y0      = 0.0;
        y1      = 20.0;
        y2      = 10.0;
        z0      = -40.0;
        z1      = -20.0;
        z2      = - 10.0;
    // create QUADS
    {
        // create Geometry object to store all the vetices and lines primtive.
        osg::Geometry* polyGeom = new osg::Geometry();

        // note, first coord at top, second at bottom, reverse to that buggy OpenGL image..
        osg::Vec3 walls[] =
        {
            osg::Vec3(x0, y0, z0),
            osg::Vec3(x1, y0, z0),
            osg::Vec3(x1, y0, z1),
            osg::Vec3(x0, y0, z1),

            osg::Vec3(x1, y0, z0),
            osg::Vec3(x1, y1, z0),
            osg::Vec3(x1, y1, z1),
            osg::Vec3(x1, y0, z1),

            osg::Vec3(x1, y1, z0),
            osg::Vec3(x0, y1, z0),
            osg::Vec3(x0, y1, z1),
            osg::Vec3(x1, y1, z1),

            osg::Vec3(x0, y1, z0),
            osg::Vec3(x0, y0, z0),
            osg::Vec3(x0, y0, z1),
            osg::Vec3(x0, y1, z1),

            osg::Vec3(x0, y0, z1),
            osg::Vec3(x1, y0, z1),
            osg::Vec3(x2, y2, z2),
            osg::Vec3(x2, y2, z2),

            osg::Vec3(x1, y0, z1),
            osg::Vec3(x1, y1, z1),
            osg::Vec3(x2, y2, z2),
            osg::Vec3(x2, y2, z2),

            osg::Vec3(x1, y1, z1),
            osg::Vec3(x0, y1, z1),
            osg::Vec3(x2, y2, z2),
            osg::Vec3(x2, y2, z2),

            osg::Vec3(x0, y1, z1),
            osg::Vec3(x0, y0, z1),
            osg::Vec3(x2, y2, z2),
            osg::Vec3(x2, y2, z2)
        };

        osg::Vec3 norms[] =
        {
            osg::Vec3( 0.0,-1.0, 0.0),
            osg::Vec3( 0.0,-1.0, 0.0),
            osg::Vec3( 0.0,-1.0, 0.0),
            osg::Vec3( 0.0,-1.0, 0.0),
            osg::Vec3( 1.0, 0.0, 0.0),
            osg::Vec3( 1.0, 0.0, 0.0),
            osg::Vec3( 1.0, 0.0, 0.0),
            osg::Vec3( 1.0, 0.0, 0.0),
            osg::Vec3( 0.0, 1.0, 0.0),
            osg::Vec3( 0.0, 1.0, 0.0),
            osg::Vec3( 0.0, 1.0, 0.0),
            osg::Vec3( 0.0, 1.0, 0.0 ),
            osg::Vec3(-1.0, 0.0, 0.0),
            osg::Vec3(-1.0, 0.0, 0.0),
            osg::Vec3(-1.0, 0.0, 0.0),
            osg::Vec3(-1.0, 0.0, 0.0),
            osg::Vec3( 0.0,-1.0, 1.0),
            osg::Vec3( 0.0,-1.0, 1.0),
            osg::Vec3( 0.0,-1.0, 1.0),
            osg::Vec3( 0.0,-1.0, 1.0),
            osg::Vec3( 1.0, 0.0, 1.0),
            osg::Vec3( 1.0, 0.0, 1.0),
            osg::Vec3( 1.0, 0.0, 1.0 ),
            osg::Vec3( 1.0, 0.0, 1.0),
            osg::Vec3( 0.0, 1.0, 1.0),
            osg::Vec3( 0.0, 1.0, 1.0),
            osg::Vec3( 0.0, 1.0, 1.0),
            osg::Vec3( 0.0, 1.0, 1.0),
            osg::Vec3(- 1.0, 0.0, 1.0),
            osg::Vec3(-1.0, 0.0, 1.0),
            osg::Vec3(-1.0, 0.0, 1.0),
            osg::Vec3(-1.0, 0.0, 1.0)
        };

        int numCoords = 32;

        osg::Vec3Array* vertices = new osg::Vec3Array(numCoords,walls);

        // pass the created vertex array to the points geometry object.
        polyGeom->setVertexArray(vertices);

        // set the colors as before, plus using the aobve
        osg::Vec4Array* colors = new osg::Vec4Array;
        colors->push_back(osg::Vec4(0.7f,0.0f,0.0f,1.0f));
        polyGeom->setColorArray(colors);
        polyGeom->setColorBinding(osg::Geometry::BIND_OVERALL);

        osg::Vec3Array* normals = new osg::Vec3Array(numCoords,norms);

                // pass the created normal array to the geometry object.
                polyGeom->setNormalArray(normals);
                polyGeom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);

        // This time we simply use primitive, and hardwire the number of coords to use
        // since we know up front,
        polyGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,numCoords));

        // add the points geomtry to the geode.
        geode->addDrawable(polyGeom);
    }

    return geode;
}


osg::Node* createModel()
{
    osg::Vec3 center(0.0f,0.0f,0.0f);
    float radius = 100.0f;

    // create light source.
    osg::LightSource* lightsource = new osg::LightSource;
    osg::Light* light = lightsource->getLight();
    light->setLightNum(0);
    light->setPosition(osg::Vec4( 1.00f,-1.00f,1.0f,0.0f));
    light->setAmbient(osg::Vec4(0.00f,0.00f,0.00f,1.0f));
    light->setDiffuse(osg::Vec4(1.0f,1.0f,1.0f,1.0f));

    lightsource->setLocalStateSetModes(osg::StateAttribute::ON);


    // the shadower model
    osg::Node* shadower = createMovingModel(center,radius*0.5f);

    // the shadowed model
    osg::Node* shadowed = createBase(center-osg::Vec3(0.0f,0.0f,radius*0.1),radius);

    // combine the models together to create one which has the shadower and the shadowed with the required callback.
    osg::Group* root = new osg::Group;

    root->setStateSet(createForestDecoratorState(1));

    root->addChild(createHouse());
    root->addChild(shadower);
    root->addChild(shadowed);

    osg::StateSet* rootStateSet = root->getStateSet();
    lightsource->setStateSetModes(*rootStateSet,osg::StateAttribute::ON);
    root->addChild(lightsource);

    return root;
}


int main( int argc, char **argv )
{

    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    // set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of pre rendering to texture to create a shadow effect..");
    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
    arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");

    // construct the viewer.
    osgProducer::Viewer viewer(arguments);

    // set up the value with sensible default event handlers.
    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);

    // get details on keyboard and mouse bindings used by the viewer.
    viewer.getUsage(*arguments.getApplicationUsage());

    // if user request help write it out to cout.
    if (arguments.read("-h") || arguments.read("--help"))
    {
        arguments.getApplicationUsage()->write(std::cout);
        return 1;
    }

    // any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized();

    // report any errors if they have occured when parsing the program aguments.
    if (arguments.errors())
    {
        arguments.writeErrorMessages (std::cout);
        return 1;
    }

    // load the nodes from the commandline arguments.
    osg::Node* model = createModel();
    if (!model)
    {
        return 1;
    }

    // comment out optimization over the scene graph right now as it optimizers away the shadow... will look into this..
    //osgUtil::Optimizer optimzer;
    //optimzer.optimize(rootnode);

    // add a viewport to the viewer and attach the scene graph.
    viewer.setSceneData( model );

        // switch off full screen
        ((viewer.getCamera(0))->getRenderSurface())->fullScreen(false);

    // create the windows and run the threads.
    viewer.realize();

    while( !viewer.done() )
    {
        // wait for all cull and draw threads to complete.
        viewer.sync();

        // update the scene by traversing it with the the update visitor which will
        // call all node update callbacks and animations.
        viewer.update();

        // fire off the cull and draw traversals of the scene.
        viewer.frame();

    }

    // wait for all cull and draw threads to complete before exit.
    viewer.sync();

    return 0;
}


_______________________________________________
osg-users mailing list
[email protected]
http://openscenegraph.net/mailman/listinfo/osg-users
http://www.openscenegraph.org/



_______________________________________________ osg-users mailing list [email protected] http://openscenegraph.net/mailman/listinfo/osg-users http://www.openscenegraph.org/


_______________________________________________
osg-users mailing list
[email protected]
http://openscenegraph.net/mailman/listinfo/osg-users
http://www.openscenegraph.org/

Reply via email to