I am using a FrameBuffer to rasterize several TextureRegions in a single TextureRegion, to be drawn on an Image/Actor afterwards.
The constructor of a FrameBuffer is the following:
FrameBuffer(Pixmap.Format format, int width, int height, boolean hasDepth)
I found that if I put Gdx.graphics.getWidth()/getHeight() as the width and height parameters in the constructor the image is drawn correctly, but if I put something else (like the rasterized texture size) the texture is way smaller and is pixelated if I increase the size. Have I missed something ?
TextureRegion initialTexture = getTexture();
// And other textures, which are not shown here for better readability
FrameBuffer frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, (int)initialTexture.getRegionWidth(), (int)initialTexture.getRegionHeight(), false);
Batch batch = new SpriteBatch();
// Adding these lines did the trick
Camera camera = new OrthographicCamera(frameBuffer.getWidth(), frameBuffer.getHeight());
camera.position.set(frameBuffer.getWidth() / 2, frameBuffer.getHeight() / 2, 0);
camera.update();
batch.setProjectionMatrix(camera.combined);
frameBuffer.begin();
batch.enableBlending();
Gdx.gl.glBlendFuncSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glClearColor(1, 1, 1, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.setColor(TAPColor.TAP_WHITE);
batch.draw(initialTexture, 0, 0);
// Also draw other textures
batch.end();
frameBuffer.end();
TextureRegion finalTexture = new TextureRegion(frameBuffer.getColorBufferTexture());
Image image = new Image(finalTexture);
image.setSize(finalTexture.getRegionWidth(), finalTexture.getRegionHeight());
image.setPosition(0, 0);
addActor(image);
I had some problems too, one thing that made it simple was:
Matrix4 projection = new Matrix4();
projection.setToOrtho2D(0, 0, 32, 48);
batch.setProjectionMatrix(projection);
I'm trying to render self-transparent textures to the framebuffer, but I'm getting not what I guessed: everything previously rendered on the framebuffer gets ignored, and this texture blends with the colour I cleaned my main canvas.
That's what I would like to get, but without using framebuffers:
package test;
import com.badlogic.gdx.*;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.*;
public class GdxTest extends ApplicationAdapter {
SpriteBatch batch;
Texture img;
#Override
public void create () {
batch = new SpriteBatch();
Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
pixmap.setColor(1, 1, 1, 1);
pixmap.fillRectangle(0, 0, 1, 1);
// Generating a simple 1x1 white texture
img = new Texture(pixmap);
pixmap.dispose();
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.setColor(1, 1, 1, 1);
batch.draw(img, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.setColor(0, 0, 0, 0.5f);
batch.draw(img, 0, 0, 300, 300);
batch.end();
}
}
And it works as perfectly as it should do:
http://i.stack.imgur.com/wpFNg.png
And that's what I get with using of framebuffer (I can't understand why the second rendered texture doesn't blend with the previous one, as it do without framebuffer):
package test;
import com.badlogic.gdx.*;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.*;
import com.badlogic.gdx.graphics.glutils.*;
public class GdxTest extends ApplicationAdapter {
SpriteBatch batch;
Texture img;
FrameBuffer buffer;
TextureRegion region;
#Override
public void create () {
batch = new SpriteBatch();
Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
pixmap.setColor(1, 1, 1, 1);
pixmap.fillRectangle(0, 0, 1, 1);
// Generating a simple 1x1 white texture
img = new Texture(pixmap);
pixmap.dispose();
// Generating a framebuffer
buffer = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
region = new TextureRegion(buffer.getColorBufferTexture());
region.flip(false, true);
}
#Override
public void render () {
// Filling with red shows the problem
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
buffer.begin();
batch.begin();
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setColor(1, 1, 1, 1);
batch.draw(img, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.setColor(0, 0, 0, 0.5f);
batch.draw(img, 0, 0, 300, 300);
batch.end();
buffer.end();
batch.begin();
batch.setColor(1, 1, 1, 1);
batch.draw(region, 0, 0);
batch.end();
}
}
And an unpredictable result:
http://i.stack.imgur.com/UdDKD.png
So how could I make the framebuffer version work the way the first version does? ;)
The easy answer is to disable blending when rendering to the screen.
But I think it is good to understand why this is happening if you want to use FBO. So let's walk through what's actually going on.
First make sure to understand what the color of the texture and the color of the batch (the vertex color) does: they are multiplied. So when setting the batch color to 0,0,0,0.5 and the texture pixel (texel) is 1,1,1,1 this will result in a value of 1*0,1*0,1*0,1*0.5 = 0,0,0,0.5.
Next make sure to understand how blending works. Blending is enabled by default and will use the SRC_ALPHA and ONE_MINUS_SRC_ALPHA functions. This means that the source value (the texel) is multiplied by the source alpha and that the destination value (the screen pixel) is multiplied by one minus the source alpha. So if your screen pixel has the value 1,1,1,1 and your texel has the value 0,0,0,0.5 then the screen pixel will be set to:(0.5*0, 0.5*0, 0.5*0, 0.5*0.5) + ((1-0.5)*1, (1-0.5)*1, (1-0.5)*1, (1-0.5)*1) which is (0,0,0,0.25) + (0.5, 0.5, 0.5, 0.5) = (0.5, 0.5, 0.5, 0.75).
So let's see how that works for you in your first code:
You clear the screen with 1, 0, 0, 1, in other words: every pixel of the screen contains the value 1, 0, 0, 1.
Then you render a full rectangle with each texel value 1,1,1,1, every pixel of the screen now contains the value 1, 1, 1, 1.
Then you render a smaller rectangle with each texel value 0,0,0,0.5, every pixel on that part of the screen now contains the value 0.5, 0.5, 0.5, 0.75.
Got a feeling about the issue already? Let's see what happens in your second code:
You clear the screen with 1, 0, 0, 1: every pixel of the screen contains the value 1, 0, 0, 1.
You bind the FBO and clear it with 1, 1, 1, 1: every pixel of the FBO contains the value 1, 1, 1, 1.
You render a full rectangle with each texel value 1,1,1,1 to the FBO: every pixel of the FBO now contains the value 1,1,1,1.
You render a smaller rectangle with each texel value 0,0,0,0.5, every pixel on that part of the FBO now contains the value 0.5, 0.5, 0.5, 0.75.
Then you bind the screen again as the render target of which each pixel still contains the value 1, 0, 0, 1.
Finally you render the FBO texture as full rectangle to the screen, causing these texels to be blended with the screen pixels. For the smaller rectangle this means blending 0.5, 0.5, 0.5, 0.75 multiplied by 0.75 and 1, 0, 0, 1 multiplied by 1-0.75=0.25, which will result in 0.375, 0.375, 0.375, 0.5625 and 0.25, 0, 0, 0.25. So the final color is 0.625, 0.375, 0.375, 0,8125
Make sure to understand this process, otherwise it can cause quite some frustrating weird issues. If you find it hard to follow then you could take pen and paper and manually calculate the value for each step.
I am trying to create a god's ray effect from scratch using libgdx and opengl shader langage. To do this I use a background image as light source, then I apply another texture as a mask setting the spriteBatch color to full black.
background texture
mask texture
the mask is then rendered in full black over the background
Color batchColor = batch.getColor();
fbo1.begin();
batch.begin();
batch.draw(textureBackground, 0, 0, w, h);
batch.setColor(Color.BLACK);
batch.draw(textureBar, 0, 0, w, h);
batch.setColor(batchColor);
batch.end();
fbo1.end();
then the god's ray shader is applied
Sprite rayEffect = new Sprite(fbo1.getColorBufferTexture());
rayEffect.flip(false, true);
fbo2.begin();
batch.setShader(shaderGodRay);
batch.begin();
rayEffect.draw(batch);
batch.end();
batch.setShader(null);
fbo2.end();
The rays are ok at this stage. Know I would like to blend the original mask color with the rendered rays in order to obtain the final image. Only rendering the mask again on top of the rays are totally overlapped by the colored mask
rayEffect = new Sprite(fbo2.getColorBufferTexture());
rayEffect.flip(false, true);
batch.begin();
rayEffect.draw(batch);
batch.draw(textureBar, 0, 0, w, h);
batch.end();
I think alpha blending should do the trick, but on my ray rendered image, the opacity is full.
Does someone know how I may blend the two texture together in order to obtain the desired final result?
I have a texture drawn in a GLcontrol and I want to draw points on top of it. Instead, I get the full texture set to the colour of the point I want to draw. I guess that I have to disable the texture format and enable the points drawings, but cant reach the solution...
Here is the draw function:
Basically the point to draw is ROI[0], but instead drawing just the point I got the image shown below (the image is grayscale before drawing "the point").
private: void drawImg(int img){
int w=this->glControl_create_grid->Width;
int h=this->glControl_create_grid->Height;
GL::MatrixMode(MatrixMode::Projection);
GL::LoadIdentity();
GL::Ortho(0, w, 0, h, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
GL::Viewport(0, 0, w, h); // Use all of the glControl painting area
GL::Clear(ClearBufferMask::ColorBufferBit | ClearBufferMask::DepthBufferBit);
GL::ClearColor(Color::LightGray);
GL::MatrixMode(MatrixMode::Modelview);
GL::LoadIdentity();
GL::Enable(EnableCap::Texture2D);
GL::BindTexture(TextureTarget::Texture2D, img);
OpenTK::Graphics::OpenGL::ErrorCode error=GL::GetError();
GL::Begin(BeginMode::Quads);
GL::TexCoord2(0, 0);
GL::Vertex2(0 ,h);
GL::TexCoord2(1, 0);
GL::Vertex2(w, h);
GL::TexCoord2(1, 1);
GL::Vertex2(w, 0);
GL::TexCoord2(0, 1);
GL::Vertex2(0, 0);
GL::End();
GL::Disable(EnableCap::Texture2D);
if (ROI[0].x!=0||ROI[0].y!=0){
GL::Color3(Color::Red);
GL::Begin(BeginMode::Points);
GL::Vertex2(ROI[0].x,ROI[0].y);
GL::End();
}
}
What should I change in my code? I can't seem to achieve it....
I found the answer. It seems that the color also applies to textures when binding them so I just needed to add GL::Color3(Color::White) before drawing the texture.
I have a weird problem that I have not found a solution for despite lots and lots of googling and reading.
I have a scene that uses a dynamically generated background. The code for the background is based on this tutorial and other code I have found related to that such as Haqus Tiny-Wings github.
Anyway, my code has simplified the hill generation and it is all contained in one CCNode class called StripedTerrain. It all works fine (now!) but when going to another scene that uses the same layout with the same background sprite, it doesnt render completely. See the screenshot. Image A is the first run with my code as is. Image B is after a replaceScene call to a new scene of the same scene class. Then, I made this small change to my draw code just before popping the matrix:
ccDrawColor4B(255, 255, 255, 255);
ccDrawLine(ccp(0.0,0.0),ccp(0.0,0.0));
and then it works fine (images C and D)
This is the strangest thing and I cannot figure out what's going wrong.
I'll post the draw call code, but spare you the rest of the details :
/**
* Previus to the draw method we have already done the following:
* Randomly selected, or have been given two colors to paint the stripes onto our texture
* Generated a texture to overlay on to our hill vertice geometry
* Generated the top of the hill peaks and valleys
* Generated the hill verticies that will fill in the surface of the hills
* with the texture applied
*/
- (void) draw {
CC_NODE_DRAW_SETUP();
// this statement fixed the screwed up jagged line rendering
// since we are only using position and texcoord vertexes, we have to use this shader
kmGLPushMatrix();
CHECK_GL_ERROR_DEBUG();
ccGLBlendFunc( CC_BLEND_SRC, CC_BLEND_DST ); //TB 25-08-12: Allows change of blend function
ccGLBindTexture2D(self.stripes.texture.name);
//TB 25-08-12: Assign the vertices array to the 'position' attribute
glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, _hillVertices);
//TB 25-08-12: Assign the texCoords array to the 'TexCoords' attribute
glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, _hillTexCoords);
glEnableVertexAttribArray(kCCVertexAttrib_Position);
glEnableVertexAttribArray(kCCVertexAttrib_TexCoords);
//TB 25-08-12: Draw the above arrays
glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)_nHillVertices);
CHECK_GL_ERROR_DEBUG();
//Debug Drawing (remove comments to enable)
if(0) {
for(int i = MAX(_fromKeyPointI, 1); i <= _toKeyPointI; ++i) {
ccDrawColor4B(255, 0, 0, 255);
ccDrawLine(_hillKeyPoints[i-1], _hillKeyPoints[i]);
}
for(int i =0;i<_nHillVertices;i+=3) {
ccDrawColor4B(255, 0, 0, 255);
ccDrawLine(_hillVertices[i+1], _hillVertices[i+2]);
}
}
// have to do this to force it to work the next scene load
ccDrawColor4B(255, 255, 255, 255);
ccDrawLine(ccp(0.0,0.0),ccp(0.0,0.0));
kmGLPopMatrix();
CC_INCREMENT_GL_DRAWS(1);
}
Any obvious mistakes above?
I've set the shader in another method.
Check if the previous scene and its children run their dealloc method. If not, and one or more are leaking the weirdest things can happen.
The same goes for overriding cleanup without calling super cleanup.