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
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 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.
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.
@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 .
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);
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.
@nite thanks for sharing the code ,for me drawing shape then clipping it worked for me this is the result
Your game looks great!Glad it works!