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/
