I promised, so rendering a night-vision frame in Splinter Cell is the following:
In the first pass, only the light maps of the 3D world are rendered

- Code: Select all
vs.1.0 ; o** registers are output registers
dp4 oPos.x, v0, c2
dp4 oPos.y, v0, c3
dp4 oPos.z, v0, c4
dp4 oPos.w, v0, c5 ; v0: vertex position, c2-c5 are the columns or rows of the world*camera*projection matrix,
; so this is a transformation
mov r0, v0
mov oD0, c1 ; constant color (modulating factor), going into the pixel pipeline
mov oT0, v3
mov oT1, v4
mov oT2, v3
mov oT3, v3 ; texture coordinates coming from the vertex, only T0 and T1 are used in the pixel pipeline
mov oFog.x, c0 ; some fog, but fogging is disabled here
(I think the 'lighter' rendering is controlled by the c1 constant. OK, it's not ambient lighting, because it's not an additive component, but instead it controls the intensity of the light maps drawn in the 1st pass.)
Pixel pipeline is fixed function:
- Code: Select all
r0 = texture0 * diffuse ; r0 = lightmap0 * vertex color0 (coming through oD0 from the vertex shader)
r0 = texture1 * r0 ; r0 = r0 * lightmap1, r0 is the final color output
Texture0 is a 256*512 DXT1, so I'm not sure if it's a lightmap. Texture1 is smaller, 64*16, it seems to be that.
Pass2:

textures and some surrounding objects are drawn, with a little different vertex shader
- Code: Select all
vs.1.0
dp4 oPos.x, v0, c2
dp4 oPos.y, v0, c3
dp4 oPos.z, v0, c4
dp4 oPos.w, v0, c5
mov r0, v0
mov oT0, v3
mov oT1, v3
mov oT2, v3
mov oT3, v3
mov oD0, c1
mov oFog.x, c0
pixel pipeline:
- Code: Select all
r0 = texture0 * diffuse
r0 = r0 * dstcolor ; this line is done in the alpha blender, dstcolor is the previously drawn light maps
Pass3: The thresholded image for light aura

Vertex pipeline is fixed function and not interesting, the previously drawn image is drawn further (scaled down) to a 256x256 texture
Pixel shader
- Code: Select all
ps 1.0
tex t0 ; sample image texture
dp3 r0, t0, c4 ; dot (r0.rgb, c4.rgb) - seems to be converting to grayscale, c4 = (0.200000003, 0.393000007, 0.0732999966, 0),
; so it also seems to contain a darkening factor (darkening the grayscale a little)
cnd r0, r0.a, c6, c5 ; This is the thresholding: r0 = (r0.a > 0.5) ? c6 : c5 (previous result of the dot is replicated to all components of r0)
; so if the grayscale is above 0.5 then the output color is c6 = (0.69, 1.0, 0.69, 0) (greenish), otherwise it's c5 = (0, 0, 0, 0)
After that, a few passes happens where the modulated and dilated versions of the threshold image is drawn onto each other with additive blending.
Vertex pipeline is fixed function, vertex data contains a color and texture coordinates for drawing the quads.
I couldn't see the vertex data when debugged because they were placed into a hw vertex buffer, but the intensity factor for modulation is coming from the vertex color (which is maybe incremented for each subsequent passes, but I guess it's not) and dilating is solved by using texture coordinates that are addressing slightly more and more into a sub-rectangle of interior of the threshold image (it's also a guess).
So, after the first blending pass the image is

I counted 9 repetative passes, after the 9th the image is

pixel pipeline
- Code: Select all
r0 = texture0 * vertex color
r0 = r0 + dstcolor ; dst color is the result of the previous pass (this line is done by the alpha blender)
This drawing process is repeated further: the previously got blended image becomes the source and it's drawn into a half size (128x128) texture this time, 9 passes again:

Then, as you may guessed, this final 128x128 image, as the new source, is drawn into a 64x64 texture, 9 passes again (the picture here is distorted because the output window reached it smallest allowed size, couldn't be 64x64, so it's stretched, don't let it mislead you)

This process is done again, 64x64 -> 32x32
So, at this point we have four textures generated from the threshold image: 256x256, 128x128, 64x64 and 32x32
These are simply stretched to 256x256 and added together to produce the final light aura image used for rendering the noised nightvision scene:

Final image in backbuffer:
