Hello and sorry for the long wait, I was working on a project from my job.
–
Using the Shader technique:
Shader:
public class LightShaderBatch
{
public static final float DEFAULT_LIGHT_Z = 0.084f;
public static final float AMBIENT_INTENSITY = 0.42f;
public static final float LIGHT_INTENSITY = 0.9f;
public static final Vector3 LIGHT_POS = new Vector3(0,0,DEFAULT_LIGHT_Z);
//Light RGB and intensity (alpha)
//public static final Vector3 LIGHT_COLOR = new Vector3(1f, 1f, 1f);
public static final Vector3 LIGHT_COLOR = new Vector3(0.5168301f, 0.6015233f, 0.78029454f);
//Ambient RGB and intensity (alpha)
public static final Vector3 AMBIENT_COLOR = new Vector3(0.9f, 0.9f, 0.9f);
//Attenuation coefficients for light falloff
public static final Vector3 FALLOFF = new Vector3(0.4f, 0.5f, 0.2f);
public static final String VERT =
"attribute vec4 "+ShaderProgram.POSITION_ATTRIBUTE+";\n" +
"attribute vec4 "+ShaderProgram.COLOR_ATTRIBUTE+";\n" +
"attribute vec2 "+ShaderProgram.TEXCOORD_ATTRIBUTE+"0;\n" +
"uniform mat4 u_projTrans;\n" +
" \n" +
"varying vec4 vColor;\n" +
"varying vec2 vTexCoord;\n" +
"void main() {\n" +
" vColor = "+ShaderProgram.COLOR_ATTRIBUTE+";\n" +
" vTexCoord = "+ShaderProgram.TEXCOORD_ATTRIBUTE+"0;\n" +
" gl_Position = u_projTrans * " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" +
"}";
public static final String FRAG =
//GL ES specific stuff
"#ifdef GL_ES\n" //
+ "#define LOWP lowp\n" //
+ "precision mediump float;\n" //
+ "#else\n" //
+ "#define LOWP \n" //
+ "#endif\n" + //
"//attributes from vertex shader\n" +
"varying LOWP vec4 vColor;\n" +
"varying vec2 vTexCoord;\n" +
"\n" +
"//our texture samplers\n" +
"uniform sampler2D u_texture; //diffuse map\n" +
"uniform sampler2D u_texture1; //diffuse map\n" +
"uniform sampler2D u_normals; //normal map\n" +
"\n" +
"//values used for shading algorithm...\n" +
"uniform vec2 Resolution; //resolution of screen\n" +
"uniform vec3 LightPos; //light position, normalized\n" +
"uniform LOWP vec4 LightColor; //light RGBA -- alpha is intensity\n" +
"uniform LOWP vec4 AmbientColor; //ambient RGBA -- alpha is intensity \n" +
"uniform vec3 Falloff; //attenuation coefficients\n" +
"\n" +
"void main() {\n" +
" //RGBA of our diffuse color\n" +
" vec4 DiffuseColor = texture2D(u_texture, vTexCoord);\n" +
" \n" +
" //RGB of our normal map\n" +
" vec3 NormalMap = texture2D(u_normals, vTexCoord).rgb;\n" +
" \n" +
" //The delta position of light\n" +
" vec3 LightDir = vec3(LightPos.xy - (gl_FragCoord.xy / Resolution.xy), LightPos.z);\n" +
" \n" +
" //Correct for aspect ratio\n" +
" LightDir.x *= Resolution.x / Resolution.y;\n" +
" \n" +
" //Determine distance (used for attenuation) BEFORE we normalize our LightDir\n" +
" float D = length(LightDir);\n" +
" \n" +
" //normalize our vectors\n" +
" vec3 N = normalize(NormalMap * 2.0 - 1.0);\n" +
" vec3 L = normalize(LightDir);\n" +
" \n" +
" //Pre-multiply light color with intensity\n" +
" //Then perform \"N dot L\" to determine our diffuse term\n" +
" vec3 Diffuse = (LightColor.rgb * LightColor.a) * max(dot(N, L), 0.0);\n" +
"\n" +
" //pre-multiply ambient color with intensity\n" +
" vec3 Ambient = AmbientColor.rgb * AmbientColor.a;\n" +
" \n" +
" //calculate attenuation\n" +
" float Attenuation = 1.0 / ( Falloff.x + (Falloff.y*D) + (Falloff.z*D*D) );\n" +
" \n" +
" //the calculation which brings it all together\n" +
" vec3 Intensity = Ambient + Diffuse * Attenuation;\n" +
" vec3 FinalColor = DiffuseColor.rgb * Intensity;\n" +
" gl_FragColor = vColor * vec4(FinalColor, DiffuseColor.a);\n" +
"}";
}
Initialize:
public void initializeShader()
{
ShaderProgram.pedantic = false;
shader = new ShaderProgram(LightShaderBatch.VERT, LightShaderBatch.FRAG);
if (!shader.isCompiled())
throw new GdxRuntimeException("Could not compile shader: "+shader.getLog());
if (shader.getLog().length()!=0)
System.out.println(shader.getLog());
shader.begin();
shader.setUniformi("u_normals", 1);
shader.setUniformf("LightColor", LightShaderBatch.LIGHT_COLOR.x, LightShaderBatch.LIGHT_COLOR.y, LightShaderBatch.LIGHT_COLOR.z, LightShaderBatch.LIGHT_INTENSITY);
shader.setUniformf("AmbientColor", LightShaderBatch.AMBIENT_COLOR.x, LightShaderBatch.AMBIENT_COLOR.y, LightShaderBatch.AMBIENT_COLOR.z, LightShaderBatch.AMBIENT_INTENSITY);
shader.setUniformf("Falloff", LightShaderBatch.FALLOFF);
Texture a = new Texture("data/images/maps/pixel_test_shader.png");
Texture b = new Texture("data/images/maps/pixel_test.png");
a.bind(1);
b.bind(0);
shader.end();
game.batch = new SpriteBatch(1000, shader);
game.batch.setProjectionMatrix(camera.combined);
Gdx.input.setInputProcessor(new InputAdapter() {
public boolean scrolled(int delta) {
LightShaderBatch.LIGHT_POS.z = Math.max(0f, LightShaderBatch.LIGHT_POS.z - (delta * 0.005f));
System.out.println("New light Z: "+LightShaderBatch.LIGHT_POS.z);
//camera.zoom = Math.max(0f, camera.zoom - (delta * 0.05f));
return true;
}
});
}
Logic:
LightShaderBatch.LIGHT_POS.set(
lightPos.x/viewport.getWorldWidth(),
lightPos.y/viewport.getWorldHeight(),
LightShaderBatch.LIGHT_POS.z);
//viewport.getWorldWidth/Height is to set the correct position padding.
Draw:
shader.setUniformf("LightPos", LightShaderBatch.LIGHT_POS);
Using the Mask technique:
Initialize:
//FrameBuffer
lightSprite = new Texture(Gdx.files.internal("data/images/sheet/light.png"));
if (lightBuffer!=null) lightBuffer.dispose();
lightBuffer = new FrameBuffer(Format.RGBA8888, resW, resH, false);
lightBuffer.getColorBufferTexture().setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
lightBufferRegion = new TextureRegion(lightBuffer.getColorBufferTexture(), 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
lightBufferRegion.flip(false, true);
Draw:
drawGame();
drawFBO();
drawUI; //stage user interface
drawFBO:
public void drawFBO()
{
//LightBuffer
lightBuffer.begin();
Gdx.gl.glClearColor(0f, 0f, 0f, 1f); //bg
Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT);
game.batch.begin();
game.batch.setBlendFunction(-1, -1);
Gdx.gl.glBlendFuncSeparate(GL30.GL_SRC_ALPHA, GL30.GL_ONE_MINUS_SRC_ALPHA, GL30.GL_ONE, GL30.GL_ONE);
game.batch.setColor(1f, 1f, 0f, 1f); //Light 1
game.batch.draw(lightSprite, resW/2-radius-150, resH/2-radius, diam, diam);
game.batch.setColor(0f, 1f, 1f, 1f); //Light 2
game.batch.draw(lightSprite, resW/2-radius+150, resH/2-radius, diam, diam);
game.batch.end();
lightBuffer.end();
Gdx.gl.glBlendFunc(GL30.GL_DST_COLOR, GL30.GL_ZERO);
game.batch.begin();
game.batch.setColor(1f, 1f, 1f, 1f); //FBO to texture.
game.batch.draw(lightBufferRegion, 0, 0);
game.batch.end();
}
Notes:
- Shaders: I was using the light to follow the front of a car (car headlight).
- Mask: I’m using in pre-defined positions, light from sources (lamps). I’m using only two BIG lights in the code above only to show, but I’m testing 10+ with different sizes, colors.
- The Car example is just my old game, but I tried the same code.
- Screens:
http://s9.postimg.org/d0yr53em7/car.png
http://s18.postimg.org/lri2fxqsp/light.png
As you can see, the lights work perfectly, but I’m not confident that I’ll can use them as adding more lights. The mobile version loses some frames (and I have not tested it yet using all the objects and enemies of the game at same time), maybe because I need to call batch.begin/end a lot of times for FBO?
How games can have glow/light effect on tons of bullets or on each enemy without losing performance. =S