Decals on terrain, objects etc.

Member
Posts: 156
Joined: 2002.10
Post: #1
I'm wanting to implement a decal system in my game so that explosions, bullets etc. will leave marks on the terrain or other objects they impact. Having trouble finding much through google on this subject, but I'm pretty sure someone here will have implemented this before, or have a link to some decent tutorials.

A few questions I had were:

Currently the objects I'd like to stick decals on are a heightmap mesh (no overhangs) and other 3D objects scattered around the scene. Is it easier to combine all these into one big mesh?

How would I do decalling where the decal is on the heightmap, but it also overlaps onto another object?

Thanks in advance,

- iain
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #2
I've done this in the past.

First, you need to have some sort of collision detection that can give you triangles which intersect, say, a sphere. So when you blow up a grenade or whatever, you can get a list of triangles which intersect the spherical radius of "damage".

Then, you'll do a sort of projected texturing. When I did this, I picked a single "normal" and "center" for the decal triangles ( I think I averaged their normals and centroids ) and using that I was able to assign texture coordinates to the triangles radially.

Then, I just used glPolygonOffset and rendered the triangle list after rendering the solid geometry.

It works pretty well for convex geometry. When dealing with non-convex, it still works, but you can get some oddities. In retrospect, I would have been smart to only apply the decal triangles if they "faced" the explosion.

I've got source code if you want to see.
Quote this message in a reply
Member
Posts: 156
Joined: 2002.10
Post: #3
A look at your code would be very helpful.

You can either post it here or mail it to me iain < at> pyramid <dash> productions <dot> net

Cheers

- Iain
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #4
Here you go:

http://zakariya.net/shamyl/etc/Decals/

I hadn't looked at the code in a long time, so I was a little wrong about how I generated texture coords. It turns out I was using GL's texgen facilities, but it's easy enough to wrangle meaningfully.

The relevant code is here:
Code:
Decal::Decal( TrimeshTriangleVec &triangles, GLuint textureID, float scale,
              vec3 center, vec3 normal, float lifespan, vec4 color, vec3 referenceY ):
    VisibilityListener( false, false ),
    _triangleArray(0), _nTriangles(0),
    _textureID( textureID ),
    _scale( scale ), _lifespan( lifespan ), _age(0),
    _center( center ), _normal( normal ), _color( color ),
    _expired( false ),
    _family(0)
{
    /*
        Add to scene graph
    */
    place( GameWorld::instance()->stage()->sceneGraph(), AABB( center, scale * 0.5f ));

    /*
        Copy triangles to triangle array, and generate an AABB
    */

    _nTriangles = triangles.size();
    _triangleArray = new TrimeshTriangle[ _nTriangles ];
    for ( int i = 0; i < _nTriangles; i++ )
    {
        _triangleArray[i] = triangles[i];        
    }
    
    vec3 origin( _center + _normal );
    vec3 pointOnTexturePlane( _center - origin );
    
    pointOnTexturePlane.normalize();
    pointOnTexturePlane += _center;

    /*
        Get s & t axes for this plane -- the plane faces
        the center
    */
    vec3 projectionDirection( _center - pointOnTexturePlane );
    projectionDirection.normalize();
    
    vec3 sAxis, tAxis;
    
    sAxis.cross( projectionDirection, referenceY );
    sAxis.normalize();
    
    tAxis.cross( sAxis, projectionDirection );
    tAxis.normalize();
    
    /*
        Get plane equation for the texture plane
    */
    vec4 texturePlaneEquation( calculatePlaneEquation( pointOnTexturePlane, pointOnTexturePlane + sAxis, pointOnTexturePlane + tAxis ));


    /*
        Calculate the origin of the plane
    */
    vec3 planeOrigin( texturePlaneEquation );
    planeOrigin *= -texturePlaneEquation.w;


    /*
        Nor calculate the position of pointOnTexturePlane in coordinates
        relative to the texture plane, 2D.
    */
    vec3 normalizedClosestProjection( pointOnTexturePlane - planeOrigin );
    float hypLength = normalizedClosestProjection.normalize();
    float sOffset = 0, tOffset = 0, rScale = 1.0f / _scale;
    
    if ( hypLength > 0.001f )
    {
        sOffset = ( normalizedClosestProjection * sAxis ) * hypLength;
        tOffset = ( normalizedClosestProjection * tAxis ) * hypLength;
    }
    
    /*
        Now scale the axes and the s & t positions, subtraction of 0.5
        centers the texture.
    */
                
    sOffset *= rScale;
    tOffset *= rScale;
    
    sOffset -= 0.5f;
    tOffset -= 0.5f;
                
    vec3 scaledSAxis( sAxis * rScale ),
         scaledTAxis( tAxis * rScale );

    _textureSAxis = vec4( scaledSAxis.x, scaledSAxis.y, scaledSAxis.z, -sOffset );
    _textureTAxis = vec4( scaledTAxis.x, scaledTAxis.y, scaledTAxis.z, -tOffset );
    
}

And the rendering code:
Code:
void Decal::displaySecondPass( float deltaT )
{
    if ( hasExpired( deltaT )) return;
        
    /*
        Setup
    */

    glDisable( GL_LIGHTING );
    glDepthMask( GL_FALSE );

    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    glEnable( GL_ALPHA_TEST );
    glAlphaFunc( GL_GREATER, 0.01f );
    
    glDepthFunc( GL_LEQUAL );
            
    PolygonOffset::push( 0, -10 );

    glEnable( GL_TEXTURE_2D );
    glBindTexture( GL_TEXTURE_2D, _textureID );
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

    glEnable(GL_TEXTURE_GEN_S);
    glEnable(GL_TEXTURE_GEN_T);
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );

    glEnableClientState( GL_VERTEX_ARRAY );

    setDisplayVA();

    /*
        Teardown
    */
    glDisableClientState( GL_VERTEX_ARRAY );

    glEnable( GL_LIGHTING );
    glDepthMask( GL_TRUE );
    glDisable( GL_BLEND );
    glDisable( GL_ALPHA_TEST );
    glDisable( GL_TEXTURE_GEN_S );
    glDisable( GL_TEXTURE_GEN_T);
    glDisable( GL_TEXTURE_2D );    

    PolygonOffset::pop();
}

void Decal::setDisplayVA( void )
{
    /*
        Give TexGen our axes and offsets
    */
    glTexGenfv( GL_S, GL_OBJECT_PLANE, _textureSAxis.v );
    glTexGenfv( GL_T, GL_OBJECT_PLANE, _textureTAxis.v );

    /*
        Assign a color with alpha approaching zero as
        age approaches lifespan.
    */

    vec4 color( _color );

    if ( _lifespan > 0 )
    {
        color.w *= 1.0f - ( _age / _lifespan );
    }
    
    if ( LOD == 1 )
    {
        color.w *= 0.5f;
    }
    else if ( LOD >= 2 )
    {
        color.w *= 0.25f;    
    }
    
    glColor4fv( color );        

    glVertexPointer( 3, GL_FLOAT, 0, _triangleArray );
    glDrawArrays( GL_TRIANGLES, 0, _nTriangles * 3 );
}
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Best way to add roads/objects to a terrain engine? Jake 6 3,714 Sep 6, 2004 07:25 AM
Last Post: Jake
  Equation of a plane and normals + Decals Jake 2 2,561 Aug 28, 2004 11:40 AM
Last Post: Jake