quake3 shader language

This is sample quake3 shader description:

textures/gothic_block/blocks18cgeomtrnx
{

    {
  map textures/sfx/fireswirl2blue.tga
            tcMod stretch sin .8 0.3 0 9.7
            tcmod rotate 333
      rgbGen identity

}
{
map textures/gothic_block/blocks18cgeomtrn2.tga
blendFunc blend
tcmod rotate 30
tcMod stretch sin .8 0.2 0 .2
rgbGen identity
}
{
map textures/gothic_block/blocks18cgeomtrn2.tga
blendFunc blend
tcmod rotate 20
tcMod stretch sin .8 0.2 0 .1
rgbGen identity
}
{
map textures/gothic_block/blocks18cgeomtrnx.tga
blendFunc blend
rgbGen identity
}
{
map $lightmap
blendFunc GL_DST_COLOR GL_ONE_MINUS_DST_ALPHA
rgbGen identity
}
}

As you can see there are 5 pairs of inner brackets {…}.

Does it mean 5 different textures are required to draw mesh with that shader?
I just can’t believe it does. On cards like GF2 with 2 texture units this would require 3 passses and quake3 is still very fast.
Looks like many othre q3 shaders have also 4/5 textures to apply.

Tell me please if they really apply so many textures to one mesh.
Thx.

Quake3 looks very good, but it doesn’t look to me like it had 4-5 textures applied to walls, floors etc.

If you look at that shader you should see that it actually uses only 4 different textures. But for this particular shader to actually appear correct, it would at least require 4 passes on a GF2. Only the first 2 stages could be composited with multitexturing, since the GF2 only has 2 stages, and the blending of stages 3, 4 and 5 of this shader is not associative.

And to liolio, you are correct, for most of Quake3, they rarely used more than 3 stages in the shaders. But there are special shaders which were usually applied to small meshes which did routinely use more than 3 stages. The little animated markers under weapon spawn points for instance.

[This message has been edited by DFrey (edited 09-12-2002).]

Thanks for your answer DFrey.

I have another questions:]

  1. First could you explain a bit more why it’s not possible to use multitexturing for 3-5 stages?

  2. I looked into quake3 shader code and almost couldn’t find shader with 2 stages, which could be done in one multitexturing pass. So it does 2 passes at least for every mesh and is soo fast?
    Since not a long time ago (before looked into quake3 shaders) i always thought quake3 uses 90% 1 multitexture pass for base texture and lightmap (instead of some reflecting walls, buttons etc…). And still I don’t see even 3 maps on most of quake3 levels’ walls. hmmm…?

  3. And one more thing…

textures/gothic_block/blocks17_ow
{

    {
  map textures/sfx/firegorre.tga
            tcmod scroll 0 1
            tcMod turb 0 .25 0 5.6
            tcmod scale 1.5 1.5
            blendFunc GL_ONE GL_ZERO
            rgbGen identity

}

{
map textures/gothic_block/blocks17_ow.tga
blendFunc blend
rgbGen identity
}
{
map $lightmap
blendFunc filter
rgbGen identity
}
}

This one looks less complicated (only 3 stages).
Could you please give me a little pseudocode of how you blend/multitexture mesh with shader like this?

I believe you can answer my questions

To answer somewhat:

  1. This is card-subjective. It is, for example, possible to use a single pass of multitexturing to do up to 4 stages on a GeForce3/4 because those cards have 4 texture units. As DFrey said, on a GeForce2 you couldn’t as it only has two texture units, so you’d probably do the first two stages multitextured then in another pass (or two), blend in the remaining stages.

  2. Two passes isn’t necessarily super-slow, it depends on how many polygons you have to re-draw and other factors.

  3. Erm… perhaps (making this up as I go)

  • Draw Mesh with firegorre.tga (at the appropriate stage of animation, as I believe thats what the scroll/turb/scale variables are)
  • set BlendFunc to ‘blend’ (whatever that is in Q3 terms, possibly SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
  • Draw mesh with blocks17_ow.tga
  • set BlendFunc to ‘filter’ (again, whatever that is in Q3 terms)
  • Draw mesh with it’s lightmap (I’m guessing that $lightmap tells the engine to look up the texture from the surface in the bsp file).

-Mezz

yes quake3 on some objects does 5/6 passes. remember for each passn the objects geometry remains the same thus that only needs to be setup the first time + then its locked.
on cards that have multitexture passes can be combined together requiring less passes BUT i believe q3 only does this in the simplest examples (less chance of ballsups) eg lightmap * pass0

also the order of the passes is important (blending != multipass) thus its not always possible to compress passes.
werent some ppl complaining about this in opengl2? ‘deal with it!’

Thank you!

About those 5/6 passes:
What is the better way of rendering say 5-passes meshes on 2-unit 3d card, where 2 first passes can be done together but none of 3, 4, 5 can be…?

(assume every surface is like description above)

for (each surface)
{
render_multitextured_passes_12();
render_pass_3();
render_pass_4();
render_pass_5();
}

or something like that:

for (each surface)
render_multitextured_passes_12();

for (each surface)
render_pass_3();

for (each surface)
render_pass_4();

for (each surface)
render_pass_5();

You should always keep the number of state chages to a minimum. That is, you should draw as much as you can before changing states. So I would go for #2.

I second what Bob said, although remember that it is unlikely that every surface will have the same pass setup (different animations, different textures etc.) so you might want to look into sorting shaders into a ‘shader tree’ and traverse that rendering all surfaces with a particular shader before changing the state.
There was a good article on this somewhere, delphi3d.net I think under the articles section, it’s called ‘state management’ I think.

-Mezz

ok… after a while and reading an article pointed by Mezz: http://delphi3d.net/articles/viewarticle.php?article=stateman.htm

…i have another question as this article doesn’t say how to deal with multipass rendering at all

How to determine optimal order of shaders so that number of glBindTexture() (only this as it’s costs at most) is minimized?

Example…

We have shaders like these
number_of_shader: texture0 texture1 texture2

0: A A C
1: B B A
2: C A C
3: D C C
4: E A C

The solution (minimum rebinding number) is:

0: A A C
1: C A C
2: E A C
3: D C C
4: B B A

on 1st unit we need 5, on 2nd 3 and on 3rd 2 calls to glBindTexture(), thus 10 times…

as you can see we can’t simply sort by 1st, 2nd or 3rd texture…

any suggestions for an algorithm that solves this an easy way?

thx again for any help