I have a single point light-source which is a flaming torch. I compute the distance from the light accurately.

I am not trying to have a particularly realistic torch effect, but I will be moving the light-source slightly each frame and perhaps introducing a slight flicker in strength.

I want near the light to be white - say up to a distance of 200 - and then getting darker and yellower until, say, 400 before fading rapidly to black at 450.

What is the best way to do smooth extinction like this?

Here's my current fragment shader, simply so I know that I have it centered correctly:

uniform vec4 COLOUR;
uniform sampler2D TEX_UNIT_0;
varying vec2 tex_coord_0;
varying vec3 normal;
varying vec3 light_0;
void main() {
    vec3 pixel = vec3(0.,0.,0.);
    vec3 N = normalize(normal);
    vec3 L = normalize(light_0);
    float lambert = max(dot(N,L),0.);
    if(lambert > 0.) {
        pixel = texture2D(TEX_UNIT_0,tex_coord_0).rgb;
        float att = 1.;
        float d = length(light_0);
        if(d > 300.) att *= .5;
        if(d > 350.) att *= .5;
        if(d > 400.) att *= .5;
        if(d > 450.) att *= .5;
        if(d > 500.) att = 0.;
        pixel *= att;
    gl_FragColor = vec4(COLOUR.rgb * pixel * lambert,COLOUR.a);
  • 1
    \$\begingroup\$ I'm curious as to the need for such specificity. Why don't you use physically-based light attenuation? \$\endgroup\$ – Nicol Bolas Jan 30 '12 at 23:16
  • \$\begingroup\$ @NicolBolas its for a hack on ludumdare.com/compo/minild-31/?action=preview&uid=10313 and its OpenGLES 2 so I don't have all the built-in light structures; if you can show how to recreate the OpenGL attenuation and you consider it fast and simple, please answer \$\endgroup\$ – Will Jan 31 '12 at 6:19
  • \$\begingroup\$ It's a shader; you can do whatever you want in terms of logic. Inverse r^2 attenuation doesn't require any "built-in light structures"; it simply requires that you pass in a constant of proportionality for the attenuation. Which is just a user-defined uniform value. \$\endgroup\$ – Nicol Bolas Jan 31 '12 at 6:22
  • 1
    \$\begingroup\$ @NicolBolas if you're saying that's the best way, you should put it in an answer, along with appropriate code snippets. \$\endgroup\$ – Will Jan 31 '12 at 7:31
  • \$\begingroup\$ Best is a subjective question, and subjective is not what Stack Exchange sites are about. I wouldn't use anything except physically based light attenuation, unless I was doing some non-photorealistic rendering technique. But that's just me; I hate screen-space ambient occlusion for the same reason: it's based on a great big lie. \$\endgroup\$ – Nicol Bolas Jan 31 '12 at 7:38

Probably the best way to control it exactly is to just bake attenuation into a low-res 1d texture and have your artist author the falloff. This'll also allow you to attenuate red/green/blue at different rates and change the attenuation function just by binding a different texture eg.

pixel = texture2D(TEX_UNIT_0, tex_coord_0).rgb;
float d = length(light_0);
lightCoord = clamp(d * LIGHT_0_INV_SCALE + LIGHT_0_BIAS, 0.0, 1.0);
pixel *= texture2D(TEX_UNIT_1, vec2(lightCoord.x, 0.0)).rgb;

Then setup your uniforms like this:

LIGHT_0_INV_SCALE = 1/lightRadius;
LIGHT_0_BIAS  = some value in [0..1];

Of course you can animate both of these properties cpu side in some random/linear fashion.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.