Máscara Libgdx con imagen
Tengo un framebuffer, donde algunas formas se dibujan usando ShapeRenderer. Y ahora quiero enmascarar este framebuffer con la máscara de la imagen. Antes de eso lo conseguí trabajando con la máscara de círculo simple dibujado por ShapeRenderer. Pero necesito usar una máscara más compleja así que tengo que utilizar una imagen. La máscara es un png con la máscara negra y el fondo transparente. Aquí está mi código:
@Override public void draw(Batch batch, float parentAlpha) { //disable RGB color, only enable ALPHA to the frame buffer Gdx.gl.glColorMask(false, false, false, true); //change the blending function for our alpha map batch.setBlendFunction(GL20.GL_ZERO, GL20.GL_SRC_ALPHA); //draw alpha mask sprite(s) batch.draw(maskTexture, MASK_OFFSET_X + getX(), MASK_OFFSET_Y + getY()); //flush the batch to the GPU batch.flush(); Gdx.gl.glColorMask(true, true, true, true); batch.setBlendFunction(GL20.GL_DST_ALPHA, GL20.GL_ONE_MINUS_DST_ALPHA); //The scissor test is optional, but it depends Gdx.gl.glEnable(GL20.GL_SCISSOR_TEST); Gdx.gl.glScissor(MASK_OFFSET_X + (int) getX(), MASK_OFFSET_Y + (int) getY(), maskTexture.getWidth(), maskTexture.getHeight()); //draw framebuffer to be masked batch.draw(frm, getX(), getY(), frmSizeX, frmSizeY); //remember to flush before changing GL states again batch.flush(); //disable scissor before continuing Gdx.gl.glDisable(GL20.GL_SCISSOR_TEST); //set default blend function batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); }
Mi imagen está enmascarada, pero hay un fondo negro de la imagen de la máscara (debe ser transparente). Ahora se ve así:
- OpenGL ES 3.0. Textura de punto flotante
- Cómo guardar bitmap de GLSurfaceView (Sólo bitmap, no toda la textura)
- La textura transparente de Android OpenGL dibuja negro
- Android Openg GL ES 2 dibujo grandes texturas lento
- Obtener las líneas de GL10 dibujo de imágenes junto a la otra, la solución?
Y debe buscar por ejemplo como este (excepto este ejemplo es sin máscara tan ofc pintura shoud no va fuera de la cabeza):
También tome nota de que la pintura es medio transparente. (No sé si cambiará algún código).
Ofc Estoy usando el formato RGBA8888, aquí está el código de inicialización:
frmBuff = new FrameBuffer(Format.RGBA8888, frmSizeX, frmSizeY, false); frm = new TextureRegion(frmBuff.getColorBufferTexture()); frmCam = new OrthographicCamera(frmSizeX, frmSizeY); frmCam.translate(frmSizeX / 2, frmSizeY / 2); maskTexture = game.manager.get("my_mask.png", Texture.class); maskTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
Estaba jugando con setBlendFunction y logré resultados muy diferentes, pero ninguno de ellos era realmente correcto.
¿Cómo puedo arreglar esto?
Btw mi código se basa en este ejemplo: https://gist.github.com/mattdesl/6076846
También he leído esto: https://github.com/mattdesl/lwjgl-basics/wiki/LibGDX-Masking
- Compatibilidad de Open GL 2.0 vs 1.1 en Android
- ¿Puede OpenGL ES renderizar texturas de dimensiones no básicas 2?
- EglCreateWindowSurface falla con java.lang.IllegalArgumentException
- Android GLSurfaceView con fondo dibujable
- Aplicación de efectos en el video que se está reproduciendo
- Android Canvas o Open GL ES para el juego 2d?
- Android GLSurfaceView
- Integración de jPCT con Vuforia / SDK de QCAR
Finalmente lo hice con shaders.
Mi código se basa en este tutorial: https://github.com/mattdesl/lwjgl-basics/wiki/ShaderLesson4
private SpriteBatch spriteBatch; private FrameBuffer frmBuff; private TextureRegion frm; private OrthographicCamera frmCam; private FrameBuffer maskBuff; private TextureRegion msk; int frmSizeX = 500; int frmSizeY = 700; private ShapeRenderer renderer; private ShaderProgram shader; public static final int MASK_OFFSET_X = 55 - (int) Constants.BACKGROUND_OFFSET_X - 8; public static final int MASK_OFFSET_Y = 150; Texture tex0; Texture mask; SpriteBatch myBatch; final String VERT = "attribute vec4 "+ShaderProgram.POSITION_ATTRIBUTE+";\n" + "attribute vec4 "+ShaderProgram.COLOR_ATTRIBUTE+";\n" + "attribute vec2 "+ShaderProgram.TEXCOORD_ATTRIBUTE+"0;\n" + "uniform mat4 u_projTrans;\n" + " \n" + "varying vec4 vColor;\n" + "varying vec2 vTexCoord;\n" + "void main() {\n" + " vColor = "+ShaderProgram.COLOR_ATTRIBUTE+";\n" + " vTexCoord = "+ShaderProgram.TEXCOORD_ATTRIBUTE+"0;\n" + " gl_Position = u_projTrans * " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" + "}"; final String FRAG = //GL ES specific stuff "#ifdef GL_ES\n" // + "#define LOWP lowp\n" // + "precision mediump float;\n" // + "#else\n" // + "#define LOWP \n" // + "#endif\n" + // "varying LOWP vec4 vColor;\n" + "varying vec2 vTexCoord;\n" + "uniform sampler2D u_texture;\n" + "uniform sampler2D u_texture1;\n" + "uniform sampler2D u_mask;\n" + "void main(void) {\n" + " //sample the colour from the first texture\n" + " vec4 texColor0 = texture2D(u_texture, vTexCoord);\n" + "\n" + " //sample the colour from the second texture\n" + " vec4 texColor1 = texture2D(u_texture1, vTexCoord);\n" + "\n" + " //get the mask; we will only use the alpha channel\n" + " float mask = texture2D(u_mask, vTexCoord).a;\n" + "\n" + " //interpolate the colours based on the mask\n" + " gl_FragColor = vColor * mix(texColor0, texColor1, mask);\n" + "}"; public SprayRenderer(ShapeRenderer renderer) { super(); this.renderer = renderer; ShaderProgram.pedantic = false; spriteBatch = new SpriteBatch(); tex0 = new Texture(Gdx.files.internal("snowman_back.png")); mask = new Texture(Gdx.files.internal("balwan_maska.png")); maskBuff = new FrameBuffer(Format.RGBA8888, frmSizeX, frmSizeY, false); msk = new TextureRegion(maskBuff.getColorBufferTexture()); frmBuff = new FrameBuffer(Format.RGBA8888, frmSizeX, frmSizeY, false); frm = new TextureRegion(frmBuff.getColorBufferTexture()); frmCam = new OrthographicCamera(frmSizeX, frmSizeY); frmCam.translate(frmSizeX / 2, frmSizeY / 2); frmCam.update(); renderer.setProjectionMatrix(frmCam.combined); frmBuff.begin(); Gdx.gl.glClearColor(0, 0, 0, 0); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); frmBuff.end(); SpriteBatch batch = new SpriteBatch(); frmCam.update(); batch.setProjectionMatrix(frmCam.combined); maskBuff.begin(); Gdx.gl.glClearColor(0, 0, 0, 0); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); batch.begin(); batch.draw(mask, 0, 0, 0, 0, 500, 700, 1, 1, 0, 0, 0, 500, 700, false, true); batch.end(); maskBuff.end(); shader = new ShaderProgram(VERT, FRAG); if (!shader.isCompiled()) { System.err.println(shader.getLog()); System.exit(0); } if (shader.getLog().length()!=0) System.out.println(shader.getLog()); shader.begin(); shader.setUniformi("u_texture1", 1); shader.setUniformi("u_mask", 2); shader.end(); //bind mask to glActiveTexture(GL_TEXTURE2) msk.getTexture().bind(2); //bind dirt to glActiveTexture(GL_TEXTURE1) // tex1.bind(1); frm.getTexture().bind(1); //now we need to reset glActiveTexture to zero!!!! since sprite batch does not do this for us Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0); } @Override public void draw(Batch batch, float parentAlpha) { batch.flush(); batch.setShader(shader); batch.draw(tex0, getX() + MASK_OFFSET_X, getY() + MASK_OFFSET_Y); batch.flush(); batch.setShader(null); } }
- JavaScript createObjectURL no funciona en el navegador de Android
- GCM Enviar mensajes a Temas: TOO_MANY_TOPICS error