Advertisement

multitexturing (more advanced than simple mt... i think...)

Started by September 16, 2002 03:26 PM
12 comments, last by Crispy 22 years, 5 months ago
Hi, I need to do the following: 1) map a texture to a surface 2) map a detail map on that texture 3) map a third texture on the detailmapped texture Can this be done in one pass (sure it can!)? Here''s some code:
  
  //build the detailmapped surface

  glActiveTextureARB(GL_TEXTURE0_ARB);
  glEnable(GL_TEXTURE_2D);
  Bind(pTexID);  //glBindTexture()


  glActiveTextureARB(GL_TEXTURE1_ARB);
  glEnable(GL_TEXTURE_2D);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
  glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2);
  Bind(pDetailTexID);

  glMatrixMode(GL_TEXTURE);
  glLoadIdentity();
  glScalef(pDetailLevel, pDetailLevel, 1);
  glMatrixMode(GL_MODELVIEW);

  //add the final texture

  glClientActiveTextureARB(GL_TEXTURE2_ARB);
  glEnable(GL_TEXTURE_2D);
  Bind(ShadowMapID);
  
If I compile and run the above code, I get no detailmapped subsurface and the shadow is mapped at pDetailLevel scale. Obviously the final texture messes up the detail map. If I first set up GL_TEXTURE2_ARB, I get a neat detailmapped surface, but no shadow map. Am I trying to do the impossible here (which I don''t think) or am I writing the code just plain wrong? And another question: why does the program crash when I increment the base texture indexes (GL_TEXTUREx_ARB) for the original texture and the detail map (as in glActiveTextureARB(GL_TEXTURE0_ARB + SomeIndex); )? Thanks, Crispy
"Literally, it means that Bob is everything you can think of, but not dead; i.e., Bob is a purple-spotted, yellow-striped bumblebee/dragon/pterodactyl hybrid with a voracious addiction to Twix candy bars, but not dead."- kSquared
A few questions that might help finding the answer ...

1. Why do you use glClientActiveTextureARB, instead of glActiveTextureARB, for TEXTURE2 ?

2. Do you intend the pDetailLevel factor to be applied to TEXTURE1 or to TEXTURE2 ?

3. When you set up the texture combiner for TEXTURE1, are you sure that the combiner is configured correctly ? I mean, if I were you I would call glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE) and things like that...
Advertisement
quote:
Original post by vincoof
1. Why do you use glClientActiveTextureARB, instead of glActiveTextureARB, for TEXTURE2 ?



It will produce a "memory could not be written" error on exit if I dont''t. I can''t explain it. Besides, I haven''t been able to find a good clear wording of the difference(s) between the two...

quote:

2. Do you intend the pDetailLevel factor to be applied to TEXTURE1 or to TEXTURE2 ?



The second one, the detail map (that''s GL_TEXTURE1)

quote:

3. When you set up the texture combiner for TEXTURE1, are you sure that the combiner is configured correctly ? I mean, if I were you I would call glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE) and things like that...



Okay you got me there - could you please elaborate. As of now I''m not doing any setting up/configuring with the combiner. Then again, I''m a bit unclear on the subject - hence my program''s not working properly

Crispy

"Literally, it means that Bob is everything you can think of, but not dead; i.e., Bob is a purple-spotted, yellow-striped bumblebee/dragon/pterodactyl hybrid with a voracious addiction to Twix candy bars, but not dead."- kSquared
quote:
It will produce a "memory could not be written" error on exit if I dont''t. I can''t explain it. Besides, I haven''t been able to find a good clear wording of the difference(s) between the two...

glClientActiveTextureARB is designed for vertex arrays.
When you call glClientActiveTextureARB, not only you activate the texture unit on the server side, but you also activate the texture unit on the client side. That is, you can call glTexCoordPointer for the current activated texture unit.
Are you using vertex arrays ?

BTW, what is your graphics card ?


quote:
Okay you got me there - could you please elaborate. As of now I''m not doing any setting up/configuring with the combiner. Then again, I''m a bit unclear on the subject - hence my program''s not working properly

You may have to be sure that the texture combiner is initialized correctly.
What effect do you want on this texture unit ?
It seems like you want :
output_RGB = 2*(previous_RGB * texture1_RGB)

I assume that your detail texture is a greyscale map where grey means "don''t modify", where black means "darken" and where white means "enlight", right ?
In that case, I recommend the following :
output_RGB = previous_RGB + texture1_RGB - 0.5

The equation you''re using is the one from gametutorials which is pretty good, but lacks detail on dark textures.

To use the new equation, write :
glActiveTextureARB(GL_TEXTURE1_ARB);glEnable(GL_TEXTURE_2D);glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD_SIGNED_EXT);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);Bind(pDetailTexID); 


BTW if you want your 3rd texture to be a detail map too, you should also set up the texture environment.
quote:
Original post by vincoof
glClientActiveTextureARB is designed for vertex arrays.
...
Are you using vertex arrays ?



Aha! Ay, there''s the rub. I am using vertex arrays. However, switching the glActiveTextureARB() to glClientActiveTextureARB() will give me a neat white surface...

quote:

BTW, what is your graphics card ?



RivaTNT 2 (32 Mb) - an oldie. Planning to upgrade soon when GF4Ti prices drop (they should when ATI comes out with its new "monster" ;p). I actually though of using VAR, but (grin) - it''s not supported by my gpu...

quote:

I assume that your detail texture is a greyscale map where grey means "don''t modify", where black means "darken" and where white means "enlight", right ?



Confused. What do you mean by your definition of a detail map. It is a grayscale bitmap, but what I mean is that you scale a complex (detailed) texture - the detail map - down and map it on the real texture, giving it a lot of detail (jagged edges and stuff) close up. Check out the last heightmap tutorial on gametutorials for a good example.

quote:

You may have to be sure that the texture combiner is initialized correctly.
What effect do you want on this texture unit ?
It seems like you want :
output_RGB = 2*(previous_RGB * texture1_RGB)

In that case, I recommend the following :
output_RGB = previous_RGB + texture1_RGB - 0.5



I already achieve the desired effect with the detail mapping - what doesn''t work is applying the third texture on top of it all: it is either scaled down to the detail map''s scale factor and removes the detail map altogether, or doesn''t appear at all...

quote:

The equation you''re using is the one from gametutorials ...



Commendable

quote:

BTW if you want your 3rd texture to be a detail map too ...



Nope, the third one is supposed to be NOT detail map(ped). I guess it would be better if I actually said what I''m trying to do: I''ve created a planet, a texturemapped sphere using vertex arrays (blazing fast, I might add - yum ). I need to detail map the surface of the planet so as to give it a lot better detail level close up, but I also need to add a terminator to the planet (the line where the back side and front side meet; where the shade and the lit side merge). So I figured the easiest way to do this would be to detail map the surface texture (TEXTURE0 and TEXTURE1), then add the shadow map (TEXTURE2). The result is described above...

Crispy
"Literally, it means that Bob is everything you can think of, but not dead; i.e., Bob is a purple-spotted, yellow-striped bumblebee/dragon/pterodactyl hybrid with a voracious addiction to Twix candy bars, but not dead."- kSquared
Ok, so there you are using :
- TEXTURE0 as a color texture (some kind of blue texture for Earth, red texture for Mars, grey texture for moon... or even your own planet)
- TEXTURE1 as detail texture (greyscale image that adds little wrinklets and stuff like)
- TEXTURE2 as a shadow map (greyscale image that shades the planet because OpenGL lighting isn''t enough for your case)

In the multitexture pipeline, you would like to have :
incoming color = color from glColor or from OpenGL lighting equations
output of texture unit 0 = texture color from texture lookup 0 (planet color), probably modulated by the incoming color
output of texture unit 1 = multiply previous texture result (planet color) by texture color from texture lookup 1 (detail map), and scaled by two
output of texture unit 2 = modulate previous texture result (planet color with detail) by texture color from texture lookup 2 (shadowmap)

First of all, you may check how many texture units are supported by your graphics card.
Call glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &nb_texture_units);
Your card supports at most 2 texture units in hardware. Though, maybe you can use a third texture unit if the driver allow so.

Secondly, you may set up texture environments for all your texture units. That''s the best way to achieve the desired result without side-effects.

  //build the detailmapped surfaceglActiveTextureARB(GL_TEXTURE0_ARB);glEnable(GL_TEXTURE_2D);glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE /*or GL_MODULATE*/); // NEWBind(pTexID);  //glBindTexture()glActiveTextureARB(GL_TEXTURE1_ARB);glEnable(GL_TEXTURE_2D);glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); // NEWglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); // NEWglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); // NEWglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS); // NEWglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR); // NEWglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2);Bind(pDetailTexID);glMatrixMode(GL_TEXTURE);glLoadIdentity();glScalef(pDetailLevel, pDetailLevel, 1);glMatrixMode(GL_MODELVIEW);//add the final textureglClientActiveTextureARB(GL_TEXTURE2_ARB);glEnable(GL_TEXTURE_2D);glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // NEWBind(ShadowMapID);  




Thirdly, you use vertex arrays but I don''t get how you define texture coordinates arrays.
Do you use a different texture coordinate array for every texture unit, or would you like to "share" the texture coordinate array for all units ?
I mean, when/where do you call glTexCoordPointer ? Do you call it for each texture unit ? Do you call it once only ?


Finally, when you write :
quote:
However, switching the glActiveTextureARB() to glClientActiveTextureARB() will give me a neat white surface...

you probably mean that calling glClientActiveTextureARB does NOT give you the desired effect, but calling glActiveTextureARB does give it to you. Is that right ?
Also, what texture unit are you talking about ? TEXTURE2 as shown in your sample code ?
Advertisement
Your problem is most likely your GPU! You got a TNT2 and if I remember right, then TNT is for TwinTextureunits. So you only got two TUs, but you try to use three at once...


Yesterday we still stood at the verge of the abyss,
today we''re a step onward!
Yesterday we still stood at the verge of the abyss,today we're a step onward! Don't klick me!!!
quote:
Original post by Vaporisator
Your problem is most likely your GPU! You got a TNT2 and if I remember right, then TNT is for TwinTextureunits. So you only got two TUs, but you try to use three at once...

Yep (actually TwiN Texel,.... but what''s in a name ),....

-Crawl
--------<a href="http://www.icarusindie.com/rpc>Reverse Pop Culture
Well guys I know what you mean, but please keep in mind that hardware is not the real barrier.
It is the driver.

If NVIDIA wants, he can limit you to use two texture units on a GF4, and if he wants ha can allow you 8 texture units on a GF2, without modding the chips.

That''s why I asked to check it by calling glGetIntegerv with GL_MAX_TEXTURE_UNITS_ARB
quote:
Original post by vincoof
First of all, you may check how many texture units are supported by your graphics card.



As already stated by you, Crawl and Vaporisator, the number is "2". Furthermore: I found out that GF2MX400 also supports only 2 TU''s... I find it rather queer...

quote:

Secondly, you may set up texture environments for all your texture units. That''s the best way to achieve the desired result without side-effects.



Okay, a few explanatory questions here: going through your code line by line - do I get them right?

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);

Start combining textures for the currently selected texture

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);

Combine the color components by using modulation (does GL_MODULATE take the average of the two, GL_REPLACE replace the original value, GL_BLEND use the blending equations specified by the last call to glBlendFunc() and GL_DECAL - uhm... what does that do - I remember reading someplace that it''s the outdated version of GL_REPLACE (compatible with older gl versions)?)

glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);

Select the rgb components of the active texture

glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);

Is this the line that tells OpenGL to multiply the active texture with (what?) ?

glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS);

Does this tell OpenGL to modulate the previously select texture with the current one?

glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);

What are multiplied this time?

glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2);

This obviously scales the whole thing


Where do you refer to for this information. I searched the web, but came up empty - there''s no explanation anywhere (not on nVidia''s site or at OpenGL.org) as to what these constants mean... I would be more than glad to delve into them myself and leave everyone else at peace

quote:

Thirdly, you use vertex arrays but I don''t get how you define texture coordinates arrays.
Do you use a different texture coordinate array for every texture unit, or would you like to "share" the texture coordinate array for all units ?
I mean, when/where do you call glTexCoordPointer ? Do you call it for each texture unit ? Do you call it once only ?



Here''s my drawing function:

  for(Index = 0; Index < pNumTextures; Index++)  {  glClientActiveTextureARB(GL_TEXTURE0_ARB + Index);  glTexCoordPointer(2, GL_FLOAT, sizeof(TVector2f), &TexCoords[0]);  glNormalPointer(GL_FLOAT, 0, &Normals[0]);  glEnableClientState(GL_VERTEX_ARRAY);  glEnableClientState(GL_TEXTURE_COORD_ARRAY);  glEnableClientState(GL_NORMAL_ARRAY);  }glVertexPointer(3, GL_FLOAT, sizeof(TVector3f), &Vertices[0]);glDrawArrays(GL_TRIANGLES, 0, NumVertices);  


As can be seen I''m calling them explicitly for each texture unit - I personally think that it''s too much, but it won''t draw correctly if I only call the glEnable..()''s for each TU and then specify the normal, tex and vertex pointers only once (even though they''re the same for all of the textures because I''m mapping a sphere - a little sidenote here, though: I need to map the shadow on the planet independently of the texture coordinates as it has to stay at the same place while the planet revolves around its axis - my texcoords are prebuilt, so is there an easy way to make the necessary adjustments to the coordinates?)

quote:

you probably mean that calling glClientActiveTextureARB does NOT give you the desired effect, but calling glActiveTextureARB does give it to you. Is that right ?
Also, what texture unit are you talking about ? TEXTURE2 as shown in your sample code ?



"Yes" regarding the first sentence. I''m talking about TEXTURE0 and TEXTURE1 in the original post - these textures will be used with vertex arrays later on. They''re actvated by calling glActiveTextureARB() without the Client part which doesn''t seem to follow this logic...

Anyway, thanks for the help guys - I would never have thought of the texture unit count for my gpu all by myself. I took it for granted that since OpenGL defines 32 (was it 32?) GL_TEXTUREi(_ARB) textures, that my gpu would support at least 4 or 8 - how much more naïve can you get...

Crispy
"Literally, it means that Bob is everything you can think of, but not dead; i.e., Bob is a purple-spotted, yellow-striped bumblebee/dragon/pterodactyl hybrid with a voracious addiction to Twix candy bars, but not dead."- kSquared

This topic is closed to new replies.

Advertisement