Skip to content

Commit

Permalink
Fixing PointLight and DirectionalLight shadows
Browse files Browse the repository at this point in the history
+minor re-factoring
for libgdx#40
  • Loading branch information
rinold committed Feb 7, 2015
1 parent 5d207d1 commit 885a3bf
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 91 deletions.
74 changes: 32 additions & 42 deletions src/box2dLight/DirectionalLight.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import com.badlogic.gdx.physics.box2d.EdgeShape;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.QueryCallback;
import com.badlogic.gdx.physics.box2d.Shape;
import com.badlogic.gdx.physics.box2d.Shape.Type;

Expand Down Expand Up @@ -100,6 +99,7 @@ void update () {
yDisp = -sizeOfScreen * sin;

prepeareFixtureData();
updateDynamicShadowMeshes();
}

if (staticLight && !dirty) return;
Expand Down Expand Up @@ -193,8 +193,6 @@ void render () {
@Override
void dynamicShadowRender () {
if (height == -1f) return;

updateDynamicShadowMeshes();
for (Mesh m : dynamicShadowMeshes) {
m.render(rayHandler.lightShader, GL20.GL_TRIANGLE_STRIP);
}
Expand All @@ -215,24 +213,21 @@ protected void prepeareFixtureData() {
}

protected void updateDynamicShadowMeshes() {
for (Mesh mesh : dynamicShadowMeshes) {
mesh.dispose();
}
dynamicShadowMeshes.clear();

int meshInd = 0;
float colBits = rayHandler.ambientLight.toFloatBits();
for (Fixture fixture : affectedFixtures) {
LightData data = (LightData)fixture.getUserData();
if (data == null || fixture.isSensor()) continue;

Shape fixtureShape = fixture.getShape();
Type type = fixtureShape.getType();
center.set(fixture.getBody().getWorldCenter());
Body body = fixture.getBody();
center.set(body.getWorldCenter());
lstart.set(center).add(xDisp, yDisp);

int size = 0;
float l = data.height /
(float)Math.tan(height * MathUtils.degRad);
(float) Math.tan(height * MathUtils.degRad);
float f = 1f / data.shadowsDropped;
if (type == Type.Polygon || type == Type.Chain) {
boolean isPolygon = (type == Type.Polygon);
Expand All @@ -241,8 +236,7 @@ protected void updateDynamicShadowMeshes() {
PolygonShape pShape = isPolygon ?
(PolygonShape)fixtureShape : null;
int vertexCount = isPolygon ?
pShape.getVertexCount() :
cShape.getVertexCount();
pShape.getVertexCount() : cShape.getVertexCount();
int minN = -1;
int maxN = -1;
int minDstN = -1;
Expand All @@ -255,11 +249,12 @@ protected void updateDynamicShadowMeshes() {
} else {
cShape.getVertex(n, tmpVec);
}
tmpVec.set(fixture.getBody().getWorldPoint(tmpVec));
tmpVec.set(body.getWorldPoint(tmpVec));
tmpVerts.add(tmpVec.cpy());
tmpEnd.set(tmpVec).sub(lstart).limit(0.01f).add(tmpVec);

tmpEnd.set(tmpVec).sub(lstart).limit2(0.0001f).add(tmpVec);
if (fixture.testPoint(tmpEnd)) {
if (n > minN) minN = n;
if (minN == -1) minN = n;
maxN = n;
hasGasp = true;
continue;
Expand All @@ -274,20 +269,22 @@ protected void updateDynamicShadowMeshes() {
ind.clear();
if (!hasGasp) {
tmpVec.set(tmpVerts.get(minDstN));
boolean correctDirection = Intersector.pointLineSide(
lstart, center, tmpVec) < 0;
for (int n = minDstN; n < vertexCount; n++) {
ind.add(n);
}
for (int n = 0; n < minDstN; n++) {
ind.add(n);
}
if (!correctDirection) {
if (Intersector.pointLineSide(lstart, center, tmpVec) > 0) {
int z = ind.get(0);
ind.removeIndex(0);
ind.reverse();
ind.insert(0, z);
}
} else if (minN == 0 && maxN == vertexCount - 1) {
for (int n = maxN - 1; n > minN; n--) {
ind.add(n);
}
} else {
for (int n = minN - 1; n > -1; n--) {
ind.add(n);
Expand All @@ -297,8 +294,7 @@ protected void updateDynamicShadowMeshes() {
}
}

for (int k = 0; k < ind.size; k++) {
int n = ind.get(k);
for (int n : ind.toArray()) {
tmpVec.set(tmpVerts.get(n));
tmpEnd.set(tmpVec).sub(lstart).limit(l).add(tmpVec);

Expand Down Expand Up @@ -343,7 +339,7 @@ protected void updateDynamicShadowMeshes() {
EdgeShape shape = (EdgeShape)fixtureShape;

shape.getVertex1(tmpVec);
tmpVec.set(fixture.getBody().getWorldPoint(tmpVec));
tmpVec.set(body.getWorldPoint(tmpVec));

segments[size++] = tmpVec.x;
segments[size++] = tmpVec.y;
Expand All @@ -357,7 +353,7 @@ protected void updateDynamicShadowMeshes() {
segments[size++] = f;

shape.getVertex2(tmpVec);
tmpVec.set(fixture.getBody().getWorldPoint(tmpVec));
tmpVec.set(body.getWorldPoint(tmpVec));
segments[size++] = tmpVec.x;
segments[size++] = tmpVec.y;
segments[size++] = zeroColorBits;
Expand All @@ -370,14 +366,21 @@ protected void updateDynamicShadowMeshes() {
segments[size++] = f;
}

Mesh mesh = new Mesh(
VertexDataType.VertexArray, staticLight, size / 4, 0,
new VertexAttribute(Usage.Position, 2, "vertex_positions"),
new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"),
new VertexAttribute(Usage.Generic, 1, "s"));
Mesh mesh = null;
if (meshInd >= dynamicShadowMeshes.size) {
mesh = new Mesh(
VertexDataType.VertexArray, false, 64, 0,
new VertexAttribute(Usage.Position, 2, "vertex_positions"),
new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"),
new VertexAttribute(Usage.Generic, 1, "s"));
dynamicShadowMeshes.add(mesh);
} else {
mesh = dynamicShadowMeshes.get(meshInd);
}
mesh.setVertices(segments, 0, size);
dynamicShadowMeshes.add(mesh);
meshInd++;
}
dynamicShadowMeshes.truncate(meshInd);
}

@Override
Expand All @@ -403,20 +406,6 @@ public boolean contains (float x, float y) {
return oddNodes;
}

final QueryCallback dynamicShadowCallback = new QueryCallback() {

@Override
public boolean reportFixture(Fixture fixture) {
if (fixture.getUserData() instanceof LightData) {
LightData data = (LightData)fixture.getUserData();
data.shadowsDropped = 0;
}
affectedFixtures.add(fixture);
return true;
}

};

/** Sets the horizontal angle for directional light in degrees
*
* <p> This could be used to simulate sun cycles **/
Expand All @@ -433,6 +422,7 @@ public void setHeight(float degrees) {
}
}


/** Not applicable for this light type **/
@Deprecated
@Override
Expand Down
21 changes: 21 additions & 0 deletions src/box2dLight/Light.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Filter;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.QueryCallback;
import com.badlogic.gdx.physics.box2d.RayCastCallback;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Disposable;
Expand Down Expand Up @@ -477,5 +478,25 @@ static public void setContactFilter(short categoryBits, short groupIndex,
filterA.groupIndex = groupIndex;
filterA.maskBits = maskBits;
}

protected boolean onDynamicCallback(Fixture fixture) {
return true;
}

final QueryCallback dynamicShadowCallback = new QueryCallback() {

@Override
public boolean reportFixture(Fixture fixture) {
if (!onDynamicCallback(fixture)) return true;

if (fixture.getUserData() instanceof LightData) {
LightData data = (LightData)fixture.getUserData();
data.shadowsDropped = 0;
}
affectedFixtures.add(fixture);
return true;
}

};

}
68 changes: 37 additions & 31 deletions src/box2dLight/PointLight.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.math.Intersector;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.ChainShape;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.EdgeShape;
Expand Down Expand Up @@ -74,43 +75,41 @@ public void update () {

if (rayHandler.pseudo3d) {
prepeareFixtureData();
updateDynamicShadowMeshes();
}
}

@Override
void dynamicShadowRender () {
updateDynamicShadowMeshes();
for (Mesh m : dynamicShadowMeshes) {
m.render(rayHandler.lightShader, GL20.GL_TRIANGLE_STRIP);
}
}

protected void updateDynamicShadowMeshes() {
for (Mesh mesh : dynamicShadowMeshes) {
mesh.dispose();
}
dynamicShadowMeshes.clear();

int meshInd = 0;
float colBits = rayHandler.ambientLight.toFloatBits();
for (Fixture fixture : affectedFixtures) {
LightData data = (LightData)fixture.getUserData();
if (data == null || fixture.isSensor()) continue;

Shape fixtureShape = fixture.getShape();
Type type = fixtureShape.getType();
center.set(fixture.getBody().getWorldCenter());
int size = 0;
float l = 0f;
float f = 1f / data.shadowsDropped;

Shape fixtureShape = fixture.getShape();
Type type = fixtureShape.getType();
Body body = fixture.getBody();
center.set(body.getWorldCenter());

if (type == Type.Polygon || type == Type.Chain) {
boolean isPolygon = (type == Type.Polygon);
ChainShape cShape = isPolygon ?
null : (ChainShape)fixtureShape;
PolygonShape pShape = isPolygon ?
(PolygonShape)fixtureShape : null;
int vertexCount = isPolygon ?
pShape.getVertexCount() :
cShape.getVertexCount();
pShape.getVertexCount() : cShape.getVertexCount();
int minN = -1;
int maxN = -1;
int minDstN = -1;
Expand All @@ -123,15 +122,16 @@ protected void updateDynamicShadowMeshes() {
} else {
cShape.getVertex(n, tmpVec);
}
tmpVec.set(fixture.getBody().getWorldPoint(tmpVec));
tmpVec.set(body.getWorldPoint(tmpVec));
tmpVerts.add(tmpVec.cpy());
tmpEnd.set(tmpVec).sub(start).limit(0.01f).add(tmpVec);
tmpEnd.set(tmpVec).sub(start).limit2(0.0001f).add(tmpVec);
if (fixture.testPoint(tmpEnd)) {
if (n > minN) minN = n;
if (minN == -1) minN = n;
maxN = n;
hasGasp = true;
continue;
}

float currDist = tmpVec.dst2(start);
if (currDist < minDst) {
minDst = currDist;
Expand All @@ -142,19 +142,19 @@ protected void updateDynamicShadowMeshes() {
ind.clear();
if (!hasGasp) {
tmpVec.set(tmpVerts.get(minDstN));
boolean correctDirection = Intersector.pointLineSide(
start, center, tmpVec) < 0;
for (int n = minDstN; n < vertexCount; n++) {
ind.add(n);
}
for (int n = 0; n < minDstN; n++) {
ind.add(n);
}
if (!correctDirection) {
int z = ind.get(0);
ind.removeIndex(0);
if (Intersector.pointLineSide(start, center, tmpVec) > 0) {
ind.reverse();
ind.insert(0, z);
ind.insert(0, ind.pop());
}
} else if (minN == 0 && maxN == vertexCount - 1) {
for (int n = maxN - 1; n > minN; n--) {
ind.add(n);
}
} else {
for (int n = minN - 1; n > -1; n--) {
Expand All @@ -165,8 +165,7 @@ protected void updateDynamicShadowMeshes() {
}
}

for (int k = 0; k < ind.size; k++) {
int n = ind.get(k);
for (int n : ind.toArray()) {
tmpVec.set(tmpVerts.get(n));

float dst = tmpVec.dst(start);
Expand Down Expand Up @@ -215,7 +214,7 @@ protected void updateDynamicShadowMeshes() {
EdgeShape shape = (EdgeShape)fixtureShape;

shape.getVertex1(tmpVec);
tmpVec.set(fixture.getBody().getWorldPoint(tmpVec));
tmpVec.set(body.getWorldPoint(tmpVec));
float dst = tmpVec.dst(start);
l = data.getLimit(dst, height, distance);

Expand All @@ -231,7 +230,7 @@ protected void updateDynamicShadowMeshes() {
segments[size++] = f;

shape.getVertex2(tmpVec);
tmpVec.set(fixture.getBody().getWorldPoint(tmpVec));
tmpVec.set(body.getWorldPoint(tmpVec));
dst = tmpVec.dst(start);
l = data.getLimit(dst, height, distance);

Expand All @@ -245,16 +244,23 @@ protected void updateDynamicShadowMeshes() {
segments[size++] = tmpEnd.y;
segments[size++] = colBits;
segments[size++] = f;
}
}

Mesh mesh = new Mesh(
VertexDataType.VertexArray, staticLight, size / 4, 0,
new VertexAttribute(Usage.Position, 2, "vertex_positions"),
new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"),
new VertexAttribute(Usage.Generic, 1, "s"));
Mesh mesh = null;
if (meshInd >= dynamicShadowMeshes.size) {
mesh = new Mesh(
VertexDataType.VertexArray, false, 64, 0,
new VertexAttribute(Usage.Position, 2, "vertex_positions"),
new VertexAttribute(Usage.ColorPacked, 4, "quad_colors"),
new VertexAttribute(Usage.Generic, 1, "s"));
dynamicShadowMeshes.add(mesh);
} else {
mesh = dynamicShadowMeshes.get(meshInd);
}
mesh.setVertices(segments, 0, size);
dynamicShadowMeshes.add(mesh);
meshInd++;
}
dynamicShadowMeshes.truncate(meshInd);
}

/**
Expand Down
Loading

0 comments on commit 885a3bf

Please sign in to comment.