How to compute the light position in screen space?

Hello guys,

I’m working on a light scattering effect, the one described in GPU Gems 3.

I have access to the 2D coord of the fragment with gl_FragCoord.xy but I also need to compute the 2D coordinate of the light on screen (from the fragment shader).

If I do something like:

gl_LightSource[0].position * gl_ModelViewProjectionMatrix

I obviously miss the viewport projection. Is what I am trying to do even possible ?


gl_ModelViewProjectionMatrix = gl_ProjectionMatrix * gl_ModelViewMatrix

So you already have everything you need.

I didn’t know the projection matrix also included the viewport projection.

So let’s say my light is projected on the screen at 640/480,

gl_LightSource[0].position * gl_ModelViewProjectionMatrix will return a vec2 = (640,480 ) ?

PS: Vive grenoble!!! J’ai fait mes etude la-bas (et je suis a toronto maintenant)

Mmh, I am not sure about this, probably this will return normalized coordinates which should be multiplied by viewport size.

Cheers au pays des caribous :slight_smile:

First off, it should be
gl_ModelViewProjectionMatrix * gl_LightSource[0].position

and second, if you want the position in screen space and since lights normally don’t move, use gluProject. If you want to absolutely do gluProject in shaders, look at the source code for GLU (

Thanks V-Man,

It turns out it would be a waste to perform these calculations for every fragment. I’m better off using gluProject or do it manually and send the vec2 via an uniform value:

Vector4 glToScreen(const Vector4& v) {
    // Get the matrices and viewport
    double modelView[16];
    double projection[16];
    double viewport[4];
    double depthRange[2];

    glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
    glGetDoublev(GL_PROJECTION_MATRIX, projection);
    glGetDoublev(GL_VIEWPORT, viewport);
    glGetDoublev(GL_DEPTH_RANGE, depthRange);

    // Compose the matrices into a single row-major transformation
    Vector4 T[4];
    int r, c, i;
    for (r = 0; r < 4; ++r) {
        for (c = 0; c < 4; ++c) {
            T[r][c] = 0;
            for (i = 0; i < 4; ++i) {
                // OpenGL matrices are column major
                T[r][c] += projection[r + i * 4] * modelView[i + c * 4];

    // Transform the vertex
    Vector4 result;
    for (r = 0; r < 4; ++r) {
        result[r] = T[r].dot(v);

    // Homogeneous divide
    const double rhw = 1 / result.w;

    return Vector4(
        (1 + result.x * rhw) * viewport[2] / 2 + viewport[0],
        (1 - result.y * rhw) * viewport[3] / 2 + viewport[1],
        (result.z * rhw) * (depthRange[1] - depthRange[0]) + depthRange[0],


Yes !

Need fog and some more clouds, but I’m getting there !!

Missing light attenuation ? 1/d² ?

Can you share some info about this nice effect ?

Just came across the technique in GPU Gems 3, which is basically just a directional streak filter as a post process (accum along vector towards projected light). Surprisingly convincing given its simplicity and speed. Anyway, the projected light bit rang a bell…

Well spoted mofus :wink: !

I’m currently comparing the pros and cons of light scattering techniques from:

  • GPU Gems 3 “Volumetric Light Scattering as a Post-Process” by Kenny Mitchell
    -ShadersX3 “Light Shaft Rendering” by Jason L. Mitchell

Kenny Mitchell’s technique is easy to implement but you can’t cast shadow out of it.

I will be releasing the source code later this week.

A highpass filter on the source/downsampled image might do the trick as an alternative to rendering occluders, if you’ve got some decent range (something you might have handy anyway if you’re doing bloom/flare stuff)…

Nice pics :wink:

Here are the binaries and source code:

OpenGL light Scattering

I tested my code on:

  • Windows Vista: GeForce 8600 GT
  • MacBook Pro: GeForce 8600M GT

A friend tried and it didn’t work on his iMac for some reason…


This is simply awesome :smiley:
Your compiled demo runs at 95fps (no matter what exposure,etc) on my weak GF8600GT.