2013-01-07 14 views
5

Sto sviluppando un live wallpaper 2D per Andoid usando libgdx e la sua classe SpriteBatch. Questo è un orologio, quindi tutto ciò di cui ho bisogno, da libgdx è solo disegnare più trame, ruotandole a un angolo specifico.libgdx: SpriteBatch, framment shader su dispositivi Android Samsung funzionano in modo errato

Ho risolto questo problema utilizzando la classe SpriteBatch e tutto andava bene.

Ma ora ho bisogno di aggiungere l'effetto lente d'ingrandimento alla mia scena. Il compito è di ingrandire un'area specifica con un rapporto specifico per simulare l'obiettivo reale.

Ho risolto questo rendendo a FrameBuffer, ottenendo texture regione da FrameBuffer e, infine, disegnando questa regione con shader personalizzato, utilizzando SpriteBatch.

IL PROBLEMA: su dispositivi Samsung (ho provato su Galaxy Note N7000 e Galaxy Tab 10.1) c'è un piccolo rettangolo al centro dell'area di ingrandimento di circa 16x16px, dove il rapporto di ingrandimento aumenta leggermente. Spiacente, non posso pubblicare uno screenshot ora, perché non ho un dispositivo Samsung. Su altri dispositivi funziona tutto bene, provato in HTC Vivid, Acer A500, Google Nexus One.

Penso, il problema se in Mali GPU su dispositivi Samsung, ma non so, come risolverlo.

Ho adattato frammento di codice dello shader da questa domanda a SpriteBatch Add Fisheye effect to images at runtime using OpenGL ES Qui è esso:

#ifdef GL_ES 
#define LOWP lowp 
precision mediump float; 
#else 
#define LOWP 
#endif 

varying LOWP vec4 v_color; 
varying vec2 v_texCoords; 
uniform sampler2D u_texture; 

void main() { 
vec2 m = vec2(0.622 , 0.4985); // lens center point, note that in live wallpaper center of texture is (0.5,0.5) 
float lensSize = 0.045; //diameter of lens 
float lensCut = 0.0342; //length of cut lines 

vec2 d = v_texCoords - m; 
float r = sqrt(dot(d, d)); // distance of pixel from mouse 
float cuttop = m.y + lensCut; 
float cutbottom = m.y - lensCut; 

vec2 uv; 
if (r >= lensSize) { 
    uv = v_texCoords; 
} else if (v_texCoords.y >= cuttop) { 
    uv = v_texCoords; 
} else if (v_texCoords.y <= cutbottom) { 
    uv = v_texCoords; 
} else { 
    uv = m + normalize(d) * asin(r)/(3.14159 * 0.37); 
} 

gl_FragColor = texture2D(u_texture, uv); 
} 

vertex shader è di default da fonti SpriteBatch:

attribute vec4 a_position; 
attribute vec4 a_color; 
attribute vec2 a_texCoord0; 

uniform mat4 u_projTrans; 

varying vec4 v_color; 
varying vec2 v_texCoords; 

void main() { 
    v_color = a_color; 
    v_texCoords = a_texCoord0; 
    gl_Position = u_projTrans * a_position; 
} 

Ecco il mio metodo render():

GL20 gl = Gdx.graphics.getGL20(); 
    gl.glEnable(GL20.GL_TEXTURE_2D); 
    gl.glActiveTexture(GL20.GL_TEXTURE0); 

    gl.glClearColor(WallpaperService.bg_red, WallpaperService.bg_green, WallpaperService.bg_blue, 1f); 
    gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 


    // Creating framebuffer, if it has gone 
    if (mFrameBuffer == null) { 
     mFrameBuffer = new FrameBuffer(Format.RGBA4444, BG_WIDTH, BG_HEIGHT, true); 

     mFrameBufferRegion = new TextureRegion(mFrameBuffer.getColorBufferTexture()); 
     mFrameBufferRegion.flip(false, true); 

    } 

    //Camera setting according to background texture 
    camera = new OrthographicCamera(BG_WIDTH, BG_HEIGHT); 
    camera.position.set(BG_WIDTH/2, BG_WIDTH/2, 0); 
    camera.update(); 
    batch.setProjectionMatrix(camera.combined); 

    //Rendering scene to framebuffer 
    mFrameBuffer.begin(); 
    batch.begin(); 
    //main Drawing goes here 
    batch.end(); 

    //Drawing frame to screen with applying shaders for needed effects 
    if (mFrameBuffer != null) { 
     mFrameBuffer.end(); 

     camera = new OrthographicCamera(width, height); 
     camera.position.set(width/2, height/2, 0); 
     camera.update(); 
     batch.setProjectionMatrix(camera.combined); 

     batch.begin(); 
     batch.setShader(null); 

     batch.setShader(shader); 

     batch.draw(mFrameBufferRegion, width/2 - (BG_WIDTH/2) + (MARGIN_BG_LEFT * ratio), height/2 
       - (BG_HEIGHT/2) + (MARGIN_BG_TOP * ratio), (float) BG_WIDTH/2, (float) BG_HEIGHT/2, 
       (float) BG_WIDTH, (float) BG_HEIGHT, (float) ratio, (float) ratio, 0f); 

     batch.setShader(null); 
     batch.end(); 
    } 

risposta

3

I ' sono riuscito a risolvere questo problema. Il problema è in Mali gpu. Mali non supporta calcoli float ad alta precisione in framment shader. Quando la distanza dal centro al punto era vicino allo zero, la variabile r è diventata zero.

Quindi ho aggiunto un coefficiente costante ai miei calcoli e questo ha fatto il trucco.

Qui sta lavorando frammento di shader:

precision mediump float; 

varying lowp vec4 v_color; 
varying vec2 v_texCoords; 


uniform sampler2D u_texture; 

const float PI = 3.14159; 
const float koef = 10.0; 
void main() { 
    vec2 uv;  
    vec2 m = vec2(0.622 , 0.4985); // lens center point, note that in live wallpaper center of texture is (0.5,0.5) 
    float lensSize = 0.045; //radius of lens 
    float lensCut = 0.0342; //height of cut 

    float cuttop = m.y + lensCut; 
    float cutbottom = m.y - lensCut; 
    float cutleft = m.x-lensSize; 
    float cutright = m.x+lensSize; 

//don't transform pixels, that aren't in lens area 
    if (v_texCoords.y >= cuttop) { 
     uv = v_texCoords; 
    } else if (v_texCoords.y <= cutbottom) { 
     uv = v_texCoords; 
      } else if (v_texCoords.x <= cutleft) { 
     uv = v_texCoords; 
      } else if (v_texCoords.x >= cutright) { 
     uv = v_texCoords; 
     } else { 
    vec2 p = v_texCoords*koef; //current point 
    vec2 d = p - m*koef; //vector differnce between current point and center point 
    float r = distance(m*koef,p); // distance of pixel from center 

    if (r/koef >= lensSize) { 
     uv = v_texCoords; 
     } else { 
    uv =m + normalize(d) * asin(r)/(PI*0.37*koef); 
    } 
    } 

    gl_FragColor = texture2D(u_texture, uv); 
} 
+1

ho copiato e incollare il vertex e fragment shader e ottenuto un errore in 'metodo SpriteBatch.begin':' java.lang.IllegalArgumentException: non uniforme con il nome ' u_projTrans 'in shader'. Cosa mi sono perso? – Nolesh

+1

Probabilmente il motivo è che SpriteBatch non ha impostato la matrice di proiezione uniforme sullo shader personalizzato. Puoi provare a impostare ShaderProgram.pedantic = false per disabilitare il controllo di tutte le uniformi nello shader. Prova anche a impostare lo shader direttamente su SpriteBatch, non sul builder. Vedi: https://code.google.com/p/libgdx/issues/detail?id=1114 https://code.google.com/p/libgdx/issues/detail?id=555 –

+0

Ok . Ci proverò più tardi. Ma a volte questo errore si verifica se qualcosa di sbagliato nel tuo shader. – Nolesh