Передача дополнительных данных в шейдер фрагмента через VBO – DynamicSpriteBatch

Я изучаю opengl shaders с AndEngine, моя цель – сделать DynamicSpriteBatch с некоторым фонариком, где светлая позиция будет передаваться через vbo для каждого вызова draw в spritebatch, поэтому я могу манипулировать источником света на каждом спрайте.

Итак, я создал LightSpriteBatch (с 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 // =========================================================== 

}

Я также создал пользовательский HighPerformanceLightSpriteBatchVBO, где я передаю светлое положение в буфер

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

Со всем этим он работает, но у меня проблемы с чтением этого светового объекта в шейдере фрагмента. Какие вычисления мне нужно сделать, чтобы правильно рассчитать расстояние между световым положением и положением, если визуализированная текстура?

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

Свет всегда находится в центре (200-радиус / 2200 радиус / 2), и он должен быть сдвинут на 100 100 в качестве последних параметров

Если я правильно понимаю, что вы хотите, это иметь относительное световое положение в шейдере фрагмента, которое отличается для каждого пикселя. Для этого вам нужно получить доступ к матрицам модели и проекции в вершинном шейдере и вычислить верхние и right векторы для вашего спрайта, которые будут переданы в шейдер фрагмента. Затем в фрагментном шейдере добавьте это (умноженное на texcoord) в положение центра спрайта, чтобы получить положение в пространстве мира каждого заштрихованного фрагмента (каждый пиксель спрайта). Вычтите это из положения света и вуаля!

Обратите внимание, что в вашем шейдерном коде у вас, похоже, есть разные спецификаторы точности для varying переменных в шейдерах вершин / фрагментов. Это может привести к проблемам (изменения могут не связываться, так что значение, которое выводится в вершинном шейдере, выбрасывается, а входное значение в шейдере фрагмента не определено). Это один из темных углов OpenGL, несколько вызванный требованием иметь возможность произвольно смешивать и сопоставлять разные шейдеры вершин и фрагментов.

Intereting Posts