multi-texturing question

I have an effect that I want to implement in my game engine, but I’m not sure the right OpenGL method…

…I’m on win98, VC++6 with an Nvidia GF2…

I have an offline program that can generate a “dirty map” for a geometry. You pass a geometry through this stand alone program and it spits out a UV array, a set of face indexes and a 1 channel “dirty map” 2D texture.

Here’s what I want to do, but I’m not sure how…

Have the original texture & color verts on the geometry, probably assigned to texture unit 0. Have another “skorched/scratched/scarred” texture be applied in addition to the previous texture- BUT it should be applied to the geometry using the precalculated “dirty map” as its alpha channel. Simple, right? But here’s the hitch: I want the resolution of the 2nd texture and the “dirty map” to be independant of each other.

I’m looking at the Red Book right now trying to figure out the right blending operations to use, but I guess I don’t have enough experience with them to be sure…

I want to use one texture as the alpha filter to apply another texture, but the two textures can have independant resolutions…

Any ideas, or links to a good blending tutorial?

-Blake

I think this could work:

Load your “dirty map” as a GL_ALPHA texture. Now render your object in 3 passes.

Pass 1) Render with the “dirty map”. This will write the alpha values you need into the color buffer.
*) Disable alpha writes at this point (glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE)).
Pass 2) Render using the base texture, and without blending.
Pass 3) Render with the scorch marks texture, and use glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA).
*) Reenable alpha writes for the next object or frame.

  • Tom

I dont think it makes a difference that the 2 textures are not the same size. Regardless of that, your tex coords go from 0.0 to 1.0. How many texels this spans is irrelevant.

The way I see it, is you want your object to contain 2 texture maps. The normal one, and an additional one, showing scars, scrathes etc…etc…

you should be able to do this in 1 pass using multi-texturing. As for the blending modes I’m not sure off hand, it depends what format your textures are in.

I did something similar once. Had a chromed object using texture unit 1, and then used to texture unit 2, to apply a scratch map to the surface.

Nutty

With multitexturing you can do what you describe in two passes.

Pass 1:
Disable blending and multitexturing.
Render the model using the main texture map.

Pass 2:
Set the depth test function to GL_EQUAL.
Enable alpha blending and texture unit 1.
Assign the dirty map (set to be an alpha texture) to texture unit 1 and set it to modulate.
Render the model using the second texture map.

Like Nutty said, having different texture resolutions makes no difference.

The usual way to do it though, is just to darken the dirty areas, and that way you can do it in just one pass. Doesn’t look quite as good, but it is faster.

I can’t see why it can’t be done in 1 pass with multi-texturing.

1 texture per pass, with 2 passes is not multitexturing, it’s multipass rendering.

Nutty

The problem is that he wants to use an alpha channel from texture A to control the blending of textures B and C (I think). So doing it in one pass on 2 texture hardware is not possible.

If it would be ok to put the “dirty map” into the original texture as an alpha channel then it could easily be done by drawing the scorched/scratched/scarred texture first and then the original texture overtop of it using a GL_DECAL texture environment. Unfortunately, lighting would not work properly then.

If you used the register combiners, it would be easy to set up so that lighting would work as well.

j

ic. So theres 3 maps in total…

Shouldn’t the dirty map be in the alpha channel of the 2nd map? If so, then they will need to be off the same size.

I assume, this dirty map is basically used to show where the 2nd map is visible on the object. In which case it should be in the alpha channel, should it not?

Nutty

Yes, there’s 3 textures. Basically I’m trying to implement 3DSMAX’s Blend material, after having generated such a material via the DirtyReyes plugin.

The DirtyReyes plugin generates a greyscale TGA file that is used as the alpha channel between a base material and an all black material.

What I’m doing is putting a scorched texture in place of the all black material, and supplying mip maps that gradually go from black to the higher resolution dirty/detail texture.

So I hope to get aged looking models in my engine with progressive detail as distance from the camera varies.

But I think I may have a hacky solution, mainly driven by my desire to get this working in one multi-texture pass:
When the model is about to be rendered for the first time, simply have a hook in the engine that gets executed right after the buffer clear; in the hook render the scorched texture and then render the alpha map into the alpha channel of the buffer, and read the buffer back as a new unified RGBA texture. Generate texture object. Only do this once, when the model is first rendered (or at “level load”.)

The maps’ resolutions can be different, I can use the same mechanism to generate the mip-maps and I can use vertex colors to ramp the lower resolution maps to black.

For 24 bit textures, doesn’t Nvidia hardware use 32 bits per texel anyway? So I’d be saving VRAM with this technique. (Also, I’m going thru ARB multiTexturing to support more than just Nvidia, hence no register combiners.)

But I’ve got one new wrinkle that has me rethinking the whole process… In the 3DSMAX Blend material dialog, you can tweak “lower” and “upper” parameters that define the range that the alpha texture should be mapped to. I’d ignore that aspect, but it turns out to be a major aspect of getting the right level of “dirt” in a model. So if “lower” is set to 0.25 and “upper” is 1.0 than the alpha channel values should all map within that range, 0==0.25, > interpolated_values < , 255==1.0.

Hmmm…

Later, when I can be assured that pbuffers are common, I’d just use this technique in a pbuffer. But I need to get the alpha range mapping to function.

Any ideas?

also, thanks all of you thus far. Each of your responses gave me more food for thought as I figure this out.

-Blake

Since you’re using 32-bit textures anyway, how about combining the dirty alpha-channel map with the second texture before uploading the texture? … The space is there, why not make use of it?

Or do you want the second texture to repeat and the alpha texture to be stretched over the entire geometry? Then you have to use different texcoords, hence three textures and no go with only 2 texturing units.

How about setting alpha at vertices instead of by texture?

I’m going to do something like this by myself soon, but our texture artist gave me five textures to play with. I’ll see what I can make of it, in the beginning I’ll just precalc a big world texture (or perhaps split it into smaller pieces). But mixing them in hardware does sound a bit sexy.

Yeah, I want the second texture to repeat and the alpha texture to cover the whole geometry…

I forgot that part when I was thinking about the hacky technique of using the hardware to render the alpha texture into the scorched/dirty-detail texture.

hmmm… I really want to figure out how to get this in one multi-texture pass. I my have to punt on the repeating texture part and just combine the alpha and scorched textures offline (or with the backBuffer/pBuffer hack upon first load/render.)

The whole thing is really starting to seem like an offline process, because I just figured out that the interpolation of alpha values between the “upper” and “lower” user parameters is done with this function:

float MappedAlpha( float a )
{
if (a < lower) return 0.0f;
if (a > upper) return 1.0f;
a = (a-lower)/(upper-lower);
return (aa(3.0f-(2.0f*a)));
}

Which is kinda a stretched S shaped curve. A 1D cubic of some form, I guess…

Is there any way to have the alpha channel index into a 1D texture? hmmm… Oh well.

Still useful, and I still have lots of stuff to do to get this working…

-Blake