2013-01-23 13 views
8

Sto imparando opengl shaders con AndEngine, il mio obiettivo è rendere DynamicSpriteBatch con un lightshader in cui la posizione di luce passerà attraverso vbo a ogni chiamata di estrazione in spritebatch in modo da poter manipolare la luce fonte su ogni sprite.Passare ulteriori dati a framment shader tramite VBO - DynamicSpriteBatch

Così ho creato 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 
// =========================================================== 

}

Ho anche creato su misura HighPerformanceLightSpriteBatchVBO dove sto passando luce di posizione nel 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; 

con tutto questo funziona ma ho problemi a leggere questa luce in shader di frammenti. Quali calcoli devo fare per calcolare correttamente la distanza tra la posizione e la posizione della luce se la trama è resa?

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

luce è sempre al centro (200-raggio/2.200-raggio/2) e dovrebbe essere spostato di 100,100 come gli ultimi parametri

+1

Potresti postare anche il codice shader? – Kimi

+0

C'è (secondo snippet dall'alto) LightShader –

risposta

0

Se ho ben capito ciò che si desidera è di avere relativa posizione chiara nello shader di frammenti, che differisce per ciascun pixel. Per fare ciò, è necessario accedere alle matrici di modelview e di proiezione in vertex shader e calcolare i vettori up e right per far sì che lo sprite venga passato a framment shader. Quindi, nello shader di frammenti, aggiungi questo (moltiplicato per il texcoord) alla posizione del centro dello sprite per ottenere la posizione dello spazio del mondo di ciascun frammento ombreggiato (ciascun pixel dello sprite). Sottrarre quello dalla posizione di luce e voilà!

Si noti che nel proprio codice shader si ha un diverso specificatore di precisione per le variabili varying in vertex/framment shader. Ciò può portare a problemi (le varianti potrebbero non essere collegate, quindi il valore che viene emesso in vertex shader viene gettato via e il valore di input in framment shader non è definito). Questo è uno degli angoli oscuri di OpenGL, in qualche modo causato dall'esigenza di essere in grado di mescolare e abbinare arbitrariamente diversi vertex e frammenti di shader.

Problemi correlati