2013-01-23 13 views
8

Uczę się shaderów OpenGL z AndEngine, moim celem jest stworzenie DynamicSpriteBatch z jakimś lighthader'em, gdzie pozycja światła będzie przekazywana przez vbo do każdego wywołania draw w spritebatch, dzięki czemu mogę manipulować światłem źródło w każdym spriterze.Prześlij dodatkowe dane do shaderów fragmentów przez VBO - DynamicSpriteBatch

więc mam stworzony LightSpriteBatch (z 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 
// =========================================================== 

}

Mam również stworzył zwyczaj HighPerformanceLightSpriteBatchVBO gdzie jestem przekazując światło pozycyjne w buforze

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

z tym wszystkim działa, ale mam problemy z odczytaniem tego lightposition w shader fragmentu. Jakie obliczenia muszę wykonać, aby prawidłowo obliczyć odległość między pozycją światła a pozycją, jeśli tekstura jest renderowana?

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

światło jest zawsze w centrum (200-radius/2200-radius/2) i powinien zostać przesunięty o 100,100 w ciągu ostatnich parametrów

+1

Czy możesz również opublikować kod modułu cieniującego? – Kimi

+0

Istnieje (drugi fragment z góry) LightShader –

Odpowiedz

0

Jeśli rozumiem go poprawnie, co chcesz to mieć względny lekka pozycja w cieniu, która różni się dla każdego piksela. Aby to zrobić, musisz uzyskać dostęp do macierzy widoków i odwzorowań w module cieniującym wierzchołków i obliczyć wektory dla wektorów, które mają zostać przekazane do shaderów fragmentów. Następnie w shaderach fragmentów dodaj to (pomnożone przez texcoord) do centralnej pozycji sprite'a, aby uzyskać pozycję w przestrzeni świata każdego cieniowanego fragmentu (każdy piksel sprite'a). Odejmij to od pozycji światła i voila!

Należy zauważyć, że w kodzie modułu cieniującego występują różne zmienne precyzji dla zmiennych varying w modułach cieniujących wierzchołków/fragmentów. Może to prowadzić do problemów (różnice mogą nie być powiązane, tak że wartość, która jest wyprowadzana w module cieniującym wierzchołków, jest odrzucana, a wartość wejściowa w module cieniującym fragmentu jest niezdefiniowana). Jest to jeden z ciemnych zakątków OpenGL, w pewnym stopniu spowodowany wymogiem, aby móc dowolnie mieszać i dopasowywać różne shadery wierzchołków i fragmentów.

Powiązane problemy