1
votes

DUMB QUETION, but I can't delete it.. I have solved the problem, I'm an idiot... :D

I have Libgdx scene2d stage with actors. I need to render the Box2D Lights (v. 1.4) between the actors, so the structure would look like this:

Actor, Actor, Light, Light, Actor

My stage render:

Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
super.render();

stage.act();
stage.draw();

My Box2D code:

rayHandler = new RayHandler(world);
rayHandler.setShadows(false);

Box2D update (I have a debug matrix because the physics world is being rendered in world coordinates(meters) and then I scale it to pixels):

public void updateWorld(float deltaTime) {
world.step(deltaTime, 7, 7);

// i know that this is not optimized to be called on every frame
debugMatrix = new Matrix4(stage.getCamera().combined.cpy());
debugMatrix.scale(ratio, ratio, 1);

rayHandler.setCombinedMatrix(debugMatrix);
rayHandler.updateAndRender();
}

And the light:

new PointLight(rayHandler, 128, null, 10, 0, 3);

Ok, now here is what I do: I have a Group that have some actors. I have another Group that holds the UI, drawn on top of the first group. I call updateWorld() right after the drawing of the first group is finished, so the lights will be on top of the first group and behind the second. Here is a quick illustration:

Start the drawing of the stage

Actors Group

  • Actor

  • Actor

  • Actor

Box2D render is called (we display the lights here)

UI Group

  • UI Actor panel

  • UI Actor panel

  • UI Actor panel

End the drawing of the stage

Here is the result (very ugly):

enter image description here

Now here is how it looks if I call updateWorld() after the stage has finished drawing (not between the actors):

Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
super.render();

stage.act();
stage.draw();

updateWorld(deltaTime);

enter image description here

It looks the way it should look, but it covers the stage and the UI.

Now, we go back to the starting point - again call the updateWorld() after the actors group, while the stage is rendering. We modify the projection matrix of the batch of the stage:

debugMatrix = new Matrix4(stage.getCamera().combined.cpy());
debugMatrix.scale(ratio, ratio, 1);

// this line was added
stage.getBatch().setProjectionMatrix(debugMatrix.cpy());

rayHandler.setCombinedMatrix(debugMatrix);
rayHandler.updateAndRender();

The result (light is still cool, but the scene2d is broken - all the actors from the UI are gone):

enter image description here

I have tested many many things (I've been trying to find a solution for 3 days):

  • I changed the projection and the transform matrix;

  • Change the matrix, draw the lights and restore the previous matrix;

  • Tested with different cameras and vieports for the stage and the lights;

  • And many other stuff with the drawing of the stage, lights batch and matrix

I think that LibGDX is changing the OpenGL drawing in some way while the stage is being drawn. I don't know what to do, I am not fully sure how OpenGL works. How I can make the light look ok (like on screenshot 2 and 3)?

Update: I know that I can make 2 separate stages and draw the lights between them - that will be ok, but my structure is far more complex (I just made it simple to explain it)... so I can't to that (or I will need 4-5 different stages, which is a terrible solution)

And please, don't propose solutions that are not solutions to the problem. I can't use shaders for lights, multiple stages, exported images of light objects and so on... I need a solution to this problem :)

3
If you solved it, why not answer your own question? - Sebastian
Because I am stupid and the problem is not in opengl or libgdx - it seems that I'be been calling the updateWorld() method /which draws the lights/ 10 times per frame, not once like I should..... - Yasen Bagalev

3 Answers

1
votes

Your problem is probably because your AfterDrawListener is called once per every child of a given actor (I am assuming that you are using the modified scene2d of The Sixth Hammer). Anyway try checking if the after draw event is from the same object.

0
votes

As I'm not really sure what you are trying to achieve, just some clarifications:

  • Each time you draw the box2dlights rayhandler, in fact you draw a black square above what you've drawn before. This black square is transparent in specific regions (these are the "lights").
  • Therefor, if you draw multiple light layers, the upper layers will darken the layers below them
  • Box2dlights uses OpenGl shaders to blend this blacks square above your scene. You can also implement your own shaders to be used here
  • because of this, the most useful approach here is to use only one light layer that is drawn above all "game" actors but below your user interface
0
votes

thanks for your question. I also searched for an answer to it and it seems I found

public void draw (Batch batch, float parentAlpha)
     {
         batch.end ();
         rayHandler.updateAndRender ();
         batch.begin ();
     }