I'm trying to use box2dlights to add lighting to my game and I have everything working except I am unable to have shadows cast with my box2d bodies. I also have collision working using category/maskBits with my various objects and I'm trying to apply the same strategy to box2dlight filters. You can see how the light just passed through the body.

No shadows casted

EDIT: I think I may have discovered why the lights are not colliding with my box2d bodies. When I define the body shapes using "real world" scale pixel coordinates, the lights cast shadows properly, but I lose collision since the bodies are defined at pixel scale as opposed to the box2d scale I have defined. Does anyone know why the box2dlights are using real world scale?

Here is my RayHandler Setup

rayHandler = new RayHandler(world);
rayHandler.setAmbientLight(.5f, .5f, .2f, 1f);

I have a PointLight that is positioned in the center of the screen.

PointLight pl = new PointLight(game.rayHandler, 128);
pl.setPosition(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
Filter filter = new Filter();
filter.categoryBits = B2DVars.CATEGORY_LIGHT; // Value listed below
filter.maskBits = B2DVars.MASK_LIGHT;         // Value listed below

Also, my body is defined as

body = world.createBody(squareBodyDef);
PolygonShape squareShape = new PolygonShape();
squareShape.setAsBox(b2dWidth / 2, b2dWidth / 2, new Vector2(squareBodyDef.position.x * WORLD_TO_BOX, squareBodyDef.position.y * WORLD_TO_BOX), 0f);

FixtureDef fdef = new FixtureDef();
fdef.shape = squareShape;
fdef.density = 10.0f;
fdef.friction =  0.1f;
fdef.restitution = 1.15f;
fdef.filter.categoryBits = CATEGORY_SQUARE_OBJECTIVE; // Value listed below
fdef.filter.maskBits = MASK_SQUARE; // Value listed below


Finally, my box2d filtering constants

public static final short CATEGORY_BALL = 1;
public static final short CATEGORY_LINE = 2;
public static final short CATEGORY_WALL = 4;
public static final short CATEGORY_SQUARE_OBJECTIVE = 8;
public static final short CATEGORY_TRIANGLE_OBJECTIVE = 16;
public static final short CATEGORY_LIGHT = 32;

public static final short LIGHT_GROUP = 1;

public static final short MASK_BALL =
                CATEGORY_LINE |
                CATEGORY_WALL |

public static final short MASK_LIGHT =
                CATEGORY_LINE |

public static final short MASK_SQUARE =
                CATEGORY_BALL |

public static final short MASK_WALL = -1

I've been going non-stop for about 3 days trying to solve this problem to no avail. Any help is appreciated!


The problem was that I was using the projection matrix from my main camera with the RayHandler. My main camera by default is in world/pixel units where 100 pixels = 1 box2d meter, but its projection matrix should have been in box2d units (meters).

Based on information from this post on the libgdx reddit forum, I decided to solve the problem by creating a separate camera for my box2dlights. Here was the solution I used...

// Create a separate camera for box2dlights
OrthographicCamera b2dCam = new OrthgraphicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

Use the camera above with the RayHandler after the box2d world.step(..) call. This camera needs to be scaled to the box2d world.

// BOX_TO_WORLD = 100 and WORLD_TO_BOX = 0.01
rayHandler.setCombinedMatrix(b2dCam.combined.scale(BOX_TO_WORLD,BOX_TO_WORLD,BOX_TO_WORLD), b2dCam.position.x * WORLD_TO_BOX, b2dCam.position.y WORLD_TO_BOX, b2dCam.viewportWidth * b2dCam.zoom, b2dCam.viewportHeight * b2dCam.zoom);

Finally I needed to create my light source in box2d units...

PointLight pl = new PointLight(rayHandler, 128, Color.WHITE, 1500 * WORLD_TO_BOX, (Gdx.graphics.getWidth() / 2) * WORLD_TO_BOX, (Gdx.graphics.getHeight() / 2) * WORLD_TO_BOX);

The end result:

enter image description here


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.