Pasar datos adicionales para fragmentar el shader a través de VBO – DynamicSpriteBatch

Estoy aprendiendo shaders opengl con AndEngine, mi objetivo es hacer DynamicSpriteBatch con algunos lightshader donde la posición de luz se pasará a través de vbo a cada llamada de dibujo en spritebatch para poder manipular la fuente de luz en cada sprite.

Así que he creado LightSpriteBatch (con 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 // =========================================================== 

}

También he creado Custom HighPerformanceLightSpriteBatchVBO donde estoy pasando la posición de la luz en el amortiguador

 @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; 

Con todo esto funciona, pero tengo problemas para leer esta posición de luz en shader de fragmentos. ¿Qué cálculos necesito hacer para calcular correctamente la distancia entre la posición de la luz y la posición si la textura se hace?

 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; } }; 

La luz está siempre en el centro (200 radios / 2.200 radios / 2) y debe ser desplazada por 100.100 como los últimos parámetros

    One Solution collect form web for “Pasar datos adicionales para fragmentar el shader a través de VBO – DynamicSpriteBatch”

    Si lo entiendo correctamente lo que quieres es tener la posición relativa de la luz en el fragmento shader, que difiere para cada píxel. Para ello, debe tener acceso a las matrices de vista de modelo y de proyección en el sombreado de vértices y calcular los vectores up y right para que su sprite se pase al fragmento de sombreado. A continuación, en shader de fragmentos, añada esto (multiplicado por el texcoord) a la posición central del sprite para obtener la posición del espacio del mundo de cada fragmento sombreado (cada píxel del sprite). Reste de la posición de luz y voila!

    Tenga en cuenta que en su código de sombreado parece que tiene especificadores de precisión diferentes para varying variables en sombreados de vértices / fragmentos. Esto puede dar lugar a problemas (las variaciones no pueden vincularse, de modo que el valor que se está produciendo en el sombreado de vértices se desecha y el valor de entrada en el sombreado de fragmentos no está definido). Esta es una de las esquinas oscuras de OpenGL, algo causada por el requisito de poder mezclar arbitrariamente y combinar diferentes sombreadores de vértices y fragmentos.

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.