Skip to content

Wrath Shading

fallenoak edited this page Nov 26, 2016 · 51 revisions

Area Lights

Exterior lighting in WotLK is driven by something known as 'area lights'. These lights are defined by entries in Light.dbc, and are selected by the client based on proximity to the lights' position. Note that later versions of WoW also make use of something called 'zone lights'. WotLK does not make use of zone lights.

Area lights effectively act like spheres, with a center point (the light's position), and two radii: an inner radius (aka falloffStart), and an outer radius (aka falloffEnd).

When the camera position is in the inner radius of an area light, that light is the exclusive source for area lighting values. Occasionally, a camera position may be in the inner radius of two lights. TODO: Determine what, exactly, the client does in this case. Theory: the client opts to use only the closest area light of the set of area lights that the camera position is within the inner radius of.

When the camera position is in the outer radius of two or more lights, a blending factor is used to combine the values of all contributing lights. TODO: Determine how the blending logic works; determine if more than two lights can be blended together.

When the camera position does not fall within the radius of any light, a default area light entry is used. This is the first light entry in Light.dbc. TODO: Confirm the use of the default; determine if default light is also used when no inner radius light is within range, but an outer radius light is within range.

Area light data is stored in other DBCs: static values are stored in LightParams.dbc, lerped color values are stored in LightIntBand.dbc, and lerped floating point values are stored in LightFloatBand.dbc.

Day Progression

The colors and values for area lights are linearly interpolated using a factor based on the time of day in half minutes. There are 2880 half minutes in a day. Half minute 0 is midnight, as is half minute 2880.

Note that the values in LightIntBand.dbc and LightFloatBand.dbc often are sparse; that is, the number of 'stops' on the gradient being interpolated might be as few as 2. TODO: Are there ever entries with single stops?

Day progression is offset to match server time, rather than following the time of day on the local computer.

Fog Shading

The following information was partially determined by reversing the client, and its accuracy has been checked against the actual WotLK client.

Fog Uniforms

In the WotLK client, when using D3D9 mode, fog is computed using two uniforms:

  • fogParams - a vec4 on the vertex shader
  • fogColor - a vec4 on the pixel shader

fogParams is broken down like so:

fogParams.x = -(1.0 / (fogEnd - fogStart));
fogParams.y = (1.0 / (fogEnd - fogStart)) * fogEnd;
fogParams.z = <unknown; often 1.0; fed to pow() in VS, so maybe for special effects / weather>;
fogParams.w = <likely unused; often 0.0>;

The values for fogEnd and fogStart come from area lights. Area lights are the lighting values and colors found in Light.dbc, LightParams.dbc, LightIntBand.dbc, and LightFloatBand.dbc.

  • fogEnd is found in LightFloatBand.dbc
  • fogScalar is found in LightFloatBand.dbc
  • fogStart is fogEnd * fogScalar

Note that fogScalar can be negative. Indeed, it often is negative in the LightFloatBand.dbc entries used by the WotLK client. Negative fogScalar values seem to increase the rate the fog factor increases toward the end of the fog range.

For details on how the DBC values backing fogEnd and fogScalar are read, see the area lights section above.

fogColor is broken down like so:

fogColor.r;
fogColor.g;
fogColor.b;
fogColor.a;

The value of fogColor is found in LightIntBand.dbc. See the area lights section above for more details.

Fog Vertex Shading

In WotLK, the vertex shader is responsible for computing the fog factor, a value between 0.0 and 1.0 representing the amount of fog that should be added to the final color in the pixel shader.

The fog vertex shading logic looks like this:

// Distance between vertex and camera
float cameraDistance = length(modelViewMatrix * vec4(position, 1.0));

float f1 = (cameraDistance * fogParams.x) + fogParams.y;
float f2 = max(f1, 0.0);
float f3 = pow(f2, fogParams.z);
float f4 = min(f3, 1.0);

float fogFactor = 1.0 - f4;

Fog Pixel Shading

In WotLK, the pixel shader is responsible for mixing the fog color with the shaded pixel color. It does so by using the fog factor computed in the vertex shader.

The fog pixel shading logic looks like this:

result.rgb = mix(result.rgb, fogColor.rgb, fogFactor);

M2 Shading

M2 Vertex Constant Buffer Layout

  • c6 - a vec4 containing something related to texture UV transforms
  • c7 - a vec4 containing something related to texture UV transforms
  • c10 - a vec4 containing sunDiffuse
  • c11 - a vec4 containing sunAmbient
  • c12 - a vec4 containing sunDir
  • c28 - unknown (involved in lighting) - c28.w is texture weight from the texture weight animation tracks
  • c29 - a vec4 that, at least in some cases, comes out of the color animation tracks in the M2
  • c30 - a vec4 containing fogParams (see fog section)

M2 Pixel Constant Buffer Layout

  • c2 - a vec4 containing fogColor (see fog section)

M2 Uniforms

  • sunDir - a vec4 sent to the vertex shader; can be overridden, for ex: s_interiorSunDir
  • sunAmbient - a vec4 sent to the vertex shader; can be overridden, for ex: MODD.color or MOHD.color
  • sunDiffuse - a vec4 sent to the vertex shader; can be overridden, for ex: MODD.color

M2 Vertex Shading

uniform vec3 lightDiffuse;  // c10
uniform vec3 lightAmbient;  // c11
uniform vec3 lightDir;      // c12

uniform vec4 animatedColor; // c29 ?? Is there more in here?
uniform vec4 fogParams;     // c30

vec4 light;

if (useLighting) {
  vec3 objectNormal = normalize(modelMatrix * vec4(normal, 0.0)).xyz;
  float lightFactor = saturate(dot(-lightDir, objectNormal));
  light.rgb = saturate((lightFactor * lightDiffuse) + lightAmbient);
} else {
  light.rgb = vec3(1.0);
}

// TODO:
// c28??
// light = saturate((light * c28) + c29)

light = saturate((light * c28) + animatedColor);

colors[0] = light;

M2 Pixel Shading

// colors[0] = output of vertex shader (see above)
// fog.rgb = fog color (see fog section)
// fogFactor = fog factor (see fog section)

vec4 result;

vec4 sampled0 = texture2D(textures[0], coords[0]);
vec4 color0 = sampled0.rgb * colors[0].rgb;

result.rgb = mix(color0.rgb, fog.rgb, fogFactor);
result.a = colors[0].a;