Harald JOHSEN:

Changes
=======

- shadowvolume.cxx, renderer.cxx :
  - reduced the polygon offset a bit to eliminate some artifact ;
  - changed again the cleanup code for objects inside a tile because it could crash on rare occasion ;
  - the culling of shadow casters has been rewritten to traverse the scene graph, it should be
    a bit faster when there is a lot of objects ;
  - the range selector was not correctly handled, sometimes the wrong LOD was casting shadows.
  - added the option to display aircraft's transparent objects after the shadows, this will
    reduce the problem of shadows being hidden by the transparent object (propeller disk,
    rotor, etc). A side effect is that aircraft's transparent objects won't receive shadows
    anymore. This is usually a good thing except when the aircraft use a 'transparent'
    texture where it should not. A transparent texture in the plib context is a texture
    with an alpha channel or a material with alpha <= 0.99.

- model.cxx, animation.cxx, shadowvolume.cxx :
  - added an optional <condition> under the <noshadow> animation

- tower.cxx
  - correct a rare bug where all occurences of the aircraft are not deleted from the
  departure list causing a crash in FGTower::CheckDepartureList function.
This commit is contained in:
ehofman
2005-07-18 16:57:20 +00:00
parent 73cb6ff00d
commit f93ea20d5e
5 changed files with 179 additions and 103 deletions

View File

@@ -1506,15 +1506,35 @@ void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
// Implementation of SGShadowAnimation
////////////////////////////////////////////////////////////////////////
SGShadowAnimation::SGShadowAnimation (SGPropertyNode_ptr props)
: SGAnimation(props, new ssgBranch)
SGShadowAnimation::SGShadowAnimation ( SGPropertyNode *prop_root,
SGPropertyNode_ptr props )
: SGAnimation(props, new ssgBranch),
_condition(0),
_condition_value(true)
{
animation_type = 1;
SGPropertyNode_ptr node = props->getChild("condition");
if (node != 0) {
_condition = sgReadCondition(prop_root, node);
_condition_value = false;
}
}
SGShadowAnimation::~SGShadowAnimation ()
{
delete _condition;
}
int
SGShadowAnimation::update()
{
if (_condition)
_condition_value = _condition->test();
return 2;
}
bool SGShadowAnimation::get_condition_value(void) {
return _condition_value;
}
// end of animation.cxx

View File

@@ -589,8 +589,14 @@ private:
class SGShadowAnimation : public SGAnimation
{
public:
SGShadowAnimation (SGPropertyNode_ptr props);
SGShadowAnimation ( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGShadowAnimation ();
virtual int update();
bool get_condition_value(void);
private:
SGCondition * _condition;
bool _condition_value;
};

View File

@@ -166,7 +166,7 @@ sgMakeAnimation( ssgBranch * model,
} else if (!strcmp("dist-scale", type)) {
animation = new SGDistScaleAnimation(node);
} else if (!strcmp("noshadow", type)) {
animation = new SGShadowAnimation(node);
animation = new SGShadowAnimation(prop_root, node);
} else {
animation = new SGNullAnimation(node);
SG_LOG(SG_INPUT, SG_WARN, "Unknown animation type " << type);

View File

@@ -27,6 +27,7 @@
#include <simgear/screen/extensions.hxx>
#include <simgear/scene/model/animation.hxx>
#include <simgear/scene/model/model.hxx>
#include <simgear/environment/visual_enviro.hxx>
#include SG_GLU_H
#include "shadowvolume.hxx"
@@ -116,10 +117,15 @@ SGShadowVolume::ShadowCaster::ShadowCaster( int _num_tri, ssgBranch * _geometry_
ssgBranch *branch = (ssgBranch *) _geometry_leaf;
while( branch && branch->getNumParents() > 0 ) {
if( !first_select && branch->isA(ssgTypeSelector())) {
if( branch->isAKindOf(ssgTypeSelector())) {
first_select = branch;
break;
}
if( sgCheckAnimationBranch( (ssgEntity *) branch ) )
if( ((SGAnimation *) branch->getUserData())->get_animation_type() == 1) {
first_select = branch;
break;
}
branch = branch->getParent(0);
}
}
@@ -150,6 +156,7 @@ void SGShadowVolume::ShadowCaster::addLeaf( int & tri_idx, int & ind_idx, ssgLea
}
if( num_tri == 0 )
return;
isTranslucent |= geometry_leaf->isTranslucent() ? true : false;
int num_ind = geometry_leaf->getNumVertices();
ind_idx += num_ind;
}
@@ -302,7 +309,7 @@ void SGShadowVolume::ShadowCaster::DrawInfiniteShadowVolume(sgVec3 lightPosition
glDrawElements ( GL_TRIANGLES, lastSilhouetteIndicesCount, GL_UNSIGNED_SHORT, silhouetteEdgeIndices ) ;
//Draw caps if required
if(drawCaps)
if(drawCaps)
{
glBegin(GL_TRIANGLES);
{
@@ -344,8 +351,19 @@ void SGShadowVolume::ShadowCaster::getNetTransform ( ssgBranch * branch, sgMat4
// check the value of <select> and <range> animation
// wich have been computed during the rendering
bool SGShadowVolume::ShadowCaster::isSelected ( ssgBranch * branch ) {
bool SGShadowVolume::ShadowCaster::isSelected ( ssgBranch * branch, float dist ) {
while( branch && branch != lib_object) {
if( sgCheckAnimationBranch( (ssgEntity *) branch ) ) {
if( ((SGAnimation *) branch->getUserData())->get_animation_type() == 1)
if( ((SGShadowAnimation *) branch->getUserData())->get_condition_value() )
return false;
}
// recompute range check since the value in the branch is shared by multiple objects
// we can only have the last value
if( branch->isA(ssgTypeRangeSelector()) )
if( dist >= ((ssgRangeSelector *) branch)->getRange(1) ||
dist < ((ssgRangeSelector *) branch)->getRange(0))
return false;
if( branch->isA(ssgTypeSelector()) )
if( !((ssgSelector *) branch)->isSelected(0) )
return false;
@@ -366,8 +384,12 @@ void SGShadowVolume::ShadowCaster::computeShadows(sgMat4 rotation, sgMat4 rotati
// check the select and range ssgSelector node
// object can't cast shadow if it is not visible
sgVec4 trans;
sgCopyVec4( trans, rotation_translation[3] );
sgAddVec4( trans, states->CameraViewM[3] );
float dist = sgLengthVec3( trans );
if( first_select && ! isSelected( first_select) )
if( first_select && ! isSelected( first_select, dist) )
return;
// get the transformations : this comes from animation code for example
@@ -481,7 +503,7 @@ void SGShadowVolume::ShadowCaster::computeShadows(sgMat4 rotation, sgMat4 rotati
}
glCullFace(GL_BACK);
DrawInfiniteShadowVolume( lightPos, false);
DrawInfiniteShadowVolume( lightPos, states->shadowsAC_transp_enabled & isTranslucent);
//Decrement stencil buffer for back face depth pass
if( states->use_alpha ) {
@@ -493,43 +515,16 @@ void SGShadowVolume::ShadowCaster::computeShadows(sgMat4 rotation, sgMat4 rotati
}
glCullFace(GL_FRONT);
DrawInfiniteShadowVolume( lightPos, false);
DrawInfiniteShadowVolume( lightPos, states->shadowsAC_transp_enabled & isTranslucent);
}
}
void SGShadowVolume::SceneryObject::computeShadows(void) {
bool intersect = true;
// compute intersection with view frustum
// use pending_object (pointer on obj transform) & tile transform
// to get position
sgMat4 position, CamXpos;
sgFrustum *f = ssgGetFrustum();
pending_object->getParent(0)->getNetTransform( position );
sgCopyMat4 ( CamXpos, states->CameraViewM ) ;
sgPreMultMat4 ( CamXpos, position ) ;
sgSphere tmp = *(pending_object->getBSphere()) ;
if ( tmp.isEmpty () )
intersect = false;
else {
// 7000
float max_dist = 5000.0f;
tmp . orthoXform ( CamXpos ) ;
// cull if too far
if ( -tmp.center[2] - tmp.radius > max_dist )
intersect = false;
else if( tmp.center[2] == 0.0 )
intersect = true;
// cull if too small on screen
else if ( tmp.radius / sgAbs(tmp.center[2]) < 1.0 / 40.0 )
intersect = false;
else
intersect = SSG_OUTSIDE != (ssgCullResult) f -> contains ( &tmp );
}
if( intersect ) {
if( !scenery_object ) {
if( states->frameNumber - states->lastTraverseTreeFrame > 5 ) {
find_trans();
@@ -552,6 +547,74 @@ void SGShadowVolume::SceneryObject::computeShadows(void) {
for(iShadowCaster = parts.begin() ; iShadowCaster != parts.end() ; iShadowCaster ++ ) {
(*iShadowCaster)->computeShadows(rotation, rotation_translation, occluder_type);
}
}
static ssgCullResult cull_test ( ssgEntity *e, sgFrustum *f, sgMat4 m, int test_needed )
{
if ( ! test_needed )
return SSG_INSIDE ;
sgSphere tmp = *(e->getBSphere()) ;
if ( tmp.isEmpty () )
return SSG_OUTSIDE ;
tmp . orthoXform ( m ) ;
if( tmp.center[2] == 0.0 )
return SSG_STRADDLE;
// cull if too small on screen
if ( tmp.radius / sgAbs(tmp.center[2]) < 1.0 / 40.0 )
return SSG_OUTSIDE ;
return (ssgCullResult) f -> contains ( &tmp ) ;
}
void SGShadowVolume::cull ( ssgBranch *b, sgFrustum *f, sgMat4 m, int test_needed )
{
int cull_result = cull_test ( (ssgEntity *) b, f, m, test_needed ) ;
if ( cull_result == SSG_OUTSIDE )
return ;
if( b->isA( ssgTypeTransform() ) ) {
SceneryObject_map::iterator iSceneryObject = sceneryObjects.find( b );
if( iSceneryObject != sceneryObjects.end() ) {
SceneryObject *an_occluder = iSceneryObject->second;
if( shadowsTO_enabled && (an_occluder->occluder_type == occluderTypeTileObject) ||
shadowsAI_enabled && (an_occluder->occluder_type == occluderTypeAI ) ||
shadowsAC_enabled && (an_occluder->occluder_type == occluderTypeAircraft ) )
an_occluder->computeShadows();
return;
}
sgMat4 tmp, transform ;
sgCopyMat4 ( tmp, m ) ;
((ssgTransform *)b)->getTransform( transform );
sgPreMultMat4 ( tmp, transform ) ;
glPushMatrix () ;
glLoadMatrixf ( (float *) tmp ) ;
for ( ssgEntity *e = b->getKid ( 0 ) ; e != NULL ; e = b->getNextKid() )
cull ( (ssgBranch *) e, f, tmp, cull_result != SSG_INSIDE ) ;
glPopMatrix () ;
} else if( b->isAKindOf( ssgTypeSelector() ) ) {
int s = ((ssgSelector *) b)->getSelect() ;
if( b->isA( ssgTypeRangeSelector() ) ) {
float range = sgLengthVec3 ( m [ 3 ] ) ;
s = (range < ((ssgRangeSelector *) b)->getRange(1) &&
range >= ((ssgRangeSelector *) b)->getRange(0) ) ? 1 : 0;
}
for ( ssgEntity *e = b->getKid ( 0 ) ; e != NULL ; e = b->getNextKid(), s >>= 1 )
if ( s & 1 )
cull ( (ssgBranch *) e, f, m, cull_result != SSG_INSIDE ) ;
} else if( b->isAKindOf( ssgTypeBranch() ) ) {
char *name = b->getName();
// quick exit for the hundreds of ground leafs
if( name && !strcmp(name, "LocalTerrain") )
return;
for ( ssgEntity *e = b->getKid ( 0 ) ; e != NULL ; e = b->getNextKid() )
if( ! e->isAKindOf( ssgTypeLeaf() ) )
cull ( (ssgBranch *) e, f, m, cull_result != SSG_INSIDE ) ;
}
}
@@ -567,7 +630,11 @@ void SGShadowVolume::SceneryObject::computeShadows(void) {
overhead for matrix computation) and at the end this will reduce the number of
silouhette edge by a lot too.
*/
static bool filterName(const char *leaf_name) {
static bool filterLeaf(ssgLeaf *this_kid) {
const char *leaf_name = this_kid->getName();
/* ssgSimpleState *sst = (ssgSimpleState *) this_kid->getState();
if( sst && sst->isTranslucent() )
return false;*/
if( ! leaf_name )
return true;
char lname[20];
@@ -586,13 +653,14 @@ void SGShadowVolume::SceneryObject::traverseTree(ssgBranch *branch) {
if( sgCheckAnimationBranch( (ssgEntity *) branch ) ) {
if( ((SGAnimation *) branch->getUserData())->get_animation_type() == 1)
return;
if( ((SGShadowAnimation *) branch->getUserData())->get_condition_value() )
return;
}
for(int i = 0 ; i < branch->getNumKids() ; i++) {
ssgEntity *this_kid = branch->getKid( i );
if( this_kid->isAKindOf(ssgTypeLeaf()) ) {
if( filterName( this_kid->getName()) ) {
if( filterLeaf( (ssgLeaf *) this_kid ) ) {
num_tri += ((ssgLeaf *) this_kid)->getNumTriangles();
num_leaf ++;
}
@@ -605,13 +673,17 @@ void SGShadowVolume::SceneryObject::traverseTree(ssgBranch *branch) {
ShadowCaster *new_part = new ShadowCaster( num_tri, branch);
new_part->scenery_object = scenery_object;
new_part->lib_object = lib_object;
new_part->isTranslucent = false;
for(int i = 0 ; i < branch->getNumKids() ; i++) {
ssgEntity *this_kid = branch->getKid( i );
if( this_kid->isAKindOf(ssgTypeLeaf()) ) {
if( filterName( this_kid->getName()) )
if( filterLeaf( (ssgLeaf *) this_kid ) )
new_part->addLeaf( tri_idx, ind_idx, (ssgLeaf *) this_kid );
}
}
// only do that for aircraft
if( occluder_type != SGShadowVolume::occluderTypeAircraft )
new_part->isTranslucent = false;
new_part->SetConnectivity();
parts.push_back( new_part );
}
@@ -619,10 +691,8 @@ void SGShadowVolume::SceneryObject::traverseTree(ssgBranch *branch) {
void SGShadowVolume::SceneryObject::find_trans(void) {
ssgBranch *branch = pending_object;
ssgBranch *prev_branch = pending_object;
// check the existence of the root node
while( branch && branch->getNumParents() > 0 ) {
prev_branch = branch;
branch = branch->getParent(0);
}
// check if we are connected to the scene graph
@@ -688,8 +758,8 @@ void SGShadowVolume::computeShadows(void) {
glDisable( GL_FOG );
glEnable( GL_CULL_FACE );
// glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// glPolygonOffset(0.0,5.0);
glPolygonOffset(0.0,30.0);
glPolygonOffset(0.0,2.0);
// glPolygonOffset(0.0,30.0);
glEnable(GL_POLYGON_OFFSET_FILL);
glShadeModel(GL_FLAT);
@@ -698,14 +768,15 @@ void SGShadowVolume::computeShadows(void) {
glEnable( GL_DEPTH_TEST );
glDepthFunc(GL_LESS);
SceneryObject_map::iterator iSceneryObject;
// compute shadows for each objects
for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end(); iSceneryObject++ ) {
SceneryObject *an_occluder = iSceneryObject->second;
if( shadowsTO_enabled && (an_occluder->occluder_type == occluderTypeTileObject) ||
shadowsAI_enabled && (an_occluder->occluder_type == occluderTypeAI ) ||
shadowsAC_enabled && (an_occluder->occluder_type == occluderTypeAircraft ) )
an_occluder->computeShadows();
{
float w, h;
sgFrustum frustum;
sgEnviro.getFOV( w, h );
frustum.setFOV( w, h );
frustum.setNearFar(0.1f, 5000.0f);
sgMat4 m;
ssgGetModelviewMatrix( m );
cull( ssg_root, &frustum, m, true);
}
@@ -779,11 +850,12 @@ void SGShadowVolume::computeShadows(void) {
glPopAttrib();
}
SGShadowVolume::SGShadowVolume() :
init_done( false ),
SGShadowVolume::SGShadowVolume( ssgBranch *root ) :
shadows_enabled( false ),
frameNumber( 0 ),
lastTraverseTreeFrame ( 0 )
lastTraverseTreeFrame ( 0 ),
ssg_root( root ),
shadows_rendered( false )
{
states = this;
}
@@ -797,7 +869,6 @@ SGShadowVolume::~SGShadowVolume() {
}
void SGShadowVolume::init(SGPropertyNode *sim_rendering_options) {
init_done = true;
shadows_enabled = true;
sim_rendering = sim_rendering_options;
int stencilBits = 0, alphaBits = 0;
@@ -819,15 +890,13 @@ void SGShadowVolume::init(SGPropertyNode *sim_rendering_options) {
void SGShadowVolume::startOfFrame(void) {
}
void SGShadowVolume::deleteOccluderFromTile(ssgBranch *tile) {
SceneryObject_map::iterator iSceneryObject, iPrevious;
iPrevious = sceneryObjects.begin();
for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end(); iSceneryObject++ ) {
if( iSceneryObject->second->tile == tile ) {
delete iSceneryObject->second;
sceneryObjects.erase( iSceneryObject );
iSceneryObject = iPrevious;
SceneryObject_map::iterator iSceneryObject;
for(iSceneryObject = sceneryObjects.begin() ; iSceneryObject != sceneryObjects.end(); ) {
SceneryObject_map::iterator iCurrent = iSceneryObject ++;
if( iCurrent->second->tile == tile ) {
delete iCurrent->second;
sceneryObjects.erase( iCurrent );
}
iPrevious = iSceneryObject;
}
}
@@ -868,10 +937,10 @@ void SGShadowVolume::setupShadows( double lon, double lat,
double gst, double SunRightAscension, double SunDeclination, double sunAngle) {
shadowsAC_enabled = sim_rendering->getBoolValue("shadows-ac", false);
shadowsAC_transp_enabled = sim_rendering->getBoolValue("shadows-ac-transp", false);
shadowsAI_enabled = sim_rendering->getBoolValue("shadows-ai", false);
shadowsTO_enabled = sim_rendering->getBoolValue("shadows-to", false);
shadowsDebug_enabled = sim_rendering->getBoolValue("shadows-debug", false);
// shadows_enabled = sim_rendering->getBoolValue("shadows", false);
shadows_enabled = shadowsAC_enabled || shadowsAI_enabled || shadowsTO_enabled;
shadows_enabled &= canDoAlpha || canDoStencil;
use_alpha = ((!canDoStencil) || sim_rendering->getBoolValue("shadows-alpha", false)) &&
@@ -880,29 +949,8 @@ void SGShadowVolume::setupShadows( double lon, double lat,
if( ! shadows_enabled )
return;
sgMat4 view_angle;
shadows_rendered = false;
sun_angle = sunAngle;
{
sgMat4 LON, LAT;
sgVec3 axis;
sgSetVec3( axis, 0.0, 0.0, 1.0 );
sgMakeRotMat4( LON, lon, axis );
sgSetVec3( axis, 0.0, 1.0, 0.0 );
sgMakeRotMat4( LAT, 90.0 - lat, axis );
sgMat4 TRANSFORM;
sgMakeIdentMat4 ( TRANSFORM );
sgPreMultMat4( TRANSFORM, LON );
sgPreMultMat4( TRANSFORM, LAT );
sgCoord pos;
sgSetCoord( &pos, TRANSFORM );
sgMakeCoordMat4( view_angle, &pos );
}
{
sgMat4 GST, RA, DEC;
sgVec3 axis;
@@ -917,8 +965,6 @@ void SGShadowVolume::setupShadows( double lon, double lat,
sgSetVec3( axis, 1.0, 0.0, 0.0 );
sgMakeRotMat4( DEC, SunDeclination * SGD_RADIANS_TO_DEGREES, axis );
sgInvertMat4( invViewAngle, view_angle);
sgMat4 TRANSFORM;
sgMakeIdentMat4( TRANSFORM );
sgPreMultMat4( TRANSFORM, GST );
@@ -935,13 +981,20 @@ void SGShadowVolume::setupShadows( double lon, double lat,
void SGShadowVolume::endOfFrame(void) {
if( ! shadows_enabled )
return;
if( shadows_rendered )
return;
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_1D, 0);
glMatrixMode(GL_MODELVIEW);
computeShadows();
frameNumber ++;
shadows_rendered = true;
}
int SGShadowVolume::ACpostTravCB( ssgEntity *entity, int traversal_mask ) {
if( states->shadowsAC_transp_enabled && (SSGTRAV_CULL & traversal_mask) )
states->endOfFrame();
return 0;
}

View File

@@ -41,7 +41,7 @@ class SGPropertyNode;
class SGShadowVolume {
public:
SGShadowVolume();
SGShadowVolume( ssgBranch *root );
~SGShadowVolume();
typedef enum {
@@ -58,7 +58,7 @@ public:
void setupShadows(double lon, double lat,
double gst, double SunRightAscension, double SunDeclination, double sunAngle );
void endOfFrame(void);
static int ACpostTravCB( ssgEntity *entity, int traversal_mask );
private:
@@ -87,7 +87,7 @@ private:
sgVec4 * vertices;
GLushort *silhouetteEdgeIndices;
int lastSilhouetteIndicesCount;
bool isTranslucent;
ShadowCaster( int _num_tri, ssgBranch * _geometry_leaf );
~ShadowCaster();
@@ -97,7 +97,7 @@ private:
void DrawInfiniteShadowVolume(sgVec3 lightPosition, bool drawCaps);
void computeShadows(sgMat4 rotation, sgMat4 rotation_translation, OccluderType occluder_type);
void getNetTransform ( ssgBranch * branch, sgMat4 xform );
bool isSelected ( ssgBranch * branch );
bool isSelected ( ssgBranch * branch, float dist);
bool sameVertex(int edge1, int edge2);
};
@@ -123,10 +123,11 @@ private:
private:
void update_light_view(void);
void computeShadows(void);
void cull ( ssgBranch *b, sgFrustum *f, sgMat4 m, int test_needed );
bool init_done;
bool shadows_enabled;
bool shadowsAC_enabled, shadowsAI_enabled, shadowsTO_enabled, shadowsDebug_enabled;
bool shadowsAC_transp_enabled;
bool use_alpha;
bool canDoAlpha, canDoStencil;
SGPropertyNode *sim_rendering;
@@ -135,14 +136,10 @@ private:
int frameNumber;
int lastTraverseTreeFrame;
sgMat4 CameraViewM;
sgMat4 invViewAngle;
double sun_angle;
SceneryObject_map sceneryObjects;
/** this sphere contains the visible scene and is used to cull shadow casters */
sgSphere frustumSphere;
/** this sphere contains the near clip plane and is used to check the need of a zfail */
sgSphere nearClipSphere;
ssgBranch *ssg_root;
bool shadows_rendered;
};
#endif // _SHADOWVOLUME_HXX