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/
|