2013-01-07 7 views
5

Opracowuję 2D animowaną tapetę dla Andoidów przy użyciu biblioteki libgdx i jej klasy SpriteBatch. Jest to zegarek, więc wszystko czego potrzebuję, z libgdx polega na rysowaniu wielu tekstur, obracaniu ich pod określonym kątem.libgdx: SpriteBatch, fragment shaderów na urządzeniach z Androidem Samsung działa niepoprawnie

Rozwiązałem ten problem, używając klasy SpriteBatch i wszystko było w porządku.

Ale teraz muszę dodać efekt powiększającej soczewki do mojej sceny. Zadaniem jest powiększenie określonego obszaru o określony współczynnik, aby symulować rzeczywistą soczewkę.

Rozwiązałem to poprzez renderowanie do FrameBuffer, pobieranie regionu tekstury z FrameBuffer i wreszcie rysowanie tego regionu za pomocą niestandardowego modułu cieniującego, za pomocą SpriteBatch.

PROBLEM: na urządzeniach Samsung (próbowałem na Galaxy N7000, a na Galaxy Tab 10.1) mały prostokąt znajdował się w środku powiększającego obszaru o 16x16 pikseli, gdzie współczynnik powiększenia nieznacznie wzrasta. Niestety, nie mogę teraz opublikować zrzutu ekranu, ponieważ nie mam urządzenia Samsung. Na innych urządzeniach wszystko działa dobrze, wypróbowane w HTC Vivid, Acer A500, Google Nexus One.

Myślę, że problem, jeśli w GPU Mali na urządzeniach Samsung, ale nie wiem, jak to naprawić.

Mam dostosowany fragment kodu shadera z tym pytaniem do SpriteBatch Add Fisheye effect to images at runtime using OpenGL ES Oto ona:

#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 jest domyślnym ze źródeł 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; 
} 

Oto moja metoda 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(); 
    } 

Odpowiedz

3

Ja " udało się naprawić ten problem. Problem jest w Mali gpu. Mali nie obsługuje obliczeń pływalności o wysokiej precyzji w module cieniowania fragmentów. Gdy odległość od środka do punktu była bliska zeru - zmienna r stała się równa zero.

Dodałem więc stały współczynnik do moich obliczeń i to załatwiło sprawę.

Tu pracuje fragment 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

I nie kopiuj i wklej wierzchołków i fragmentów cieniowania i masz błąd w metodzie '' SpriteBatch.begin': java.lang.IllegalArgumentException: brak munduru z nazwą ' u_projTrans "w module cieniującym". Co mnie ominęło? – Nolesh

+1

Prawdopodobnie powodem jest to, że SpriteBatch nie ustawił macierzy odwzorowania w jednolitym cieniu niestandardowego modułu cieniującego. Możesz spróbować ustawić ShaderProgram.pedantic = false, aby wyłączyć sprawdzanie wszystkich uniformów w module cieniującym. Spróbuj również ustawić shader bezpośrednio w SpriteBatch, a nie w Builderze. Patrz: https://code.google.com/p/libgdx/issues/detail?id=1114 https://code.google.com/p/libgdx/issues/detail?id=555 –

+0

Ok . Spróbuję później. Ale czasami ten błąd występuje, jeśli coś jest nie tak w twoim module cieniującym. – Nolesh

Powiązane problemy