I am using Libgdx.
I want to simulate fog in my game using pixmap, but I have a problem during generating the "fogless" circle. First, I make a pixmap, filled with black (it is transparent a little bit). After filling I want to draw a filled circle onto it, but the result is not that I expected.
this.pixmap = new Pixmap(640, 640, Format.LuminanceAlpha);
Pixmap.setBlending(Blending.None); // disable Blending
this.pixmap.setColor(0, 0, 0, 0.9f);
this.pixmap.fill();
//this.pixmap.setColor(0, 0, 0, 0);
this.pixmap.fillCircle(200, 200, 100);
this.pixmapTexture = new Texture(pixmap, Format.LuminanceAlpha, false);
In the procedure render()
public void render() {
mapRenderer.render();
batch.begin();
batch.draw(pixmapTexture, 0, 0);
batch.end();
}
If I use Format. Alpha when creating the Pixmap and Texture, I neither see the more translucent circle.
Here is my problem:
Problem
Could somebody help me? What should I do, what should I init before to draw a full transparent circle? Thanks.
UPDATE
I have found the answer for my problem. I have to disable blending to avoid the problem.
Now my code:
FrameBuffer fbo = new FrameBuffer(Format.RGBA8888, 620, 620, false);
Texture tex = EnemyOnRadar.assetManager.get("data/sugar.png", Texture.class);
batch.begin();
// others
batch.end();
fbo.begin();
batch.setColor(1,1,1,0.7f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw( tex, 100, 100);
batch.end();
fbo.end();
But I don't see the circle (it's a png image, represents transparent bg, white filled circle).
I am not sure if this works for you but i just share it:
You could use FrameBuffers and do the following:
Draw everything you want to draw on screen.
End your SpriteBatch and begin your FrameBuffer, begin the SpriteBatch again.
Draw the Fog, which fills the whole "screen" (FrameBuffer) with a black, non transparent color.
Draw the "Fogless" circle as a white circle, at the position you want to delete the fog.
Set the FrameBuffers alpha channel (transparancy) to 0.7 or something like that.
End the SpriteBatch and the FrameBuffer to draw it to screen.
What happens? You draw the normal scene, without fog. You create a "virtual screen", fill it with black and overdraw the black with a white circle. Now you set a transparacy to this "virtual screen" and overdraw your real screen with it. The part of the screen, which is under the white circle seems to be bright, while the black rest makes your scene darker.
Something to read: 2D Fire effect with libgdx, more or less the same as fog.
My question to this: Libgdx lighting without box2d
EDIT: another Tutorial.
Let me know if it helps!
EDIT: Some Pseudocode:
In create:
fbo = new FrameBuffer(Format.RGBA8888, width, height, false);
In render:
fbo.begin();
glClearColor(0f, 0f, 0f, 1f); // Set the clear color to black, non transparent
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); // Clear the "virtual screen" with the clear color
spriteBatch.begin(); // Start the SpriteBatch
// Draw the filled circles somehow // Draw your Circle Texture as a white, not transparent Texture
spriteBatch.end(); // End the spritebatch
fbo.end(); // End the FrameBuffer
spriteBatch.begin(); // start the spriteBatch, which now draws to the real screen
// draw your textures, sprites, whatever
spriteBatch.setColor(1f, 1f, 1f, 0.7f); // Sets a global alpha to the SpriteBatch, maybe it applies alo to the stuff you have allready drawn. If so just call spriteBatch.end() before and than spriteBatch.begin() again.
spriteBatch.draw(fbo, 0, 0); // draws the FBO to the screen.
spriteBatch.end();
tell me if it works
Related
This problem seemed very obvious for me to solve, but whatever I try, it doesn't work. What I'm trying to do is to incorporate a mini-version of my PlayScreen in a ScrollPane as a tutorial where you can read text and try it out immediately.
Because I didn't find any better solution to add this to the Table inside the ScrollPane, I edited the draw() method of the PlayScreen to take the ScrollPane.getScrollPercentY() and offset the camera of the PlayScreen accordingly.
What I want to do now is to only render only part of the viewport that would be normally visible in the real game. Subsequently, I want to be able to control the size and position of this "window".
I also want to be able to resize and move the content, while cutting off the edges that are not visible to the camera. This is what I tried inside the PlayScreenDraw:
public void draw(final float yOffset,
final int xTiles,
final int yTiles) {
view.getCamera().position.y = yTiles / 2f - yOffset * yTiles / HEIGHT; // HEIGHT = 800
view.getCamera().position.x = xTiles / 2f;
view.setWorldSize(xTiles, yTiles); //Do i even need to change the world size?
b.setProjectionMatrix(view.getCamera().combined);
b.begin();
...
b.end();
view.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
What this gives me, in terms of the picture above, is this
How do I need to change the viewport and/or the camera? Btw., this is how i set the two up:
cam = new OrthographicCamera();
cam.setToOrtho(false, WIDTH, HEIGHT); // WIDTH = 8, HEIGHT = 16
batch.setProjectionMatrix(cam.combined);
view = new FitViewport(WIDTH, HEIGHT, cam);
The Pixmap class can help you achieve what you want since you stated that you wanted to "cut off" the parts outside of the green selection box.
You need to render what the camera sees to an FBO and then get the pixmap from the FBO itself.
Framebuffer Objects are OpenGL Objects, which allow for the creation of user-defined Framebuffers. With them, one can render to non-Default Framebuffer locations, and thus render without disturbing the main screen.
-- OpenGL wiki
// Construct an FBO and keep a reference to it. Remember to dispose of it.
FrameBuffer fbo = new FrameBuffer(Format.RGBA8888, width, height, false);
public void render() {
//Start rendering to the fbo.
fbo.begin();
//From the camera's perspective.
batch.setProjectionMatrix(camera.combined);
batch.begin();
//Draw whatever you want to draw with the camera.
batch.end();
// Finished drawing, get pixmap.
Pixmap pixmap = ScreenUtils.getFrameBufferPixmap(0, 0, width, height);
//Stop drawing to your fbo.
fbo.end();
}
After getting the pixmap you can iterate through the pixels and set the alpha of the pixels outside your green selection window to 0 making them invisible or "cutting them off"
I'm working on a game which requires me to dynamically generate cards with text on them . To achieve this I am attempting to render a generic card background and some text to a frame buffer then create a TextureRegion from this for use as a Sprite.
My current attempt creates some rather...unexpected results:
The large, colorful image above is what the sprite returned by the below function looks like. The image being rendered is actually the full spritesheet that the texture atlas is loading a sprite from.
The second image (which is the expected result) is the content of the PNG screenshot generated from the pixmap towards the end of the function.
I can confirm that the TextureRegion generated in the function is being used because changing the parameters of fboRegion.flip() does affect the resulting sprite.
private Sprite generateCard(String text, TextureAtlas atlas){
//Create and configure font
BitmapFont font = new BitmapFont();
font.setColor(Color.RED);
//Create a SpriteBatch (Temporary, need to pass this in later)
SpriteBatch sb = new SpriteBatch();
//Create sprite from texture atlas
Sprite sprite = atlas.createSprite("back", 3);
//Create FrameBuffer
FrameBuffer fbo = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
//Extract Texture from FrameBuffer
TextureRegion fboRegion = new TextureRegion(fbo.getColorBufferTexture());
//Flip the TextureRegion
fboRegion.flip(false, true);
//Begin using the FrameBuffer (disable drawing to the screen?)
fbo.begin();
//Clear the FrameBuffer with transparent black
Gdx.gl.glClearColor(0f, 0f, 0f, 0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
sb.begin();
//Draw card background
sb.draw(sprite, 0,0, sprite.getWidth(), sprite.getHeight());
//Draw card text
font.draw(sb, text, 20, 100);
sb.end();
//Take "Screenshot" of the FrameBuffer
Pixmap pm = ScreenUtils.getFrameBufferPixmap(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
PixmapIO.writePNG(new FileHandle("screenshot.png"), pm);
fbo.end();
sb.dispose();
fbo.dispose();
return new Sprite(fboRegion);
}
If anyone has any suggestions I'd greatly appreciate the help. I feel like something is just happening in the wrong order but I can't for the life of me see where the FrameBuffer could be getting the Image it is rendering from or why the returned sprite has the wrong image but dumping the FrameBuffer to a PNG gives the the right image.
So after a fair bit of extra experimentation I've found out the above code is working exactly as intended. I have managed to track the issue down to some other code which is taking the dimensions and position of the sprite but rendering a different texture (hence the flipping when I changed the texture region).
Thanks to those that checked out my question.
I am trying to draw a bunch of tiles (10,000 sprites) for a minimap. It lags on android when drawing individually, so I am trying to use a framebuffer. For some reason, I can't get anything drawn to the screen with the buffer. I will show the relevant code.
buffer = new FrameBuffer(Pixmap.Format.RGBA8888, Main.VIRTUAL_WORLD_WIDTH, Main.VIRTUAL_WORLD_HEIGHT, false);
OrthographicCamera cam = new OrthographicCamera(Main.VIRTUAL_WORLD_WIDTH, Main.VIRTUAL_WORLD_HEIGHT);
buffer.begin();
batch.begin();
batch.setProjectionMatrix(cam.combined);
for(Tile[] tiles : world.level.getGrid()){
for(Tile tile : tiles){
tile.getSprite().draw(batch);
}
}
batch.end();
buffer.end();
tiles = new Sprite(buffer.getColorBufferTexture());
The above code creates the framebuffer in the create method.
And this renders
batch.setProjectionMatrix(camera.combined);
batch.begin();
tiles.draw(batch);
batch.end();
Note, The position of the tiles sprite is 0, 0. I have tried changing all kids of stuff with this code, but can never get it to draw on the screen. The actual tiles aren't a problem, they all function correctly. My camera is setup correctly, so are my viewports.
Ok I have this code
#Override
public void render() {
// do not update game world when paused
if (!paused) {
// Update game world by the time that has passed
// since last render frame
worldController.update(Gdx.graphics.getDeltaTime());
}
// Sets the clear screen color to: Cornflower Blue
Gdx.gl.glClearColor(0x64/255.0f, 0x95/255.0f, 0xed/255.0f,
0xff/255.0f);
// Clears the screen
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// Render game world to screen
worldRenderer.render();
}
And it draws a light blue background onto the screen. I am attempting to create a gradient that goes from a dark blue at the top, to a light blue towards the bottom. Is there a simple way to do this? I'm new to Libgdx, and OpenGL so i'm trying to learn from a book but I can't seem to find the answer to this one. I've heard of drawing a big square and having the vertices different colors, but I'm unsure of how to do this.
In libGDX, the ShapeRenderer object contains a drawRect() method that takes arguments for its position and size as well as four colors. Those colors are converted to a 4-corners gradient. If you want a vertical gradient, just make the top corners one color and the bottom corners another color. Something like this:
shapeRenderer.filledRect(x, y, width, height, lightBlue, lightBlue, darkBlue, darkBlue);
From the API for ShapeRenderer:
The 4 color parameters specify the color for the bottom left, bottom right, top right and top left corner of the rectangle, allowing you to create gradients.
It seems ShapeRenderer.filledRect method has been removed in late libGDX versions. Now the way to do this is as follows:
shapeRenderer.set(ShapeRenderer.ShapeType.Filled);
shapeRenderer.rect(
x,
y,
width,
height,
Color.DARK_GRAY,
Color.DARK_GRAY,
Color.LIGHT_GRAY,
Color.LIGHT_GRAY
);
The parameters for rect method work in the same way as those in filledRect used to do, like in Kevin Workman answer.
There are some further details worth bearing in mind before comitting to ShapeRenderer. I for one will be sticking with stretching and tinting Texture.
private Color topCol = new Color(0xd0000000);
private Color btmCol = new Color(0xd0000000);
#Override
public void render(float delta) {
...
batch.end(); //Must end your "regular" batch first.
myRect.setColor(Color.YELLOW); // Must be called, I don't see yellow, but nice to know.
myRect.begin(ShapeRenderer.ShapeType.Filled); //Everyone else was saying call `set`.
//Exception informed me I needed `begin`. Adding `set` after was a NOP.
myRect.rect(
10, 400,
//WORLD_H - 300, // WORLD_H assumed 1920. But ShapeRenderer uses actual pixels.
420,
300,
btmCol, btmCol, topCol, topCol
);
myRect.end();
I was hoping to change transparency dynamically as player health declines. The btmCol and topCol had no effect on transparency, hence I'll stick to Textures. Translating pixel space is no biggie, but this is much more than the proferred single or double line above.
I am attempting to make dynamic 2D shadows in my game.
I'm successfully able to render the shadows to a frame buffer. (grey and white squares designate transparency)
Then for debug purposes, I render the contents of the frame buffer on top of another frame buffer which is cleared white every frame, and then render this frame on my game. This works just fine... as long as I render the shadows with 100% opaqueness:
But if I do this before drawing the shadows on the second framebuffer,
spriteBatch.setColor(0f, 0f, 0f, 0.5f);
The transparent shadows tear through the framebuffer and you can see the game world underneath.
Here's my code:
public class Light
{
FrameBuffer shadowbuffer; // for rendering shadows
FrameBuffer buffer; // for debug
OrthographicCamera cam;
public Light(Images images)
{
shadowbuffer = new FrameBuffer(Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
buffer = new FrameBuffer(Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
cam = new OrthographicCamera(buffer.getWidth(), buffer.getHeight());
cam.setToOrtho(true);
cam.update();
}
public Texture render(SpriteBatch batch, GameWorld world)
{
batch.end();
batch.setProjectionMatrix(cam.combined);
shadowbuffer.begin();
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
batch.begin();
// ... render shadows here ...
batch.end();
shadowbuffer.end();
buffer.begin();
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
batch.begin();
batch.setColor(0f, 0f, 0f, .5f);
batch.draw(shadowbuffer.getColorBufferTexture(), 0, 0);
batch.setColor(Color.WHITE);
batch.end();
buffer.end();
batch.begin();
return buffer.getColorBufferTexture();
}
}
I've tried all sorts of different blending settings, but none of them work..
EDIT Here are the blend settings I'm currently using:
batch.enableBlending();
batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Do not clear you shadowbuffer to black, clear it to transparent and draw your shadows with black color. Also don't forget to choose right blending function. If you use this method, your parameters will be like
spritebatch.enableBlending();
spritebatch.setBlendFunction(gl.BLEND_SRC_ALPHA,gl.BLEND_ONE_MINUS_SRC_ALPHA);