Best way to draw lights from raycast

Im trying to make box2d lights from raycast ,i’ve mange to create raycast lines and points for the light the only step i am missing is drawing the light from the points.


i wanna draw light like this

here is a video tutorial

And this post is the math behind it

2 Likes

@nite I did the math and i have the points, i only want away to draw the light from vec2 points .

I don’t think there is a existing function that can draw lights.

I guess you can take the code from draw polygon and apply a different shader

drawing polygon and then masking it with png light is good idea, but some how draw polygon is missing some points i think its a bug .

That dose looks like a bug, so maybe use the drawPoly code but change the code to use a shader that your own coloring function.

BTW, what you have looks really promising.

I implemented 2d visibility few weeks ago for my game, and I say shader is the way.

What I did is very similar to you. I raycasted from light position to all unique points on walls to get the visible area, removed all the unnecessary rays, then I used shader for smooth light effect.

Pros for using shader was that it was easy to modify light’s attributes, such as color, intensity, blur, etc.
Cons for using shader was I had to re-create light texture every time if light or wall moves, changes, etc. Also it was the slowest step in the entire algorithm.

Here’s the screenshot from my demo application. I used cocos2d-x 3.14 version.

4 Likes

perfect ,can you share the shader code

@bsy6766, that looks excellent, and the shading and and recasting are things that I am very interested in learning more about.

Would you be willing to share as much of the relevant code that you are comfortable sharing? Particularly the shader code, as @Kotaiba requested.

Thanks!

My shader code in demo app is kind of messy and inefficient, I was testing other stuffs while I was implementing.

I’m curious if you guys want the entire shader code or just how to make a light with white in center and fade out effect as my screenshot I posted above.

1 Like

@bsy6766 i am not that good at shaders ,if you feel comfortable sharing the lighting code ,or the lighting and masking it from the raycast point that would be perfect .

1 Like

Here’s my shader code and cpp codes.

vertex shader. Same as default, nothing special.

attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;

varying vec4 v_color;
varying vec2 v_texCoord;

void main()
{
    gl_Position = CC_PMatrix * a_position;
    v_color = a_color;
    v_texCoord = a_texCoord;
}

fragment shader.
I tried to comment as much as I can and there can be always the better way to achieve this, so just use as reference.

in vec2 v_texCoord;   
in vec4 v_color;

/*
                               WHITE_RANGE
                                    |       WHITE_FADE_RANGE      Light ends here
                                    |             |                     |
                                    v             v                     v
    light position -> *-------------*-------------*---------------------*------------//---* 
                      |<- range 1 ->|<- range 2 ->|
*/

// These two const values are distance from light position
const float WHITE_RANGE = 4.0;
const float WHITE_FADE_RANGE = 8.0;

uniform float lightIntensity;            // Distance between 'light position' and 'light end'
uniform vec3 lightColor;                 // Color of light. This is different with cocos2d node's color
uniform vec2 lightPosition;              // Light position
uniform sampler2D lightMapTexture;       // Visible area texture

void main()         
{
    // Get texture color
    vec4 lightMapColor = texture2D(lightMapTexture, v_texCoord);

    // Simply check r from rgb value. If it's not 0, then light is visible
    if(lightMapColor.r != 0.0)
    {
        // Get distance between rendering pixel and light position
        float dist = abs(distance(lightPosition, gl_FragCoord.xy));

        if(0.0 <= dist && dist <= WHITE_RANGE)
        {
            // range 1. color is always white
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
        else if(WHITE_RANGE <= dist && dist <= WHITE_FADE_RANGE)
        {
            // range 2. Mix white and light color
            float ratio = ((dist - WHITE_RANGE) / (WHITE_FADE_RANGE - WHITE_RANGE));
            gl_FragColor = mix(vec4(1.0, 1.0, 1.0, 1.0), vec4(lightColor, 0.7), ratio);
        }
        else if(WHITE_FADE_RANGE <= dist && dist <= lightIntensity)
        {
            float ratio = ((dist - WHITE_FADE_RANGE) / (lightIntensity - WHITE_FADE_RANGE));
            gl_FragColor = mix(vec4(lightColor, 0.7), vec4(0.0, 0.0, 0.0, 0.0), ratio);
        }
        else
        {
            // light doesn't reach here
            gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
        }
    }
    else
    {
        // Light doesn't reach here
        gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
    }
}

I saved shaders in Resource/shaders folder as ‘light_vert.glsl’ and ‘light_frag.glsl’.

Create shader

auto lightShader = cocos2d::GLProgram::createWithFilenames("shaders/light_vert.glsl", "shaders/light_frag.glsl");

Create shader state

auto lightShaderState = cocos2d::GLProgramState::create(lightShader);

Set shader state to sprite.
I created empty sprite.

shaderSprite->setGLProgramState(lightShaderState);

Update shader uniform values every time one of the light position, light color, light intensity changes.

    // Light intenstity
    lightShaderState->setUniformFloat("lightIntensity", lightIntensity);
    // Light color (yellow in this case. Color value must be between 0 and 1 not 0 to 255)
    lightShaderState->setUniformVec3("lightColor", lightColor);
    // Light's position
    lightShaderState->setUniformVec2("lightPosition", lightPosition);
    // Light texture created based on visible area (cocos2d::Texture2D)
    lightShaderState->setUniformTexture("lightMapTexture", lightMapTexture);

And here is the screenshot from above shader.
Intensity = 300.0f, color = vec3(1.0, 1.0, 0.0);

4 Likes

I implemented a version with minimal ray casting and shader without lightmap, should improve the performance a bit.

PS: there is a little thing I’m still trying to figure out. the transition from world coordinates to gl_FragCoord are not correct yet.

4 Likes

@nite thanks for sharing the code ,for me drawing shape then clipping it worked for me this is the result

2 Likes

Your game looks great!Glad it works!