Doom3 shading questions

I was wondering how doom3 does the shading. I looked at the screenshots and it seems like the patches are always smooth shaded while brushes are flat shaded? What about meshes? Is the shading variable for both meshes and brushes or only for meshes? By variable I mean based on the angle between faces, too sharp the face is flat shaded, not sharp edge the face is smooth shaded. In my tests, the variable shading works the best. The bumps nicely hide the mesh trinagulation lines we’ve seen while smooth shading. Not sure if I implement variable shading on brushes. Last time I smooth shaded the brushes the tangent basis got skewed too much and controlling this per brush or collection of them might get too tiresome. What do you think?

I looked at the screenshots and it seems like the patches are always smooth shaded while brushes are flat shaded?
That’s the idea behind patches. You’ll also note, that there is no more dynamic sub division on them.

What about meshes?
I think the models (or meshes) are generated in max or maya. Thus normals will be exported. So the shading depends on how you build the model. You can use curves, patches (whatever they are called there) or simple brushes to make the model look smooth on some parts while you can have hard edges on other parts. I don’t think there’s somethink like “variable shading”, as you describe it, going on.

Hope you don’t mind me hijacking your thread. :slight_smile:

Does Doom 3 use GL2 shaders at all or is it just ARB_vp, ARBfp, NVvp, NVfp?

I know that in the .plan file he says he experiments with them (a very old .plan)

Originally posted by V-man:
[b]Hope you don’t mind me hijacking your thread. :slight_smile:

Does Doom 3 use GL2 shaders at all or is it just ARB_vp, ARBfp, NVvp, NVfp?

I know that in the .plan file he says he experiments with them (a very old .plan)[/b]
Nope, no GL2 shaders. But there are some cvars for CG shaders. Didn’t figure out if they’re really supported.

I think the low poly chars are using bumps from high poly meshes and think they’re smooth shaded, ie. the tangent basis is calculated per vertex. I’m not so sure about non-char meshes like doors and door frames. It’s hard to tell whether the effect is light attenuation, whether it’s smooth shaded or flat or inbetween ie. flat and smooth on some parts. It almost looks like flat but I’ve noticed a light gradient across a face which could be attributed to smooth shading with variable edge hardness because I still see corner edges in the door frame.

No problem with hijacking :slight_smile: Carmack said he’s going to be using glsl from now on. Only asm shaders in doom3 to my knowledge (including gf2 reg.cmbs and/or tex.env.combine dot3).

I think geometry is smooth shaded, if the vertex is shared by two faces and flat shaded for two touching faces with different vertices. The algorithm for calculating tangents and binormals should automatically smooth the vectors, if they are shared by more than one index (speaking of indexed vertices) by summing the calculated vectors up and normalizing them at the end. It doesn’t really matter, if the geometry comes from model or map data.

PS: I’m sorry if this is not a very clear explanation but it’s pretty late already :slight_smile:

hope you don’t mind another hijacking :stuck_out_tongue: do you know how JC do dynamic lighting in DOOM3? I think all those lights are project texture, there are places that have one, two or more lights there. does he write different shaders for all these conditions, or do it in other way, e.g. multipass?

Originally posted by Nil_z:
hope you don’t mind another hijacking :stuck_out_tongue: do you know how JC do dynamic lighting in DOOM3? I think all those lights are project texture, there are places that have one, two or more lights there. does he write different shaders for all these conditions, or do it in other way, e.g. multipass?
Multipass, as it is required by the shadowing.

Originally posted by tfpsly:
[quote]Originally posted by Nil_z:
hope you don’t mind another hijacking :stuck_out_tongue: do you know how JC do dynamic lighting in DOOM3? I think all those lights are project texture, there are places that have one, two or more lights there. does he write different shaders for all these conditions, or do it in other way, e.g. multipass?
Multipass, as it is required by the shadowing.
[/QUOTE]can you explain some details? thank you

The way Doom3 works is, for each light :

  • Compute shadow volume (if the light casts shadows. Each light may have this flag set in the *.map files).
  • Display everything that is near the light and not in the shadow volume, hightlighed and add this into the framebuffer (using normal mapping and DOT3).
    There are a few projected light ; in which case you add a projected texture in the second step.

By the way, i even wonder why you make assumptions about doom3 shaders, since the text files are stored in the directory base/pak000.pk4 (open with winrar).
Just browse in the glprogs directory and you’ll see the nice ARB vertex programs and they seem well commented by their author…

regards… :wink:

thanks, nystep, those vp&fp programs are very good reference. but still I can’t find out how they handle project light in those programs, can you explain how it works? I have been wondering about how to do (multiple) dynamic project light in a game scene for some time, can’t figure out a good solution…

Check out http://www.ronfrazier.net/apparition/index.asp?appmain=research/per_pixel_lighting.html – a little outdated in that the code snippets are based on old-school NV_register_combiners, but the text should give you the general idea.

– Tom

Hi Nil_z,

but still I can’t find out how they handle project light in those programs, can you explain how it works? I have been wondering about how to do (multiple) dynamic project light in a game scene for some time, can’t figure out a good solution…
First you’re totally right to ask this because it’s much harder and interresting than just finding out some text files in an archive, and i’m really sorry if my previous post looked arrogant or whatever…
This being said, i had a look at the nv20_bumpAndLight.vp.
From the comment: “# TEX2 will be the 3D light texture” i understand that TEX2 is used as a volumetric spotlight (or whatever 3d light shape you wish) mask. It means that the projection light is already precalculated in a way. Later in the vertex program, you find the following part of code that generates the texture coordinate for this 3d-lookup-table:

texture 3 has three texgens

DP4 result.texcoord[3].x, vertex.position, program.env[6];
DP4 result.texcoord[3].y, vertex.position, program.env[7];
DP4 result.texcoord[3].w, vertex.position, program.env[8];

You’ll notice that the texture coordinate is a linear combinaison of the vertex position and a special 43 matrix stored in environement.
I’d guess this matrix is a scaling/rotating/translation matrix to put the light and orientate it correctly in the game. DP4 is really required because you can’t translate elseway, and it’s nice to put the light where you wish in the 3d world. The scaling is usefull to simulate a random varying light source, as so often used in the mars planet levels.
Thinking about it, you wouldn’t even need a big 3d-texture-lookup spotlight shape, one should test, but 16
16*16 could be enough thanks to the trilinear-filtering (trilinear filtering is required to have a correct interpolation on a 3d texture without mipmaps or am i mistaking?).
You should keep in mind that this shader is executed once per light. You can’t really do more lights per passes when you combine this to stencil shadowing (considering where the stencil test is done in the opengl pipeline), but if you don’t use stencil shadows, further optimisation is possible.
The vertex data seems also pretransformed when entering the shader (the homogenous divide isn’t done yet), and that’s what the OPTION ARB_position_invariant means. It’s a clever optimisation since you don’t have to transform your vertex at each pass, but it means that you probably have to use the CPU to transform them, since you can’t store pretransformed vertices in the GPU memory when the camera moves arround.

However, after watching this shader, i began to wonder why it was specific to nv20. Nothing here seems unrunable on ati cards, except maybe the ARB_position_invariant, but it’s also specified in the R200_interaction.vp.
The R200 codepath is slighly longer and more complex than this one. By watching more closelly, we can see that the spotlight calculation are not precalculated in a 3d-lookup-texture but are done in the shader, with the half-angle vector.

If you combine this with the fact that the nvidia cards up to geForceFX can do twice more depth-stencil writes when no color is written, there’s no wonder these boards perform so well in the benchmarks compared to ati, is it?
Or is it just that i’m ill today and that my fever gives me weird ideas… ???

regards,

Doom 3 does NOT use 3D textures at all. Each light can have a projected texture (or even multiple (will result in multiple passes)) and an attenuation texture. These two textures combined result in the spot/whatever light in the game. For spot lights, there is a simple attenuation texture, that eliminates the back projection of the projected texture. The 2D projected texture is sampled by the TXP instruction, which takes the s/q and t/q texture coordinates for sampling.

Uhh, and the vertex data is not “pretransformed”. It’s transformed after the vertex program execution. This is no optimization. It’s necessary for the other passes (the GUIs and so on) that don’t use the vertex program. The ARB_position_invariant option came with ATI, so nVidia had it later supported on request in their vertex_program_NV, IIRC.

You’ll see this wehen looking at the ARB vp/fp shaders. The NV20 shaders are not really a good example, since you don’t see what’s going on in the pixel pipeline.

Some of my thoughts about higher performance of nVidia in Doom3: X800 is a little modified version of the R3x0 chip against an almost new NV40 (i take this from the much better FP32 performance). Even the depth_clamp extension doesn’t bring any noticeable gain (must be activated by hand). Also nVidia is using shader replacement to optimize. ATI currrently not (correct me, if i’m wrong). Even if so, they’re known for, well, not the best drivers around.

Now, please close this thread :slight_smile:

Also nVidia is using shader replacement to optimize. ATI currrently not (correct me, if i’m wrong). Even if so, they’re known for, well, not the best drivers around.
They do now. And they even officaly promote it as “AI”(sic, wtf is AI in there?) Catalyst drivers.

thanks nystep, it is very kind of you to explain how those shaders work. so doom3 uses multipass for each light? i’ll think about how it works

Originally posted by Nil_z:
thanks nystep, it is very kind of you to explain how those shaders work. so doom3 uses multipass for each light? i’ll think about how it works
Doom 3 uses multiple passes per light for (i think) all the render paths [i]EXCEPT the ARB2 path, which everything can fit into one pass. The ARB2 path is using ARB_vertex_program and ARB_fragment_program.

-SirKnight

Originally posted by SirKnight:
[b] [quote]Originally posted by Nil_z:
thanks nystep, it is very kind of you to explain how those shaders work. so doom3 uses multipass for each light? i’ll think about how it works
Doom 3 uses multiple passes per light for (i think) all the render paths [i]EXCEPT the ARB2 path, which everything can fit into one pass. The ARB2 path is using ARB_vertex_program and ARB_fragment_program.

-SirKnight[/b][/QUOTE]The R200 path (GL_fragment_shader_ATI) can do it in one pass too. But only, if the texture matrices for the specular and diffuse maps are identity (so no rotation, scrolling, etc.). Else it does two passes with the same shader.

there are up to more than 4 project lights in DOOM3, some rooms have even more, can those be fitted into one pass? I am thinking of using additive blend for each light(in multipasses), but can’t figure out how those can be rendered in one pass, for the number of lights is not fixed.