![JAR search and dependency download from the Maven repository](/logo.png)
ca.blarg.gdx.tilemap3d.lighting.LitChunkVertexGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gdx-tilemap3d Show documentation
Show all versions of gdx-tilemap3d Show documentation
Library to handle management and rendering of a game world composed of 3D "tiles" arranged in a uniform 3D grid, via libGDX.
The newest version!
package ca.blarg.gdx.tilemap3d.lighting;
import ca.blarg.gdx.graphics.Vertices;
import ca.blarg.gdx.tilemap3d.ChunkVertexGenerator;
import ca.blarg.gdx.tilemap3d.Tile;
import ca.blarg.gdx.tilemap3d.TileChunk;
import ca.blarg.gdx.tilemap3d.TileCoord;
import ca.blarg.gdx.tilemap3d.tilemesh.TileMesh;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.math.collision.BoundingBox;
public class LitChunkVertexGenerator extends ChunkVertexGenerator {
final Vector3 tmpOffset = new Vector3();
final Vector3 tmpLightSourcePos = new Vector3();
final BoundingBox tmpBounds = new BoundingBox();
@Override
protected void addMesh(MeshBuilder builder, Tile tile, TileMesh sourceMesh, TileChunk chunk, TileCoord position, Matrix4 transform, Color color, int firstVertex, int numVertices) {
// adjust position by the tilemesh offset. TileMesh's are modeled using the
// origin (0,0,0) as the center and are 1 unit wide/deep/tall. So, their
// max extents are from -0.5,-0.5,-0.5 to 0.5,0.5,0.5. For rendering
// purposes in a chunk, we want the extents to be 0,0,0 to 1,1,1. This
// adjustment fixes that
tmpOffset.set(TileMesh.OFFSET);
tmpOffset.x += (float)position.x;
tmpOffset.y += (float)position.y;
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
byte defaultLightValue = chunk.tileMap.skyLightValue;
if (chunk.tileMap.ambientLightValue > defaultLightValue)
defaultLightValue = chunk.tileMap.ambientLightValue;
Vertices sourceVertices = sourceMesh.getVertices();
sourceVertices.moveTo(firstVertex);
// copy vertices
for (int i = 0; i < numVertices; ++i) {
sourceVertices.getVertex(vertex);
// transform if applicable... (this will probably just be per-tile rotation)
if (transform != null) {
vertex.position.mul(transform);
vertex.normal.rot(transform);
}
// translate vertex into "world/tilemap space"
vertex.position.add(tmpOffset);
// 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 ...
// get the exact "world/tilemap space" position to grab a potential light source tile from
//if (!tile.isLargeTile())
// using the center of this tile as the reference point this helps avoid problems with using the vertex
// as the ref point where the vertex is at the very edge of the tile boundaries facing out of the tile
// (we could end up inadvertenly skipping over the tile we should get the light from in such a case)
tmpLightSourcePos.set(tmpOffset).add(vertex.normal);
//else
// throw new NotImplementedException();
float brightness;
// 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);
else {
// light source is within the boundaries of the world, get the
// actual tile (may or may not be in a neighbouring chunk)
int lightX = (int)tmpLightSourcePos.x - chunk.getMinX();
int lightY = (int)tmpLightSourcePos.y - chunk.getMinY();
int lightZ = (int)tmpLightSourcePos.z - chunk.getMinZ();
Tile lightSourceTile = chunk.getWithinSelfOrNeighbourSafe(lightX, lightY, lightZ);
if (lightSourceTile == null)
// out of bounds of the map
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
brightness = lightSourceTile.getBrightness();
}
}
// 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.g * color.g * brightness,
vertex.color.b * color.b * brightness,
vertex.color.a * color.a
);
builder.vertex(vertex);
sourceVertices.moveNext();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy