I'm learning opengl shaders with AndEngine , my goal is to make DynamicSpriteBatch with some lightshader where light position will be passed throught vbo to each draw call in spritebatch so i can manipulate light source on every sprite.
So i have created LightSpriteBatch ( with drawtype.dynamic )
public class LightSpriteBatch extends Shape {
// ===========================================================
// Constants
// ===========================================================
private static final float[] VERTICES_TMP = new float[8];
private static final Transformation TRANSFORATION_TMP = new Transformation();
public static final int VERTEX_INDEX_X = 0;
public static final int VERTEX_INDEX_Y = 1;
public static final int COLOR_INDEX = 2;
public static final int TEXTURECOORDINATES_INDEX_U = 3;
public static final int TEXTURECOORDINATES_INDEX_V = 4;
public static final int LIGHT_POSITION_INDEX_X = 5;
public static final int LIGHT_POSITION_INDEX_Y = 6
;
public static final int VERTEX_SIZE = 2 + 1 + 2 + 2 ;
public static final int VERTICES_PER_SPRITE = 6;
public static final int SPRITE_SIZE = VERTEX_SIZE * VERTICES_PER_SPRITE;
public static final VertexBufferObjectAttributes VERTEXBUFFEROBJECTATTRIBUTES_DEFAULT = new VertexBufferObjectAttributesBuilder(4)
.add(ShaderProgramConstants.ATTRIBUTE_POSITION_LOCATION, ShaderProgramConstants.ATTRIBUTE_POSITION, 2, GLES20.GL_FLOAT, false)
.add(ShaderProgramConstants.ATTRIBUTE_COLOR_LOCATION, ShaderProgramConstants.ATTRIBUTE_COLOR, 4, GLES20.GL_UNSIGNED_BYTE, true)
.add(ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES_LOCATION, ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES, 2, GLES20.GL_FLOAT, false)
.add(LightShader.ATTRIBUTE_LIGHT_POSITION_LOCATION, LightShader.ATTRIBUTE_LIGHT_POSITION, 2, GLES20.GL_FLOAT, false)
.build();
LightShader
public class LightShader extends ShaderProgram {
// ===========================================================
// Constants
// ===========================================================
private static LightShader INSTANCE;
public static final String ATTRIBUTE_LIGHT_POSITION = "a_lightPosition";
public final static int ATTRIBUTE_LIGHT_POSITION_LOCATION = 4;
public static final String VERTEXSHADER =
"uniform mat4 " + ShaderProgramConstants.UNIFORM_MODELVIEWPROJECTIONMATRIX + ";\n" +
"attribute vec4 " + ShaderProgramConstants.ATTRIBUTE_POSITION + ";\n" +
"attribute vec4 " + ShaderProgramConstants.ATTRIBUTE_COLOR + ";\n" +
"attribute vec2 " + ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES + ";\n" +
"attribute vec2 " + LightShader.ATTRIBUTE_LIGHT_POSITION + ";\n" +
"varying vec4 " + ShaderProgramConstants.VARYING_COLOR + ";\n" +
"varying vec2 " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + ";\n" +
"varying vec2 v_lightPosition;\n" +
"void main() {\n" +
" v_lightPosition = "+ LightShader.ATTRIBUTE_LIGHT_POSITION +" ;\n" +
" " + ShaderProgramConstants.VARYING_COLOR + " = " + ShaderProgramConstants.ATTRIBUTE_COLOR + ";\n" +
" " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " = " + ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES + ";\n" +
" gl_Position = " + ShaderProgramConstants.UNIFORM_MODELVIEWPROJECTIONMATRIX + " * " + ShaderProgramConstants.ATTRIBUTE_POSITION + ";\n" +
"}";
public static final String FRAGMENTSHADER =
"precision lowp float;\n" +
"uniform sampler2D " + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ";\n" +
"varying lowp vec4 " + ShaderProgramConstants.VARYING_COLOR + ";\n" +
"varying mediump vec2 " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + ";\n" +
"varying lowp vec2 v_lightPosition;\n" +
"void main() {\n" +
" vec4 tx = texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + ") ;"+
" float u_radius = 100.0;"+
" vec2 u_lightPosition = vec2(200-50+v_lightPosition.x,200-50+v_lightPosition.y);"+
" float distance = length( u_lightPosition - gl_FragCoord.xy );"+
" float intensity =( 1.5-min( distance, u_radius )/u_radius)*1.5;"+
" gl_FragColor = vec4(tx.r*intensity,tx.g*intensity,tx.b*intensity,tx.w);"+
"}";
// ===========================================================
// Fields
// ===========================================================
public static int sUniformModelViewPositionMatrixLocation = ShaderProgramConstants.LOCATION_INVALID;
public static int sUniformTexture0Location = ShaderProgramConstants.LOCATION_INVALID;
// ===========================================================
// Constructors
// ===========================================================
private LightShader() {
super(LightShader.VERTEXSHADER, LightShader.FRAGMENTSHADER);
}
public static LightShader getInstance() {
if(LightShader.INSTANCE == null) {
LightShader.INSTANCE = new LightShader();
}
return LightShader.INSTANCE;
}
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
protected void link(final GLState pGLState) throws ShaderProgramLinkException {
GLES20.glBindAttribLocation(this.mProgramID, ShaderProgramConstants.ATTRIBUTE_POSITION_LOCATION, ShaderProgramConstants.ATTRIBUTE_POSITION);
GLES20.glBindAttribLocation(this.mProgramID, ShaderProgramConstants.ATTRIBUTE_COLOR_LOCATION, ShaderProgramConstants.ATTRIBUTE_COLOR);
GLES20.glBindAttribLocation(this.mProgramID, ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES_LOCATION, ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES);
GLES20.glBindAttribLocation(this.mProgramID, ShaderProgramConstants.ATTRIBUTE_POSITION_0_LOCATION, ShaderProgramConstants.ATTRIBUTE_POSITION_0);
super.link(pGLState);
LightShader.sUniformModelViewPositionMatrixLocation = this.getUniformLocation(ShaderProgramConstants.UNIFORM_MODELVIEWPROJECTIONMATRIX);
LightShader.sUniformTexture0Location = this.getUniformLocation(ShaderProgramConstants.UNIFORM_TEXTURE_0);
}
@Override
public void bind(final GLState pGLState, final VertexBufferObjectAttributes pVertexBufferObjectAttributes) {
GLES20.glEnableVertexAttribArray(ShaderProgramConstants.ATTRIBUTE_POSITION_0_LOCATION);
super.bind(pGLState, pVertexBufferObjectAttributes);
GLES20.glUniformMatrix4fv(LightShader.sUniformModelViewPositionMatrixLocation, 1, false, pGLState.getModelViewProjectionGLMatrix(), 0);
GLES20.glUniform1i(LightShader.sUniformTexture0Location, 0);
}
@Override
public void unbind(GLState pGLState) throws ShaderProgramException {
GLES20.glDisableVertexAttribArray(ShaderProgramConstants.ATTRIBUTE_POSITION_0_LOCATION);
super.unbind(pGLState);
}
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}
I have also created custom HighPerformanceLightSpriteBatchVBO where i'm passing light position into buffer
@Override
public void addWithPackedColor(final ITextureRegion pTextureRegion, final float pX1, final float pY1, final float pX2, final float pY2, final float pColorABGRPackedInt,final float pLightXX,final float pLightYY) {
final float[] bufferData = this.getBufferData();
final int bufferDataOffset = this.mBufferDataOffset;
final float x1 = pX1;
final float y1 = pY1;
final float x2 = pX2;
final float y2 = pY2;
final float u = pTextureRegion.getU();
final float v = pTextureRegion.getV();
final float u2 = pTextureRegion.getU2();
final float v2 = pTextureRegion.getV2();
final float pLightX = pLightXX;
final float pLightY = pLightYY;
if(pTextureRegion.isRotated()) {
bufferData[bufferDataOffset + 0 * LightSpriteBatch.VERTEX_SIZE + LightSpriteBatch.VERTEX_INDEX_X] = x1;
bufferData[bufferDataOffset + 0 * LightSpriteBatch.VERTEX_SIZE + LightSpriteBatch.VERTEX_INDEX_Y] = y1;
bufferData[bufferDataOffset + 0 * LightSpriteBatch.VERTEX_SIZE + LightSpriteBatch.COLOR_INDEX] = pColorABGRPackedInt;
bufferData[bufferDataOffset + 0 * LightSpriteBatch.VERTEX_SIZE + LightSpriteBatch.TEXTURECOORDINATES_INDEX_U] = u;
bufferData[bufferDataOffset + 0 * LightSpriteBatch.VERTEX_SIZE + LightSpriteBatch.TEXTURECOORDINATES_INDEX_V] = v;
bufferData[bufferDataOffset + 0 * LightSpriteBatch.VERTEX_SIZE + LightSpriteBatch.LIGHT_POSITION_INDEX_X] = pLightX;
bufferData[bufferDataOffset + 0 * LightSpriteBatch.VERTEX_SIZE + LightSpriteBatch.LIGHT_POSITION_INDEX_Y] = pLightY;
with all of this it works but i have problems reading this lightposition in fragment shader. What calculations i need to do to properly calculate distance between light position and position if rendered texture ?
DynamicLightSpriteBatch sb = new DynamicLightSpriteBatch(mTextureSprite,10,getVertexBufferObjectManager()) {
@Override
protected boolean onUpdateSpriteBatch() {
draw(mTextureSpriteRegion, 0f, 0f, 400f, 400f, 0f, 1.0f, 1.0f, 1.0f, 1.0f,100f,100f); // ( 100,100 = lightX & Y )
return true;
}
};
light is always at center (200-radius/2,200-radius/2) and it should be shifted by 100,100 as the last parameters