Sign in to follow this  

texture blending layers

This topic is 4771 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi guys, I know what I want to do, but I'm not sure how to do it. :-) I rendering the textures on my terrain and I want to do it like the following. Each texture layer (with the exception of the base layer), has an alpha map associated with it. I want to use that alpha map to blend the current layer onto the layer below it. I also want to support a infinite number of texture layers (obviously restricted by performance). So my questions are, how do I do this? Do I need to use register combiners and if so how? I do not want to use any vertex or fragment shaders, at least not now. I'd appreciate any help, I've been looking up things and trying to figure it out for a while now. [Edited by - pammatt on November 17, 2004 10:30:28 AM]

Share this post


Link to post
Share on other sites
That's pretty easy to do with blending and/or texture combiners.

The easiest way : full multipass.
render the terrain with the base texture
enable blending (glEnable(GL_BLEND) and glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA))
set depth function to equal (glDepthFunc(GL_EQUAL))
for i = 2 to n, render the terrain with the ith texture
disable blending (glDisable(GL_BLEND))
restore depth function (eg glDepthFunc(GL_LESS))

More clever way : use as many texture units as possible.
Use the same method as above, except that you group texture passes with multitexturing available for the first pass. For instance, if your graphics card supports 4 texture units and if you have 7 layers, then render 4 layers in a first pass and render the 3 other layers in 3 passes.

The former method uses n passes to render n layers. The latter method uses min(0,n-m)+1 to render n layers with m texture units.

Share this post


Link to post
Share on other sites
with any card u can do.
draw the first terrain layer.
and then for subsequent texture layers enable blending with GL_SRC_ALPHA ONE_MINUS_SRC_ALPHA, + draw the relelavent terrain polygons.

with higher capable cards u can collaspse these multiple passes down into fewer passes (which may or may not run quicker)
eg with glsl on gffx u can access 16 textures in one pass

Share this post


Link to post
Share on other sites
good point reminds me with the blending passes u can disable deopthwrites, which will provide a speedboost (maybe)
also dont use GL_EQUAL (the ati performance faq saiz this aint optimal) use GL_LEQUAL instead

Share this post


Link to post
Share on other sites
Right, makes sense, but what stumps me, is how do I do this using a seperate alpha map and not the alpha channel of the terrain texture layers. The reason I ask, is that I want to use the same set of texture coordinates for each layer and rely on the texture matrix. So if I want one of the texture layers to repeat several times, I want its alpha mask to remain unaffected.

Share this post


Link to post
Share on other sites
Quote:
Right, makes sense, but what stumps me, is how do I do this using a seperate alpha map and not the alpha channel of the terrain texture layers

You can use pair of textures with the GL_ARB_texture_env_crossbar extension (or GL_NV_texture_env_combine4 for NVIDIA cards). This requires graphics cards that handle multitexturing with at least 2 texture units (TBH almost all cards do it today!), and this requires twice the number of texture units when using the "second" method I mentioned above.

Share this post


Link to post
Share on other sites
you dont need to use the crossbar extension.

you have to use 2 texture units for the mask and the terrain quad (using interpolate, not modulate), then the result of that u blend with multipass (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).

just do that for all ur layers.

you can avoid the multipass completely and just do multitexturing, but you'll run out of texture units very fast! 3 layers + 3 masks = 6 texture units, or in ur case 3 layers + 2 masks = 5 units.

older cards have 4 units, moderately new cards have 6, and most new cards have 8.

Share this post


Link to post
Share on other sites
Quote:
Original post by DaN1maL
you dont need to use the crossbar extension.

...

you can avoid the multipass completely and just do multitexturing, but you'll run out of texture units very fast!

If you're skipping multipass thanks to multitexturing, you _need_ the crossbar capability.

Quote:
Original post by DaN1maL
older cards have 4 units, moderately new cards have 6, and most new cards have 8.

Roughly :
GeForce1, GeForce2GTS/MX/Go) and GeForce4MX/Go have 2 texture units, GeForce 3Ti and GeForce4Ti have 4 texture units and GeForceFX have 16 texture units (well, in fact you have to play a bit with it to get as much as that, since only 4 are available without fragemnt programs).
Radeon 7xxx have 3 texture units, Radeon 8xxx lower 9xxx (that is, R200 class) have 6 texture units, and higher Radeon 9xxx (R300 class) have 8 texture units.
And most other graphics cards do support 2 texture units, except very very old cards that so not support multitexturing.

Share this post


Link to post
Share on other sites
By older I meant gf3 ;)

You don't need crossbar ext...

texunit 0 - layer 1 (doesn't need mask)
texunit 1 - layer 2's mask
texunit 2 - layer 2 (use interpolate to blend using prev alpha map)
texunit 3 - layer 3's mask
texunit 4 - layer 3 (use interpolate to blend using prev alpha map)

You never need to access anything before the previous texture unit.

Unless crossbar does more than allow you to use GL_TEXTUREn .. I'm not sure. I've never had to use crossbar, and I've done exactly the above.

Share this post


Link to post
Share on other sites
I have everything working utilizing the crossbar functionality. I'm not sure how to set up the combiner state for this layout though. (Still new to the combiner thing so please bear with me).

SOURCE2 would be the alpha map, so GL_PREVIOUS...
SOURCE1 would be the current layer, so GL_TEXTURE

now one of those sources needs to be the previous texture layer.. but I'm not sure how to get that to work without the crossbar stuff.

Thanks for the help thus far, and hopefully i'm not sounding too stupid. :-)

Share this post


Link to post
Share on other sites
Anyone can complete pammatt efforts?

what will be the right combination using combiners operations... none NV or ATI specific will be more interesting... just one pass witout blending... sounds like a challenge!!! hehe

THX

Share this post


Link to post
Share on other sites
Just realized, what I mean in my latest post is how to I acheive the setup DaN1maL gave.

texunit 0 - layer 1 (doesn't need mask)
texunit 1 - layer 2's mask
texunit 2 - layer 2 (use interpolate to blend using prev alpha map)
texunit 3 - layer 3's mask
texunit 4 - layer 3 (use interpolate to blend using prev alpha map)

Thanks.

Share this post


Link to post
Share on other sites
// texunit 0 - layer 1 (doesn't need mask)
glActiveTextureARB(GL_TEXTURE0_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

// texunit 1 - layer 2's mask
glActiveTextureARB(GL_TEXTURE1_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
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_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);

// texunit 2 - layer 2 (use interpolate to blend using prev alpha map)
glActiveTextureARB(GL_TEXTURE2_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE);
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_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_PREVIOUS_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA);

// texunit 3 - layer 3's mask
// texunit 4 - layer 3 (use interpolate to blend using prev alpha map)
// For textutre units 3 and 4 (and other pairs if your card support more units), simply copy'n'paste the code for texture units 1 and 2, granted you replace the GL_TEXTUREi_ARB token of course [wink]
// [edit] : BTW, instead of copy/paste, you can use display lists. In this case it's more a toy though.

Share this post


Link to post
Share on other sites
I was thinking about something along those lines but I wasn't sure if it would work for the following..

given a card with 4 texture units available I would have to do some multi-pass stuff. I didn't think that setup would work for the following:

texunit 0 - layer 1 (doesn't need mask)
texunit 1 - layer 2's mask
texunit 2 - layer 2 (use interpolate to blend using prev alpha map)
-->create new render pass here
texunit 3 - layer 3's mask
texunit 4 - layer 3 (use interpolate to blend using prev alpha map)

I thought I needed to have the mask and the texture grouped in the same multi-texturing pass, so that's why I broke it up the way I did. Given this, on the second pass, the mask would reside in texunit 0, however, rendering the mask uses GL_PREVIOUS for one of the sources. Is this something I need to write code to figure out.. I was thinking I could rearrange the masks and textures if the mask falls at texunit0, but wasn't sure.

Thanks again for all of the help.

Share this post


Link to post
Share on other sites
Alright, so I've been trying to get this stuff to work without success. I hate to do it.. but does anyone by any chance have some sample application I can look at.. this is driving me crazy!

Share this post


Link to post
Share on other sites
Nevermind, I finally got it. It is not quite how I want it though. I wanted to use a single channel texture for the alpha map. I set the texture format to be GL_ALPHA, however, that does not work. I need to use a 32-bit RGBA texture for the mask.. not sure why though. Shouldn't the texture of the form GL_ALPHA get the job done for me?

Share this post


Link to post
Share on other sites
Alright, so the next problem i'm trying to tackle is this. I was under the impression that on each render pass, I could render more than one texture layer. I'm seeing now, that I can only render more than one layer on the first render pass. On subsequent passes, each texture layer overwrites the alpha channel, therefore, when I blend each pass, the alpha information is only in the last layer rendered which is no good. Are there any nice solutions to this problem? Or am I stuck using a full pass for each remaining texture layer after the first pass is complete?

Thanks, and I know I've been posting a lot, but I'm just trying to get this stuff working nice.

Share this post


Link to post
Share on other sites
Quote:
Original post by pammatt
texunit 0 - layer 1 (doesn't need mask)
texunit 1 - layer 2's mask
texunit 2 - layer 2 (use interpolate to blend using prev alpha map)
-->create new render pass here
texunit 3 - layer 3's mask
texunit 4 - layer 3 (use interpolate to blend using prev alpha map)

Right. For the new render passes, you can switch mask and color (though it's not needed, it's just a thought in case it fits better your memory scheme, class management or whatever).

Quote:
Original post by pammatt
I set the texture format to be GL_ALPHA, however, that does not work. I need to use a 32-bit RGBA texture for the mask.. not sure why though. Shouldn't the texture of the form GL_ALPHA get the job done for me?

Yes it should. However, it is sometimes a bit dodgy to get it working. From memory alignment to buggy drivers, there are lots of issues with alpha masking. Anyway you SHOULD be able to make it working. May I ask which card/driver/OS combo you have, and which parameters you send to glTexImage2D (or whatever texture uploading function you use) ?

Quote:
Original post by pammatt
Alright, so the next problem i'm trying to tackle is this. I was under the impression that on each render pass, I could render more than one texture layer. I'm seeing now, that I can only render more than one layer on the first render pass.

Right. AFAIR that's exactly what I mentioned in my first reply to this thread.

Quote:
Original post by pammatt
Are there any nice solutions to this problem? Or am I stuck using a full pass for each remaining texture layer after the first pass is complete?

Even if you can/want/need to deal with multi-path rendering (don't mistake with "multipass"), I don't think you can benefit register combiners, fragment shaders, fragment programs or-the-like. It's a blending issue, and as far as blending programs do not exist, you're stuck to multipass the way you describe.
However, if some layers have 1-bit non-filtered alpha channel (cookie-cutter like) then you can play with them sometimes. It's a bit tricky and not flexible at all though.

Share this post


Link to post
Share on other sites
I forgot to post last night. But I finally got everything working how I want it. I can blend as many texture layers as the user wants and they all blend very nicely together. I still haven't fixed the GL_ALPHA problem yet though.

My system is a Dell Inspiron 8600, GeforceFX 5200 Go, and the 4586 nvidia (well dell's nvidia) drivers.

Btw, here is a screenshot of what I have so far. Obviously, it looks like a mess because I am just using randomly generated alpha maps. One of the next stages of my planned work is to incorporate texture painting in my in progress editor. Well, actually lighting is one of the next steps.

Screenshot: http://mysafari.mine.nu:1224/terrain.jpg

Anyways, thanks again for all of the assistance.

Share this post


Link to post
Share on other sites
if u use glsl (which the GeforceFX 5200 does) u can access 16 texture in one pass, not to mention no need to fart around with this

// texunit 1 - layer 2's mask
glActiveTextureARB(GL_TEXTURE1_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
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_COMBINE_ALPHA_ARB, GL_REPLACE);
...
...

just use tex0.rgb * tex1.a + tex ....

Share this post


Link to post
Share on other sites
Unfortunately, glsl support is not spreaded enough actually to rely on this extension. Moreover, he stated explicitly that he didn't want to play with fancy extensions. However, it's true that it's a much more powerful mechanism ! *dang*

Share this post


Link to post
Share on other sites
I will probably add a pixel shader version later on down the line as more of an optimization technique. I do not want to have to rely on pixel shaders to be the only mechanism by which it worked.

Share this post


Link to post
Share on other sites

This topic is 4771 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this