user3893373
user3893373

Reputation: 41

Box2dlights - Layering lights

How do you make the box2dlights ignore textures and sprites in ambient lighting? For example I have a stage that has the ambient lighting set to dark. I want my lights to brighten up a platform directly underneath the light, but the background image behind the light should remain dark and not lit up. Currently the lights are the top rendered layer and everything underneath the light is lit up.

Upvotes: 4

Views: 1610

Answers (1)

Azurlake
Azurlake

Reputation: 632

The right way to achieve this is the following:

  1. Update your physics and cameras.
  2. Render the light map so you can later fetch the texture from the RayHandler's FrameBuffer.
  3. Render your top layers to a transparent FrameBuffer object, in the desired order, but don't render the light map inside of it. Do not render here your HUD or whatever top-most layers you don't want to be affected by you lighting.
  4. Finish rendering to your FBO and begin rendering to your screen.
  5. Render the background which is not affected by lights.
  6. Bind to Texture Units 0 and 1 the light map and your top layers' FBO Texture.
  7. Begin a Shader you will use to blend your light map with your FBO Texture. The mixing is quite simple (occurs in the Fragment Shader): glFragColor = tex0.rgb * tex1.rgb, and keep tex1.a untouched (tex0 = light map texture, tex1 = fbo texture). The RayHandler's ambient light is lost with this rendering method, so you can pass the ambient light colour to the shader and add it to the light map channels.
  8. Bind the texture units to the shader and perform the rendering. This rendering must be done with alpha blending enabled (SRC_ALPHA, ONE_MINUS_SRC_ALPHA).
  9. Bind again the default Texture Unit so remaining rendering is properly done (TEXTURE_0): render any remaining top-most layers and the HUD, if any.

Some example code:

@Override
public void render(float delta) {

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

	tweenManager.update(delta);
        worldUpdate(delta);

        /* We have three cameras (foreground + double parallax background) */
        moveForegroundCamera(player.getPosition().x, player.getPosition().y);
        moveBackground0Camera(player.getPosition().x, player.getPosition().y);
        moveBackground1Camera(player.getPosition().x, player.getPosition().y);

        cameraMatrixCopy.set(foregroundCamera.combined);
        rayHandler.setCombinedMatrix(cameraMatrixCopy.scale(Globals.BOX_TO_WORLD, Globals.BOX_TO_WORLD, 1.0f), foregroundCamera.position.x,
                foregroundCamera.position.y, foregroundCamera.viewportWidth * camera.zoom * Globals.BOX_TO_WORLD,
                foregroundCamera.viewportHeight * foregroundCamera.zoom * Globals.BOX_TO_WORLD);
        rayHandler.update();
        rayHandler.render();
        lightMap = rayHandler.getLightMapTexture();

        fbo.begin();
        {
            Gdx.gl.glClearColor(0, 0, 0, 0);
            Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

            /* Draw the second background (affected by lights),  the player, the enemies and all the objects */
            batch.enableBlending();
            batch.setProjectionMatrix(background1Camera.combined);
            batch.begin();
            background1.draw(batch);
            batch.end();
            batch.setProjectionMatrix(foregroundCamera.combined);
            batch.begin();

            // Draw stuff...

            batch.end();
        }
        fbo.end();

        /* Now let's pile things up: draw the bottom-most layer */
        batch.setProjectionMatrix(background0Camera.combined);
        batch.disableBlending();
        batch.begin();
        background0.draw(batch);
        batch.end();

        /* Blend the frame buffer's texture with the light map in a fancy way */
        Gdx.gl20.glActiveTexture(GL20.GL_TEXTURE0);
        fboRegion.getTexture().bind(); // fboRegion = new TextureRegion(fbo.getColorBufferTexture());

        Gdx.gl20.glActiveTexture(GL20.GL_TEXTURE1);
        lightMap.bind();

        Gdx.gl20.glEnable(Gdx.gl20.GL_BLEND);
        Gdx.gl20.glBlendFunc(Gdx.gl20.GL_SRC_ALPHA, Gdx.gl20.GL_ONE_MINUS_SRC_ALPHA);
        lightShader.begin();
        lightShader.setUniformf("ambient_color", level.getAmbientLightColor());
        lightShader.setUniformi("u_texture0", 0);
        lightShader.setUniformi("u_texture1", 1);
        fullScreenQuad.render(lightShader, GL20.GL_TRIANGLE_FAN, 0, 4);
        lightShader.end();
        Gdx.gl20.glDisable(Gdx.gl20.GL_BLEND);

        Gdx.gl20.glActiveTexture(GL20.GL_TEXTURE0); // Bind again the default texture unit

        /* Draw any top-most layers you might have */
        hud.draw();

    }

Upvotes: 3

Related Questions