General question about light maps

I have a general question on the use of light maps. I recently wrote a demo for myself that was using specular light map (a texture) along with the diffuse light texture (base colors).
Both light/color sources were merged with the ambient light inside the fragment shader. So that part works fine.
My question is more about the light map usage. I looked inside a packed resource containing DDS light maps, and there was a lot of them in there. Do you create those for every model and every facade of the model? I saw light maps for buildings rooftops, walls, ground tiles, flower beds, etc.
And are those light maps the same as the specular light maps, or is that yet another category of textures?
When I wrote my demo code I learned about the texture unit constant, how many texture units can a model have?
I’d appreciate a detailed explanation, I’d like to better understand how all these light attributes are used together.


Typically light map is a term that is usually used to describe textures that store information about light arriving at a surface. Quite often only indirect light (light that has bounced off at least one surface in the scene) is stored because that is the part that is computationally more expensive to calculate. As such every visible surface must have a unique part of a texture assigned - you cannot share lightmaps between instances of the same geometry because lighting conditions can and usually are very different for each instance. Therefore lightmaps otften also make use of a separate set of texture coordinates that ensures there is no overlap (even within a single geometry).
To avoid having to access a large number of textures when rendering with the lightmaps many of them can be packed into a smaller number of textures. A renderer has to bind the correct lightmap for each geometry before drawing it, but in the corresponding shader you only need to access one lightmap.

I’m not exactly sure what you call a specular light map. In general you can store all kinds of things in textures, some common examples are: base color, roughness, metallicity (these first are common parameters for physically based shading models), shading normal, ambient occlusion, displacement (for parallax mapping or displacement mapping), noise (a case of using a texture as a lookup table for an expensive to compute function), etc.
The number of textures accessible by a shader stage is given by the value of GL_MAX_TEXTURE_IMAGE_UNITS and the limit for a program object by GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS and varies by hardware.

How the values from various texture interact with the light from the light sources in your scene of course depends on what you store in those textures. The calculations are described by a “shading model”, at it’s core that is a function that takes as input a surface normal, a vector towards a light source, a vector towards the viewer, and a set of parameters that describe properties of the surface and light source and produces the amount of light reflected towards the viewer. Those parameters that are not constant across the surface are good candidates to store in textures.

Thank you for sharing this info, this is useful. I added code to my demo to print those two constants you mentioned, here is the output:

max texture image units: 32
max combined texture image units: 192

When I’m loading textures to be used by the same model (all textures available as uniforms in shader code) I need to specify a different texture unit for each one, for example:

val diffuseId = loadTexture(GL13.GL_TEXTURE0, "data/image/texture/container2.png")
val specularId = loadTexture(GL13.GL_TEXTURE1, "data/image/texture/container2Specular.png")

I can see that GL13 constants for GL_TEXTUREn are defined from 0 to 31 (32 total), which matches max texture image units value (32). I’m not sure why documentation lists max combined texture image units as the upper limit (192 on my card), but maybe that’s related to the actual implementation.

Anyway thank you for the detailed info, I’ll read up on that.


You can specify texture units with GL_TEXTURE0 + textureUnit, the pre-defined constants are not really necessary - the values are guaranteed to be sequential.