fix (with bad hacks!) some lighting issues. rewrite some comments
One of these fixes unfortunately removes the "free" smooth lighting from before, but that was actually mostly the result of a side-effect from a bug in the way we checked for light-source tiles. And it wasn't really fully correct smooth lighting anyway.
This commit is contained in:
parent
1a18049b27
commit
0482491c2a
|
@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color;
|
||||||
import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder;
|
import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder;
|
||||||
import com.badlogic.gdx.math.Matrix4;
|
import com.badlogic.gdx.math.Matrix4;
|
||||||
import com.badlogic.gdx.math.Vector3;
|
import com.badlogic.gdx.math.Vector3;
|
||||||
|
import com.badlogic.gdx.math.collision.BoundingBox;
|
||||||
import com.blarg.gdx.graphics.Vertices;
|
import com.blarg.gdx.graphics.Vertices;
|
||||||
import com.blarg.gdx.tilemap3d.ChunkVertexGenerator;
|
import com.blarg.gdx.tilemap3d.ChunkVertexGenerator;
|
||||||
import com.blarg.gdx.tilemap3d.Tile;
|
import com.blarg.gdx.tilemap3d.Tile;
|
||||||
|
@ -13,8 +14,8 @@ import com.blarg.gdx.tilemap3d.tilemesh.TileMesh;
|
||||||
|
|
||||||
public class LitChunkVertexGenerator extends ChunkVertexGenerator {
|
public class LitChunkVertexGenerator extends ChunkVertexGenerator {
|
||||||
final Vector3 tmpOffset = new Vector3();
|
final Vector3 tmpOffset = new Vector3();
|
||||||
final Vector3 tmpLightSource = new Vector3();
|
final Vector3 tmpLightSourcePos = new Vector3();
|
||||||
final Color finalLightingColor = new Color();
|
final BoundingBox tmpBounds = new BoundingBox();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addMesh(MeshBuilder builder, Tile tile, TileMesh sourceMesh, TileChunk chunk, TileCoord position, Matrix4 transform, Color color, int firstVertex, int numVertices) {
|
protected void addMesh(MeshBuilder builder, Tile tile, TileMesh sourceMesh, TileChunk chunk, TileCoord position, Matrix4 transform, Color color, int firstVertex, int numVertices) {
|
||||||
|
@ -28,6 +29,8 @@ public class LitChunkVertexGenerator extends ChunkVertexGenerator {
|
||||||
tmpOffset.y += (float)position.y;
|
tmpOffset.y += (float)position.y;
|
||||||
tmpOffset.z += (float)position.z;
|
tmpOffset.z += (float)position.z;
|
||||||
|
|
||||||
|
chunk.getBoundingBoxFor(position.x, position.y, position.z, tmpBounds);
|
||||||
|
|
||||||
// figure out what the default lighting value is for this chunk
|
// figure out what the default lighting value is for this chunk
|
||||||
byte defaultLightValue = chunk.tileMap.skyLightValue;
|
byte defaultLightValue = chunk.tileMap.skyLightValue;
|
||||||
if (chunk.tileMap.ambientLightValue > defaultLightValue)
|
if (chunk.tileMap.ambientLightValue > defaultLightValue)
|
||||||
|
@ -49,46 +52,85 @@ public class LitChunkVertexGenerator extends ChunkVertexGenerator {
|
||||||
// translate vertex into "world/tilemap space"
|
// translate vertex into "world/tilemap space"
|
||||||
vertex.position.add(tmpOffset);
|
vertex.position.add(tmpOffset);
|
||||||
|
|
||||||
// the color we set to the chunk mesh determines the brightness (in other words: it is the lighting value)
|
// now we need to find the appropriate light source for this vertex. this light source could be either
|
||||||
|
// this very tile itself, or an adjacent tile. we'll check using the vertex normal as a direction to
|
||||||
|
// "look in" for the light source ...
|
||||||
|
|
||||||
// use the tile that's adjacent to this one in the direction that
|
// get the exact "world/tilemap space" position to grab a potential light source tile from
|
||||||
// this vertex's normal is pointing as the light source
|
tmpLightSourcePos.set(vertex.position).add(vertex.normal);
|
||||||
tmpLightSource.set(vertex.position).add(vertex.normal);
|
|
||||||
|
// HACK: if the light source position we just got lies exactly on the max x/y/z boundaries of this tile
|
||||||
|
// then casting it to int and using it as a tilemap grid coord to get the tile will fetch us the
|
||||||
|
// _next_ tile which we probably don't want when the position is exactly at max x/y/z ...
|
||||||
|
// (this was resulting in some incorrect dark edges along certain tile layouts)
|
||||||
|
if (tmpLightSourcePos.x == tmpBounds.max.x)
|
||||||
|
tmpLightSourcePos.x -= 0.01f;
|
||||||
|
if (tmpLightSourcePos.y == tmpBounds.max.y)
|
||||||
|
tmpLightSourcePos.y -= 0.01f;
|
||||||
|
if (tmpLightSourcePos.z == tmpBounds.max.z)
|
||||||
|
tmpLightSourcePos.z -= 0.01f;
|
||||||
|
|
||||||
// if the light source position is off the bounds of the entire world
|
|
||||||
// then use the default light value.
|
|
||||||
// the below call to TileChunk.getWithinSelfOrNeighbour() actually does
|
|
||||||
// do bounds checking, but we would need to cast from float to int
|
|
||||||
// first. this causes some issues when the one or more of the
|
|
||||||
// lightSource x/y/z values are between 0 and -1 (rounds up to 0 when
|
|
||||||
// using a cast). rather then do some weird custom rounding, we just
|
|
||||||
// check for negatives to ensure we catch them and handle it properly
|
|
||||||
// NOTE: this is only a problem currently because world coords are
|
|
||||||
// always >= 0. this will need to be adjusted if that changes
|
|
||||||
float brightness;
|
float brightness;
|
||||||
if (tmpLightSource.x < 0.0f || tmpLightSource.y < 0.0f || tmpLightSource.z < 0.0f)
|
|
||||||
|
// if the light source position is off the bounds of the entire world then use the default light value.
|
||||||
|
// the below call to TileChunk.getWithinSelfOrNeighbour() actually does do bounds checking, but we would
|
||||||
|
// need to cast from float to int first. this causes some issues when the one or more of the lightSource
|
||||||
|
// x/y/z values are between 0 and -1 (rounds up to 0 when using a cast). rather then do some weird custom
|
||||||
|
// rounding, we just check for negatives to ensure we catch them and handle it properly
|
||||||
|
// NOTE: this is _only_ a problem currently because world coords right now are always >= 0
|
||||||
|
if (tmpLightSourcePos.x < 0.0f || tmpLightSourcePos.y < 0.0f || tmpLightSourcePos.z < 0.0f)
|
||||||
brightness = Tile.getBrightness(defaultLightValue);
|
brightness = Tile.getBrightness(defaultLightValue);
|
||||||
else {
|
else {
|
||||||
// light source is within the boundaries of the world, get the
|
// light source is within the boundaries of the world, get the
|
||||||
// actual tile (may or may not be in a neighbouring chunk)
|
// actual tile (may or may not be in a neighbouring chunk)
|
||||||
int lightX = (int)tmpLightSource.x - chunk.getMinX();
|
int lightX = (int)tmpLightSourcePos.x - chunk.getMinX();
|
||||||
int lightY = (int)tmpLightSource.y - chunk.getMinY();
|
int lightY = (int)tmpLightSourcePos.y - chunk.getMinY();
|
||||||
int lightZ = (int)tmpLightSource.z - chunk.getMinZ();
|
int lightZ = (int)tmpLightSourcePos.z - chunk.getMinZ();
|
||||||
|
|
||||||
Tile lightSourceTile = chunk.getWithinSelfOrNeighbourSafe(lightX, lightY, lightZ);
|
Tile lightSourceTile = chunk.getWithinSelfOrNeighbourSafe(lightX, lightY, lightZ);
|
||||||
if (lightSourceTile == null)
|
if (lightSourceTile == null)
|
||||||
|
// out of bounds of the map
|
||||||
brightness = Tile.getBrightness(defaultLightValue);
|
brightness = Tile.getBrightness(defaultLightValue);
|
||||||
|
else if (lightSourceTile.isEmptySpace())
|
||||||
|
// this tile is getting it's light from another tile that is empty
|
||||||
|
// just use the other tile's light value as-is
|
||||||
|
brightness = lightSourceTile.getBrightness();
|
||||||
|
else {
|
||||||
|
// this tile is getting it's light from another tile that is not empty
|
||||||
|
// check if the direction we went in to find the other tile passes through any
|
||||||
|
// of the other tile's opaque sides. if so, we cannot use its light value and
|
||||||
|
// should instead just use whatever this tile's light value is
|
||||||
|
// TODO: i'm pretty sure this is going to produce poor results at some point in the future... fix!
|
||||||
|
|
||||||
|
TileMesh lightSourceTileMesh = chunk.tileMap.tileMeshes.get(lightSourceTile);
|
||||||
|
|
||||||
|
// collect a list of the sides to check for opaqueness with the light source tile .. we check
|
||||||
|
// the sides of the light source mesh opposite to the direction of the vertex normal (direction we
|
||||||
|
// are "moving" in)
|
||||||
|
// TODO: is it better to check each side individually? how would that work if the normal moves us
|
||||||
|
// in a non-orthogonal direction and we need to check 2 sides ... ?
|
||||||
|
byte sides = 0;
|
||||||
|
if (vertex.normal.y < 0.0f) sides |= TileMesh.SIDE_TOP;
|
||||||
|
if (vertex.normal.y > 0.0f) sides |= TileMesh.SIDE_BOTTOM;
|
||||||
|
if (vertex.normal.x < 0.0f) sides |= TileMesh.SIDE_RIGHT;
|
||||||
|
if (vertex.normal.x > 0.0f) sides |= TileMesh.SIDE_LEFT;
|
||||||
|
if (vertex.normal.z < 0.0f) sides |= TileMesh.SIDE_BACK;
|
||||||
|
if (vertex.normal.z > 0.0f) sides |= TileMesh.SIDE_FRONT;
|
||||||
|
|
||||||
|
if (lightSourceTileMesh.isOpaque(sides))
|
||||||
|
brightness = tile.tileLight;
|
||||||
else
|
else
|
||||||
brightness = lightSourceTile.getBrightness();
|
brightness = lightSourceTile.getBrightness();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
finalLightingColor.set(
|
// TODO: need to play with vertex/mesh color combinations a bit more to see if this is really correct
|
||||||
|
vertex.color.set(
|
||||||
vertex.color.r * color.r * brightness,
|
vertex.color.r * color.r * brightness,
|
||||||
vertex.color.g * color.g * brightness,
|
vertex.color.g * color.g * brightness,
|
||||||
vertex.color.b * color.b * brightness,
|
vertex.color.b * color.b * brightness,
|
||||||
vertex.color.a * color.a
|
vertex.color.a * color.a
|
||||||
);
|
);
|
||||||
vertex.color.set(finalLightingColor);
|
|
||||||
|
|
||||||
builder.vertex(vertex);
|
builder.vertex(vertex);
|
||||||
sourceVertices.moveNext();
|
sourceVertices.moveNext();
|
||||||
|
|
Loading…
Reference in a new issue