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).
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 (www.mesa3d.org)
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],
rhw);
}
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…
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)…