How to get a texture from a FrameBuffer?

Started by Darkflame, May 15, 2010, 08:43:06 PM

Previous topic - Next topic

Darkflame

Trying to get a texture from a framebuffer but its coming out totally transparent/unset :?


//set up font
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setTypeface(Typeface.create((String)null, Typeface.BOLD));
paint.setTextSize(16);
glFont = new GLFont(paint);


//created a new framebuffer to render the texture too
Texture textTexture = new Texture(60,60, RGBColor.BLACK);
FrameBuffer meep = new FrameBuffer(gl, 100, 100);

meep.setRenderTarget(textTexture);
meep.clear(RGBColor.BLACK);
glFont.blitString(meep, " test test test! ",
5, 5, 10, RGBColor.WHITE);
meep.display();


(that texture is then applied to a mesh, but it doesn't show up)

Probably something I'm not understanding about the process here.

EgonOlsen

There are a few things to consider:


  • The render-to-texture code of jPCT-AE is totally untested. It's a straight port from the desktop version, so it should work if Android's drivers work correctly...but as we all know, they don't. So there is a chance that it won't work even if everything else is correct.
  • Make sure that your texture has a power of two size that's smaller than the framebuffers. 60*60 isn't a good size, use 64*64 instead.
  • Make sure to remove the render target before using the texture in the actual rendering.
  • There's still a little ugliness in jPCT (both versions) when is comes to blitting: It requires that a world has been rendered at least once into the buffer to blit into. Any world will do. Try something like:


                        Texture textTexture = new Texture(64,64, RGBColor.BLACK);
FrameBuffer meep = new FrameBuffer(gl, 100, 100);
                        World tw=new World();
                        tw.renderScene(meep);
                        tw.draw(meep);
                        meep.display();

meep.setRenderTarget(textTexture);
meep.clear(RGBColor.BLACK);
glFont.blitString(meep, " test test test! ",
5, 5, 10, RGBColor.WHITE);
meep.display();


Where are you calling this? In onDrawFrame()?

Darkflame

Quote from: EgonOlsen on May 15, 2010, 10:30:35 PM

  • The render-to-texture code of jPCT-AE is totally untested. It's a straight port from the desktop version, so it should work if Android's drivers work correctly...but as we all know, they don't. So there is a chance that it won't work even if everything else is correct.
  • Make sure that your texture has a power of two size that's smaller than the framebuffers. 60*60 isn't a good size, use 64*64 instead.

Done.
I noticed I couldnt have textures of 90x90 early because it got a
"- ERROR: Can't render into a texture larger than the current framebuffer!"
error. (despite the fact the framebuffer  is specified as 100,100)
Was this because it was rounding up internally to 128x128?

Quote
  • Make sure to remove the render target before using the texture in the actual rendering.
  • There's still a little ugliness in jPCT (both versions) when is comes to blitting: It requires that a world has been rendered at least once into the buffer to blit into. Any world will do. Try something like:


                        Texture textTexture = new Texture(64,64, RGBColor.BLACK);
FrameBuffer meep = new FrameBuffer(gl, 100, 100);
                        World tw=new World();
                        tw.renderScene(meep);
                        tw.draw(meep);
                        meep.display();

meep.setRenderTarget(textTexture);
meep.clear(RGBColor.BLACK);
glFont.blitString(meep, " test test test! ",
5, 5, 10, RGBColor.WHITE);
meep.display();


Thanks for your help, but I gave that a go and still nothing/transparent. :(
Not sure where to put that meep.removeRenderTarget(); though. Is it rendered into the texture on that ".display()", and thus any time after will do?

Quote
Where are you calling this? In onDrawFrame()?

No, onSurfaceCreate() at the moment.
What I really want to do is create a texture based on some text at any point though.

My goal is to effectively make a "add marker here" function. Which, given some text, and a position, will display a billboard with the text on at that position.
So far Ive made the billboard, complete with my own rectangle object...


Now I'm trying to assign a custom texture at that point.


[attachment deleted by admin]

EgonOlsen

#3
No idea...maybe it just isn't working in the way it should because of some driver issues. It wouldn't be the first thing that is on Android. However, it's better if you can manage to render the text into an int[]-array or at least a Bitmap anyway. With both, you can create (Bitmap) or update (int[] via an ITextureEffect, the prefered way) a texture and use that as texture for your billboard. Raft's GlFont class creates textures with those letters too, so it may help as a starting point.

raft

Quote
Quote
Where are you calling this? In onDrawFrame()?
No, onSurfaceCreate() at the moment.
i would definitely try running it in onDrawFrame() in this case..

Darkflame

Wouldn't that recreate the texture each frame :?
Seems a bit wasteful.
The thing I'm doing the texture might be updated but certainly not every frame.
Basically the AddPlacemark(X,Y,"any text goes here") will be triggered a lot as the programs loading, then maybe once or twice after its already loaded.
Mostly the textures will be just like any other texture when created.

Quoteno idea...maybe it just isn't working in the way it should because of some driver issues. It wouldn't be the first thing that is on Android. However, it's better if you can manage to render the text into an int[]-array or at least a Bitmap anyway. With both, you can create (Bitmap) or update (int[] via an ITextureEffect, the prefered way) a texture and use that as texture for your billboard. Raft's GlFont class creates textures with those letters too, so it may help as a starting point.

I must admit I dont have any idea how to use a ITextureEffect.

I did get it working by just using Canvas to make a bitmap;
paint.setColor(Color.BLACK);
Bitmap.Config config = Bitmap.Config.ARGB_8888;
FontMetricsInt fontMetrics = paint.getFontMetricsInt();
int fontHeight = fontMetrics.leading - fontMetrics.ascent + fontMetrics.descent;
int baseline = -fontMetrics.top;
int height = fontMetrics.bottom - fontMetrics.top;

Bitmap charImage = Bitmap.createBitmap(closestTwoPower((int)paint.measureText(text)+10), 64, config);

Canvas canvas = new Canvas(charImage);
canvas.drawColor(Color.WHITE);
canvas.drawText(text, 10, baseline, paint); //draw text with a margin of 10

TextureManager tm = TextureManager.getInstance();

Texture testtext = new Texture(charImage);

tm.addTexture("testText2", testtext);


Is there anything specificly wrong with this method? Bad for performance?



raft

Quote from: Darkflame on May 17, 2010, 07:02:26 PM
Wouldn't that recreate the texture each frame :?
Seems a bit wasteful.
i mean trying display on onDrawFrame() of course ;)

Darkflame

So having my "meep.display();" in the onDrawFrame(), and everything else where it is? ('save for meeps declaration of course).
--

Ok, I found what was wrong with just using my method above, the text comes out transparent, and the texture never gets updated even if I use replacetexture :P

EgonOlsen

Quote from: Darkflame on May 17, 2010, 08:48:58 PM
Ok, I found what was wrong with just using my method above, the text comes out transparent, and the texture never gets updated even if I use replacetexture :P
I'm a bit lost now...which method are you talking about? The Canvas-solution you've posted above? And that thing does work...or not (?) and what has replaceTexture to do with it?

Darkflame

Sorry,The canvas solution works, as in, it appears on the object perfectly after that code is run.

However it has a few problems;

a) if I then trigger the same code again with a different string, the old texture remains on the object.
(this is where I tried "tm.replaceTexture("testText2", testtext);" rather then "addTexture" if the texture already had been put
on it once, but it had no effect).


b) The other problem is the texture comes out with the text being transparent, but on a white background. So you can see the camera view though the text itself;


paint.setColor(Color.BLACK); doesn't seem to help.







[attachment deleted by admin]

EgonOlsen

#10
I can't verify a)...it works just fine in a test case of mine. Can you post the code snippet that you use to do this? In addition, make sure to call TextureManager.unload(...) for the old texture before replacing it, because otherwise, it will stay in GPU's memory forever. However, this shouldn't prevent the texture from changing.

b) is actually a feature of jPCT as it converts all black parts of a texture to transparent. If you don't want this, either use a color above #0f0f0f for the text or try new Texture(yourBitmap, true); so that the alpha channel isn't calculated based on the pixel data but on the channel that the bitmap contains. You just have to make sure that it doesn't contain one in your example. Another option is to leave everything as it is and call texture.removeAlpha() after creating the texture.

Darkflame

Quote from: EgonOlsen on May 18, 2010, 08:41:38 PM
I can't verify a)...it works just fine in a test case of mine. Can you post the code snippet that you use to do this? In addition, make sure to call TextureManager.unload(...) for the old texture before replacing it, because otherwise, it will stay in GPU's memory forever. However, this shouldn't prevent the texture from changing.

I fixed the problem, it was a daft error of mine where the code I thought was being triggered wasn't.
Added the unload too, thanks for the advice.

Quote
b) is actually a feature of jPCT as it converts all black parts of a texture to transparent. If you don't want this, either use a color above #0f0f0f for the text or try new Texture(yourBitmap, true); so that the alpha channel isn't calculated based on the pixel data but on the channel that the bitmap contains. You just have to make sure that it doesn't contain one in your example. Another option is to leave everything as it is and call texture.removeAlpha() after creating the texture.

Bingo. That worked a charm.
I used the "true" flag as I will probably want to use my own alpha later.