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);
Related
I have a problem with skybox textures. If you twist the camera, it creates a feeling that one texture overlays another, as in the screenshot:
Skybox show code:
private void drawSkybox(int texId){
glColor4f(1,1,1,1);
glDepthMask(false);
glEnable(GL_TEXTURE_CUBE_MAP);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, texId);
glBindVertexArray(vao[0]);
glBindBuffer (GL_ARRAY_BUFFER, vbo[0]);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glBindBuffer (GL_ARRAY_BUFFER, 0);
glDepthMask(true);
glDisable(GL_TEXTURE_CUBE_MAP);
}
My opengl paramters:
glEnable(GL_ALPHA_TEST);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glEnable(GL_NORMALIZE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_SMOOTH);
glColorMask (true, true, true, true);
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
And my call drawSkybox:
glViewport(0, 0, WIDTH, HEIGHT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-max, max, -1, 1, 10, -10);
glRotated(cameraX, 1f, 0f, 0);
glRotated(cameraY, 0f, 1f, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
drawSkybox(texId);
How i can fix the problem?
I understand that the problem is glDepthMask(false); but how can it be replaced?
If I just remove glDepthMask(false); and replace it with an example with glDepthFunc(GL_LEQUAL); and glDepthFunc(GL_LESS); then the skybox will overlap all other objects and only it will be visible –
Do not change the depth mask or the depth test when you draw the skybox. Keep the depth test function GL_LESS.
private void drawSkybox(int texId){
glColor4f(1,1,1,1);
// glDepthMask(false); <---- DELETE
// [...]
}
But clear the depth buffer again, after drawing the skybox. Draw the skybox first, then the skybox covers the entire screen. Then clear the depth buffer, thus all objects which are draw after, will cover the skybox:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// [...]
drawSkybox(texId);
glClear(GL_DEPTH_BUFFER_BIT);
// render other objects
// [...]
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 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
I am making a platformer which I started developing with default java functions, but now am switching to OpenGL for everything. I have done everything like I always do with OpenGL, and what I did works fine in my other OpenGL projects. Now my problem is that LWJGL/OpenGL is scaling my textures in a very strange way.
It seems to be related to my screen's aspect ratio. (8:5)
I already had to flip the screen to make it the right way round, but as you can see the text is working fine, it's just the textured rect, and it isn't even straight on the bottom.
Here are the most important snippets from the two classes which actually use OpenGL:
Metamorph.java (main class)
public static void initGL()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, Display.getWidth(), 0, Display.getHeight(), 1, -1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glMatrixMode(GL_MODELVIEW);
glClearColor(0, 0, 0, 1);
glDisable(GL_DEPTH_TEST);
}
public void render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glScalef(1.0f, -1.0f, 1.0f);
glTranslatef(0f, -720f, 0f);
//glScalef(1280f/800, 720f/500, 1f);
renderer.render();
Display.update();
Display.sync(60);
}
Renderer.java (rendering stuff)
private void renderMainMenuWithGL()
{
//System.out.println("Main Menu!");
glColor4f(1, 1, 1, 1);
try
{
Texture bg = loadTexture("mockery");
bg.bind();
} catch (Exception e)
{
e.printStackTrace();
}
//drawQuad(0, 0, 1280, 720, 0, 0, 1280, 720);
glPushMatrix();
{
glBegin(GL_QUADS);
glTexCoord2f(0, 0);glVertex2f(0, 0);
glTexCoord2f(0, 1);glVertex2f(0, 720);
glTexCoord2f(1, 1);glVertex2f(1280, 720);
glTexCoord2f(1, 0);glVertex2f(1280, 0);
glEnd();
}
glPopMatrix();
TrueTypeFont f = loadFont(MAINFONT, Font.PLAIN, 50);
TrueTypeFont fb = loadFont(MAINFONT, Font.PLAIN, 48);
int sel = -1;
if(Mouse.getX() > 1000 && Mouse.getX() < 1240 && Mouse.getY() > 282.5F && Mouse.getY()< 737.5F)
sel = Math.round((Mouse.getY() - 337.5F)/75F);
if(sel == 0)
drawStringRight(fb, 1240, 350, "Story", new Color(0xff516b6b));
else
drawStringRight(f, 1240, 350, "Story", new Color(0xff516b6b));
}
private void drawStringRight(TrueTypeFont f, int x, int y, String s, Color c)
{
glPushMatrix();
f.drawString(x-f.getWidth(s), y, s, c);
glPopMatrix();
}
I am also open to advice on file structure/what I did wrong elsewhere, but keep in mind this is heavily WIP
The only possible problem I can see from what you have posted is the scaling and translating you are doing prior to rendering. You should not need to do this with your projection matrix setup the way it is. Other possibilities are that either the dimensions are not really 1280x720 as you think or you have modified one of the matrices further in the code you have not posted. I would try setting both the modelview and projection matrices to the identity matrix and then use glOrtho as you have above immediatly before drawing your quad, and use Display.getWidth and Display.getHeight instead of 1280/720 for the vertex coords.
This works fine for me:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, Display.getWidth(), 0, Display.getHeight(), 1, -1);
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex2i(0, 0);
glTexCoord2f(1,0);
glVertex2i(Display.getWidth(), 0);
glTexCoord2f(1,1);
glVertex2i(Display.getWidth(), Display.getHeight());
glTexCoord2f(0,1);
glVertex2i(0, Display.getHeight());
glEnd();
If this still doesnt work, make sure that the viewport is also set to the entire display: glViewport(0,0,Display.getWidth(),Display.getHeight()).
Aswell, I notice that you are using glPushMatrix() and glPopMatrix before and after drawing, which does nothing and is not needed. Push and pop are used to save the current projection or modelview matrix and then reload it later, so that you can apply transformations inbetween and undo them when needed.
You're setting the projection matrix such that the coordinates of the corners of the window are (0,0) through (1680, 1050), and those are mapped into an area that covers 1280x800 pixels. Then you're drawing a 1280x720 image into it, so the screen coordinates of the image come out to span only 800x500 pixels. If you use 1280x720 in your glOrtho() call, I believe it will fix the issue. That is, you want the size of the window, not the size of the display in that call.
For some reason enabling alpha blending results in me not being able to draw run-of-the-mill coloured shapes. The order in which everything is drawn makes no difference. Even if the only thing being drawn is the coloured shape, it still won't show.
Disabling alpha blending fixes this, but disables alpha blending (obviously). This leads me to believe the problem is in how I'm initializing openGL.
The textured objects are contained in the world, which is commented out. Commenting "world.run();" out makes no difference, only disabling alpha blending does.
public class Core {
int width=800, height=600;
//World world;
public void Start(){
try {
Display.setDisplayMode(new DisplayMode(width,height));
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
System.exit(0);
}
initGL();
System.out.println("OpenGL version: " + GL11.glGetString(GL11.GL_VERSION));
boolean Close = Display.isCloseRequested();
//world = new World(width, height);
while(!Close){
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
if(Keyboard.isKeyDown(Keyboard.KEY_ESCAPE) || Display.isCloseRequested())
Close = true;
//world.run();
GL11.glColor4d(1, 0, 0, 1);
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2d(0, 0);
GL11.glVertex2d(0, 50);
GL11.glVertex2d(50, 50);
GL11.glVertex2d(50, 0);
GL11.glEnd();
Display.update();
//Display.sync(60);
}
}
public void initGL(){
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
// enable alpha blending
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glViewport(0,0,width,height);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, width, height, 0, 1, -1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
}
public static void main(String args[]){
Core m = new Core();
m.Start();
}
}
This is for a 2D app where I'm trying to draw metaballs behind the texture of a black-and-white world map.
Run-of-the-mill coloured shapes refers to the following,
GL11.glColor4d(1, 0, 0, 1);
GL11.glBegin(GL11.GL_QUADS);
GL11.glVertex2d(0, 0);
GL11.glVertex2d(0, 50);
GL11.glVertex2d(50, 50);
GL11.glVertex2d(50, 0);
GL11.glEnd();
Even if drawn on its own, as long as alpha blending is enabled, it won't show up.
UPDATE:
The constructor for world was loading (but not drawing) a texture. Removing that part of the code lets the coloured square show up. I have deduced that the problem will occur as long as a texture is loaded, regardless of whether it is displayed or not.
You've got glEnable(GL_TEXTURE_2D) in initGL, but I don't see it disabled anywhere.
You know you have to disable texturing if you want to draw an untextured object, right?