I've created a GLsurfaceView which renders a square according to where i press the screen.
I want it to appear above a different layout.
in order to make it transparent i call:
setEGLConfigChooser(8,8,8,8,16,0);
mRenderer = new SlidingRenderer();
setRenderer(mRenderer);
getHolder().setFormat(PixelFormat.TRANSLUCENT);
In my renderer:
public void onDrawFrame(GL10 gl){
gl.glClearColor(0, 0, 0, 0);
but it also changes the color of my drawn square and makes it appear semi-transparent as well.
BEFORE:
AFTER:
TRANSLUCENT is a vague pixel format descriptor, by its very definition the system is free to choose RGBA_4444 or RGBA_8888.
Chances are very good that the system is configured to select the minimal pixel format that satisfies your conditions. For PixelFormat.TRANSLUCENT those conditions are:
System chooses a format that supports translucency (many alpha bits)
Since you probably want to match up with your EGL pixel format, try PixelFormat.RGBA_8888 instead of PixelFormat.TRANSLUCENT.
Related
There is a need to mask or crop part of a 3D model in Libgdx by another model. Assuming the attached images, there are two boxes which I need to crop green box with red one on-the-fly (if the camera view changes the specific part should be cropped as well) and the result should be like the other image.Any help or suggestion would be appreciated.
I applied the depth buffer to mask my 3D model and it works fine. Here is my snippet code.
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl.glClearDepthf(1f);
Gdx.gl.glClear(GL20.GL_DEPTH_BUFFER_BIT);
Gdx.gl.glDepthFunc(GL20.GL_LESS);
Gdx.gl.glEnable(GL20.GL_DEPTH_TEST);
Gdx.gl.glDepthMask(true);
Gdx.gl.glColorMask(false, false, false, false);
//the mask model
modelBatch.begin(cam);
modelBatch.render(redBox);
modelBatch.end();
// the model which is masked
modelBatch.begin(cam);
Gdx.gl.glColorMask(true, true, true, true);
Gdx.gl.glEnable(GL20.GL_DEPTH_TEST);
Gdx.gl.glDepthFunc(GL20.GL_EQUAL);
modelBatch.render(greenBox);
modelBatch.end();
And special thanks to Matt DesLauriers.
I don't know the libgdx but using the Stencil buffer (if supported) could be a help. It's additional buffer that allows you to mark specific pixels with an integer value, then during the main rendering you can setup some stencil tests to decide which pixels should be discarded.
In short:
Clean Stencil buffer to 0
Draw red object only in stencil buffer, with value e.g. 1
Set stencil test to 'is zero'
Draw green object normally
This way you draw green box as usual, but ignore pixels for which stencil != 0, which means all occluded by a red box.
I would like to create an interactive 2D effect that I can put on anything. So I want to take a mostly transparent effect, render it to a texture, and put it wherever I want simply by putting it on a square.
The problem I encountered is that I can't get rid of the background color. When I put the effect over an object, the background color of the effect blocks out the object that I want to put the effect over.
Here is my code. Can anybody tell me what I'm missing?
Drawing:
GLES20.glClearColor(0.6f, 0.34f, 0.14f, 0.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
ball.draw(); //This is the object a simple square draw with 2 triangles
particleSystem.renderToTexture(); //effect rendering to texture and drawing it
The render to texture code code:
public void renderToTexture(){
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb[0]);
GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, renderTex[0], 0);
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, depthRb[0]);
int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
drawRender(); //draws the effect on a fbo and saving the texture to renderTex[0]
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, renderTex[0]);
drawEffect(); //draws a square with the effect texture on it
The problem should be here somewhere, but I have no idea what to do. I tried everything I could think of. I even triend to dispose of the background color in the shader.
The posted code looks perfectly fine. You will need to make sure that the texture you use for the color render target (renderTex[0]) has an alpha component.
Note that the number of texture formats in ES 2.0 that are guaranteed to be color-renderable is very limited. The only two with an alpha component (see table 4.5. in the spec) are GL_RGBA4 and GL_RGB5_A1. Most notably, this does not include GL_RGBA with 8 bits per component.
So for defining a color-renderable texture with alpha component that is guaranteed to work across all ES 2.0 implementations, you will have to use GL_RGBA for the internal format, and GL_UNSIGNED_SHORT_4_4_4_4 or GL_UNSIGNED_SHORT_5_5_5_1 for the type argument of glTexImage2D().
Most common devices (at least all the ones I have seen) do support the OES_rgb8_rgba8 extension, which adds support for rendering to 8 bit component textures. But if you want to be completely portable, you should check for the presence of this extension before using render targets with those formats.
I know this question is old, but i also encountered it right now and the solution for me was to do something with the GLSurfaceView. Just add these lines after setting the context
glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 0, 0);
glSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
I was already using GL_RGBA format and was really annoyed that nothing else was working, but this worked like magic.
I try to render using GLSurfaceView, and by docs I set format:
getHolder().setFormat(PixelFormat.TRANSLUCENT);
The I use GLSurfaceView.Renderer, which draws in onDrawFrame:
GLES20.glClearColor(0, 0, 1, .5f);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
However, the GL rendering in GLSurfaceView is not translucent, and is fully blue. If I omit glClear call, then it's fully black.
How do I make GL rendering to have transparent background, so that it is blended with views drawn behind it?
EDIT: here is my GLSurfaceView:
class GLView extends GLSurfaceView{
MyRenderer r;
public GLView(Context ctx){
super(ctx);
setEGLContextClientVersion(2);
getHolder().setFormat(PixelFormat.TRANSLUCENT);
setEGLConfigChooser(8, 8, 8, 8, 16, 0);
r = new MyRenderer(getContext());
setRenderer(r);
}
}
OK, after some research I can answer this myself.
I finally made it to be drawn with transparency using SurfaceView.setZOrderOnTop(true). But then I lost possibility to place other views on top of my GLSurfaceView.
I ended with two possible results:
On left is standard GL surface below all other views, which can't be drawn with transparency, because GL surface is drawn before application's window surface, and GLSurfaceView just punches hole in its location so that GL surface is seen through.
On right is transparent GL surface drawn with setZOrderOnTop(true), thus its surface is drawn on top of application window. Now it's transparent, but is drawn on top of other views placed on it in view hierarchy.
So it seems that application has one window with surface for its view hierarchy, and SurfaceView has own surface for GL, which may be on top or below of app window. Unfortunately, transparent GL view can't be ordered correctly inside view hierarchy with other views on top of it.
You need RGBA 8888 pixel format for translucency:
private void init( boolean translucent, int depth, int stencil )
{
/* By default, GLSurfaceView() creates a RGB_565 opaque surface.
* If we want a translucent one, we should change the surface's
* format here, using PixelFormat.TRANSLUCENT for GL Surfaces
* is interpreted as any 32-bit surface with alpha by SurfaceFlinger.
*/
this.getHolder().setFormat( PixelFormat.RGB_565 );
if ( translucent )
{
this.getHolder().setFormat( PixelFormat.TRANSLUCENT );
}
setEGLContextFactory( new ContextFactory() );
/* We need to choose an EGLConfig that matches the format of
* our surface exactly. This is going to be done in our
* custom config chooser. See ConfigChooser class definition
* below.
*/
setEGLConfigChooser( translucent ?
new ConfigChooser( 8, 8, 8, 8, depth, stencil ) :
new ConfigChooser( 5, 6, 5, 0, depth, stencil ) );
setRenderer( new Renderer() );
}
Have you thought about using a LayerDrawable with setAlpha? Here's an example i have of two images... one is transparent (by the setAlpha) and the other is not. The 'calendar_cell' is solid and is on the back, then comes the box which is transparent to show the calendar cell behind it. This way you can stack as many images as you want giving them all a different transparency.
Drawable []layers = new Drawable [2];
int imageResource1 = mContext.getResources().getIdentifier("drawable/calendar_cell", null, mContext.getPackageName());
Drawable background = v.getResources().getDrawable(imageResource1);
layers [0]= background;
int imageResource = mContext.getResources().getIdentifier("drawable/box_" + box, null, mContext.getPackageName());
Drawable boxImg = v.getResources().getDrawable(imageResource);
boxImg.setAlpha(100);
layers [1]= boxImg;
LayerDrawable layerDrawable = new LayerDrawable (layers);
v.setBackground(layerDrawable)
I'm not sure what the problem is exactly but an alternative could be covering the screen with a translucent colored rectangle and just clearing the depth buffer bit.
Is there any alternative for GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)?
Otherwise make sure your depth buffer bit is 1
I'll be back later to try and recreate the problem on my phone in a bit when I can.
Edit: I just realized that the reason it appears blue may be that you set it to .5f so it only takes 2 calls for it to get to full 1f opacity. meaning that it takes at 30fps 1/15th of a second to go fully blue.
Try lowering the alpha transparency value to 0.01f or 0.05f
try using setZOrderMediaOverlay(true) for the GLSurfaceView with Hardware Acceleration for the Activity set to false. That makes the GLSurfaceView background Transparent. But I am not sure how the hardware acceleration impacts it. Overlaying a GLSurface on top of a MapView without using SetZOrderTop.
I had posted a question recently still looking for a better solution
I am trying to implement fireworks with point sprites and then drawing trails by rendering the fireworks to two different textures, and then drawing them back to each other every second time with alpha set to < 1, making each previous draw fade away more and more.
It looks nice and depending on what alpha I use when drawing the previously rendered texture the trails gets longer or shorter, as expected. However, on most devices (not all) the trails never disappear completely. They leave a very transparent but still noticable trail after they should have faded away.
This is what I do currently:
depending on a boolean called second I set the framebuffer to render to one of two textures called buff1 and buff2.
((GL11ExtensionPack)gl).glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, myFBO.get(0));
if (second){
((GL11ExtensionPack)gl).glFramebufferTexture2DOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, GL11ExtensionPack.GL_COLOR_ATTACHMENT0_OES, GL10.GL_TEXTURE_2D, buff2.texture.textureId, 0);
} else {
((GL11ExtensionPack)gl).glFramebufferTexture2DOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, GL11ExtensionPack.GL_COLOR_ATTACHMENT0_OES, GL10.GL_TEXTURE_2D, buff1.texture.textureId, 0);
}
gl.glViewport(0, 0, bufferSize, bufferSize);
gl.glClearColor(0, 0, 0, 0);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
Then I render the previously drawn texture on the current one, using a alpha value < 1. The buff object is just a helper drawing a quad with a texture. The draw function premultiplies the alpha to the other color channels.
// a = alpha, higher value = longer trails = more distinct leftovers
if (second){
buff1.setColor(1, 1, 1, a);
buff1.draw(gl);
second = false;
else {
buff2.setColor(1, 1, 1, a);
buff2.draw(gl);
second = true;
}
After that I do the drawing of the point sprite fireworks. Also using premultiplied alpha and gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
Finally I reset the frame buffer and have my new texture containing the old trails fading and the current fireworks on top drawn at 100% alpha. I then use this texture to draw to my scene together with all the other objects behind and in front of the fireworks texture.
As I said, almost everything is working, except for those almost transparent trails staying after the trails should have faded. The higher the alpha value drawing the previous buffer the more noticable the trail "leftovers" that stay forever.
I have been trying with different blending modes, pre-multiplied and not pre-multiplied alpha etc. But since this is an android opengl es 1.1 I think the blending should be GL_ONE and GL_ONE_MINUS_SRC_ALPHA since all bitmaps are premultiplied by default.
What am I doing wrong? Is there a better way to do this?
Thanks for any help,
Anders
What am I doing wrong?
The way you sum downscaled (in their values) image is effectively a Power Series that exponetiate your alpha value. Such a power series will asympote to zero, but never reach it.
Is there a better way to do this?
Actually this is the right way to do it. You just forgot one last step: You want to have some threshold added, so that values below a certain alpha values get clamped to zero. Most easily this is obtained adding a GL_GREATER alpha test, with the threshold slightly above the alpha value of your trails you do want to remove.
I have a texture. It is JPEG file, with a red RGB(255,0,0) background. What is the best way, to load this texture(or show) where my RGB(255,0,0) colors be TRANSPARENT?
Well jpegs don't have a transparency channel (AFAIK) so the first thing to do is edit it in Paint.NET or whatever, use magic wand or similar to make your red pixels transparent, and save as a PNG.
At runtime you need to load the PNG from assets or resources into a Bitmap.Config.ARGB_8888 bitmap before converting to a texture.
Finally your GLSurfaceView view needs to explicitly request that it's translucent cos its opaque by default... here's what I do in my GLSurfaceView-derived constructor, before calling setRenderer():
// Make the surface transparent, which it isn't by default
setEGLConfigChooser(8, 8, 8, 8, 0, 0);
getHolder().setFormat(PixelFormat.TRANSLUCENT);