Two textures, a colormap, a mixmap, and dynamic lighting

Sage
Posts: 1,199
Joined: 2004.10
Post: #1
All,

Some weeks ago I was aided greatly in this forum in figuring out how to use an RGBA texture as a colormap ( the RGB components ) and mixmap ( the alpha component ) for a terrain system.

http://www.idevgames.com/forum/showthread.php?t=7421

The code works, excellently.

Now, recently I've started to add dynamic lighting from effects in my game, like lasers and particle-system explosions and all that crap. The lighting works nicely for non-terrain geometry. [ for reference, the terrain lights correctly when texturing is turned off ]

So, here's my setup:

Code:
if ( _primaryTextureID )
{
    glActiveTextureARB( GL_TEXTURE0_ARB );
    glEnable( GL_TEXTURE_2D );
    glBindTexture( GL_TEXTURE_2D, _primaryTextureID );

    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
    glTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    glTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    glEnable( GL_TEXTURE_GEN_S );
    glEnable( GL_TEXTURE_GEN_T );

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 0.0f);
    
    glMatrixMode( GL_TEXTURE );
    glLoadIdentity();
    glScalef( _primaryTextureScale, _primaryTextureScale, 1.0f );
    glTranslatef( -_xyScaleOverTwo, -_xyScaleOverTwo, 0.0f );
    
    glMatrixMode( GL_MODELVIEW );
}

if ( !_secondaryTextureID )
{
    /*
        Set the colormap texture to TEXTURE2,
        and set up a scaling matrix to stretch
        it across the whole terrain, using
        automatic tex coord generation
    */
    glActiveTextureARB( GL_TEXTURE1_ARB );
    glEnable( GL_TEXTURE_2D );
    glBindTexture( GL_TEXTURE_2D, _colormapTextureID );

    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
    
    glTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    glTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    
    glEnable( GL_TEXTURE_GEN_S );
    glEnable( GL_TEXTURE_GEN_T );
    
    glMatrixMode( GL_TEXTURE );
    glLoadIdentity();
    glScalef( _oneOverXYScale, _oneOverXYScale, 1.0f );
    glTranslatef( -_xyScaleOverTwo, -_xyScaleOverTwo, 0.0f );
    
    glMatrixMode( GL_MODELVIEW );
}
else
{
    glActiveTextureARB( GL_TEXTURE1_ARB );
    glEnable( GL_TEXTURE_2D );
    glBindTexture( GL_TEXTURE_2D, _secondaryTextureID );
    
    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
    glTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    glTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );        
    glEnable( GL_TEXTURE_GEN_S );
    glEnable( GL_TEXTURE_GEN_T );
    
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 0.0f);

    glMatrixMode( GL_TEXTURE );
        glLoadIdentity();
        glScalef( _secondaryTextureScale, _secondaryTextureScale, 1.0f );
    glMatrixMode( GL_MODELVIEW );
    
    
    /*
        Set up mixmap blending, use alpha channel of TEXTURE2
        as interpolative factor between TEXTURE0 and TEXTURE1
    */
    
    glActiveTextureARB( GL_TEXTURE2_ARB );
    glEnable( GL_TEXTURE_2D );
    glBindTexture( GL_TEXTURE_2D, _colormapTextureID );
    
    glTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    glTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    
    glEnable( GL_TEXTURE_GEN_S );
    glEnable( GL_TEXTURE_GEN_T );
    
    glMatrixMode( GL_TEXTURE );
        glLoadIdentity();
        glScalef( _oneOverXYScale, _oneOverXYScale, 1.0f );
        glTranslatef( -_xyScaleOverTwo, -_xyScaleOverTwo, 0.0f );
    glMatrixMode( GL_MODELVIEW );

    glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE1_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
    glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE0_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
    glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE2_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, GL_SRC_ALPHA );
    glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE_ARB );

    /*
        Set up colormap blending
        Bind colormap to TEXTURE3, & set the TEXTURE_ENV_COLOR for
        to solid white with solid alpha, so TEXTURE3's alpha component
        is ignored
    */
    glActiveTextureARB( GL_TEXTURE3_ARB );
    glEnable( GL_TEXTURE_2D );
    glBindTexture( GL_TEXTURE_2D, _colormapTextureID );

    glTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    glTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
    
    glEnable( GL_TEXTURE_GEN_S );
    glEnable( GL_TEXTURE_GEN_T );
    
    glMatrixMode( GL_TEXTURE );
        glLoadIdentity();
        glScalef( _oneOverXYScale, _oneOverXYScale, 1.0f );
        glTranslatef( -_xyScaleOverTwo, -_xyScaleOverTwo, 0.0f );
    glMatrixMode( GL_MODELVIEW );
    
    /*
        I THINK THE TROUBLE LIES HERE
    */
        
    GLvector4f white = { 1, 1, 1, 1 };
    glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, white);
    glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
    glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_CONSTANT_EXT);
    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
}

Unfortunately, the solution reached for the mixmap blending is a little magical to me. I understand why it works, but I can't really figure out how to change it to allow the lighting of the underlying geometry to shine through.

I've made several modifications that I thought might do it, but none do. I've posted the original, not-mucked-with code.

If anybody has some insight, could you help me?
Quote this message in a reply
Sage
Posts: 1,234
Joined: 2002.10
Post: #2
So, this is what I get out of your code (the "else" path):
Code:
unit0: MODULATE: TEX0 * PRIMARY COLOR
unit1: REPLACE:  TEX1
unit2: COMBINE:  TEX1 * TEX2_a + TEX1 * (1-TEX2_a)
unit3: MODULATE: TEX3 * unit2
So there's a few things that probably aren't right here... first, the work done by unit0 is ignored, you never use it.

Second, your setup on unit3 is ignored, because you never specify COMBINE mode. Remember, the texture mode defaults to MODULATE, and the source, operand, etc setup doesn't affect any mode except for COMBINE.

Third, you're using four units when you could get the current result with only two (although, you have three textures, so you still need at least three units.)

OK, now for your original question... you want to modulate all of the texturing result with the lit primary color, right? So you need a pass at the end to do that. You could use a texture unit with MODULATE (PREVIOUS, PRIMARY_COLOR) to get the diffuse light component. You need another pass if you want specular.
Quote this message in a reply
Sage
Posts: 1,234
Joined: 2002.10
Post: #3
How's this look?
Code:
unit0: COMBINE:  TEX0 * TEX2_a + TEX1 * (1-TEX2_a)
unit1: COMBINE:  unit0 * TEX2_rgb
unit2: MODULATE: unit1 * PRIMARY_COLOR
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #4
That looks logical; the trouble is I'm over my head here... is there any chance you could skeleton it? I'm really not grokking COMBINE particularly well.

As always, I really appreciate your help, arrekusu.

EDIT: I wrote this in my COMBINE testbed app -- how's it look?

Code:
    /*
        Bind textures
        TEXTURE0 : Primary Texture
        TEXTURE1 : Secondary Texture
        TEXTURE2 : ColorMap / Mixmap
    */

    glActiveTextureARB( GL_TEXTURE0_ARB );
    glEnable( GL_TEXTURE_2D );
    glBindTexture( GL_TEXTURE_2D, _texture0 );

    glActiveTextureARB( GL_TEXTURE1_ARB );
    glEnable( GL_TEXTURE_2D );
    glBindTexture( GL_TEXTURE_2D, _texture1 );

    glActiveTextureARB( GL_TEXTURE2_ARB );
    glEnable( GL_TEXTURE_2D );
    glBindTexture( GL_TEXTURE_2D, _mixmap );
    

    /*
        unit0: COMBINE:  TEX0 * TEX2_a + TEX1 * (1-TEX2_a)
    */
    glActiveTextureARB( GL_TEXTURE0_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE_ARB );

    glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE0_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );

    glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE1_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );

    glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE2_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA );


    /*
        unit1: COMBINE:  unit0 * TEX2_rgb
    */
    glActiveTextureARB( GL_TEXTURE1_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );

    glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
    
    glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE2_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
    
    /*
        unit2: MODULATE: unit1 * PRIMARY_COLOR
    */
    glActiveTextureARB( GL_TEXTURE2_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );

    glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
    
    glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB );
    glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );

In my testbed app, it seems to work...

I get texture mixing, colormap application, and color interpolation between vertices. Seems right to me... I guess I'll put it in my game and cross my fingers.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #5
It works! Explosions and laser blasts cause the terrain to light up!

Now, a new pickle. The per vertex shading on the terrain looks like hell -- and is essentially unnecessary due to my having a light/color map.

I'm going to have to fiddle and see if I can disable the primary lightsource without the terrain going black, but have it respond to the effects lighting.
Quote this message in a reply
Sage
Posts: 1,234
Joined: 2002.10
Post: #6
That code looks fine. One thing is that the output alpha might be wrong, but that only matters if you're blending your terrain in multiple passes. You could use a constant env color to get 1.0 alpha on unit 1 if you need to.

So, yeah, it's up to you to figure out how to combine a diffuse colormap and GL's vertex lighting. If your colormap already has precalc'd shadows in it for the terrain, then maybe what you want is to ADD light in only for explosions. Figure out how to set up GL's lights so that all the terrain is black, except around an explosion. Then add PRIMARY_COLOR in unit3 instead of modulating.

Might look OK? There's no sure-fire solution, everything in graphics is approximations of approximations... so you have to dink around with it. Wink
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #7
Actually, I got it working and looking nice by having the terrain be rendered with only a mid-gray ambient light with specular and diffuse turned off. I get only the colormap lighting and dynamic lighting from lasers and explosions looks great.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #8
arekkusu Wrote:Might look OK? There's no sure-fire solution, everything in graphics is approximations of approximations... so you have to dink around with it. Wink

Yeah... I feel this pain. I spend waay too much time dinking with this stuff.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  2D Dynamic Lighting in OpenGL! Sort of... metacollin 22 18,603 Aug 19, 2009 01:48 AM
Last Post: Madrayken
  dynamic lighting problems ghettotek 3 2,613 Feb 15, 2003 07:05 PM
Last Post: ghettotek