Transferring Additional Data to the Fragment Shader via VBO - DynamicSpriteBatch

I am studying opengl shaders with AndEngine, my goal is to make DynamicSpriteBatch with some flashlight, where the light position will be transmitted via vbo for each draw call in spritebatch, so I can manipulate the light source on each sprite.

So I 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 also created a custom HighPerformanceLightSpriteBatchVBO where I pass the light position to the 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; 

it works with all this, but I have problems reading this light object in the fragment shader. What calculations do I need to do to correctly calculate the distance between the position and the position of the light, if the visualized 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; } }; 

the light is always in the center (200-radius / 2200 radius / 2) and it should be shifted by 100 100 as the last parameters

+8
android opengl-es shader vbo andengine
source share
1 answer

If I understand correctly what you want is to have a relative light position in the fragment shader that is different for each pixel. To do this, you need to access the model and projection matrices in the vertex shader and calculate the up and right vectors for your sprite, which will be passed to the fragment shader. Then, in the fragment shader, add this (multiplied by texcoord) to the center of the sprite to get the position in the world space of each shaded fragment (each pixel of the sprite). Subtract this from the light and voila!

Note that in your shader code you seem to have different precision specifiers for varying variables in vertex / fragment shaders. This can lead to problems (changes may not be bound, so the value that is displayed in the vertex shader is discarded, and the input value in the fragment shader is undefined). This is one of the dark corners of OpenGL, somewhat caused by the requirement to be able to arbitrarily mix and match different shaders of vertices and fragments.

0
source share

All Articles