Skip to content

Commit c025e92

Browse files
committed
🩵 Work on lighting
1 parent 986b6a3 commit c025e92

6 files changed

Lines changed: 110 additions & 92 deletions

File tree

‎src/main/java/com/james090500/renderer/shaders/ChunkShader.java‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public ChunkShader() {
1010
layout(location = 1) in vec2 aUv;
1111
layout(location = 2) in uint aLayer;
1212
layout(location = 3) in float aAo;
13+
layout(location = 4) in uint aLight;
1314
1415
uniform mat4 model;
1516
uniform mat4 view;
@@ -19,11 +20,13 @@ public ChunkShader() {
1920
flat out uint vLayer;
2021
out vec3 mvPos;
2122
out float vAo;
23+
flat out uint vLight;
2224
2325
void main() {
2426
vUv = aUv;
2527
vLayer = aLayer;
2628
vAo = aAo;
29+
vLight = aLight;
2730
2831
vec4 modelViewMatrix = view * model * vec4(aPos, 1.0);
2932
gl_Position = projection * modelViewMatrix;
@@ -39,6 +42,7 @@ void main() {
3942
in vec2 vUv;
4043
flat in uint vLayer;
4144
in float vAo;
45+
flat in uint vLight;
4246
4347
uniform sampler2DArray texArray;
4448
@@ -47,7 +51,7 @@ void main() {
4751
""" + GlobalShader.FOG_METHOD + """
4852
4953
void main() {
50-
float faceLight = 1.0;
54+
float faceLight = (1.0 / 16) * vLight;
5155
5256
vec4 texel = texture(texArray, vec3(vUv, float(vLayer)));
5357

‎src/main/java/com/james090500/renderer/world/ChunkRenderer.java‎

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import java.nio.FloatBuffer;
2323
import java.nio.IntBuffer;
2424
import java.util.ArrayList;
25-
import java.util.Map;
25+
import java.util.concurrent.ThreadLocalRandom;
2626

2727
import static org.lwjgl.opengl.GL15.*;
2828
import static org.lwjgl.opengl.GL30.*;
@@ -117,6 +117,7 @@ private void createMesh(ChunkMesh chunkMesh, boolean transparent) {
117117
FloatBuffer uvBuffer = ByteBuffer.allocateDirect(numQuads * 8 * Float.BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
118118
IntBuffer texLayerBuffer = ByteBuffer.allocateDirect(numQuads * 4 * Integer.BYTES).order(ByteOrder.nativeOrder()).asIntBuffer();
119119
FloatBuffer aoBuffer = ByteBuffer.allocateDirect(numQuads * 4 * Float.BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
120+
IntBuffer lightBuffer = ByteBuffer.allocateDirect(numQuads * 4 * Integer.BYTES).order(ByteOrder.nativeOrder()).asIntBuffer();
120121

121122
// Positions (vec3 per vertex)
122123
for (float[] v : chunkMesh.vertices) {
@@ -135,7 +136,7 @@ private void createMesh(ChunkMesh chunkMesh, boolean transparent) {
135136
uvBuffer.put(uv, 0, 8);
136137
}
137138

138-
// Texture layer (same layer repeated for the quad’s 4 vertices)
139+
// Texture layer (same layer repeated for the quad's 4 vertices)
139140
for (int layer : chunkMesh.texOffset) {
140141
texLayerBuffer.put(layer).put(layer).put(layer).put(layer);
141142
}
@@ -145,12 +146,18 @@ private void createMesh(ChunkMesh chunkMesh, boolean transparent) {
145146
aoBuffer.put(a, 0, 4);
146147
}
147148

149+
// Light Buffer (same layer repeated for the quad's 4 vertices)
150+
for (int light : chunkMesh.light) {
151+
lightBuffer.put(light).put(light).put(light).put(light);
152+
}
153+
148154
// Flip for OpenGL
149155
vertexBuffer.flip();
150156
indexBuffer.flip();
151157
uvBuffer.flip();
152158
texLayerBuffer.flip();
153159
aoBuffer.flip();
160+
lightBuffer.flip();
154161

155162
if(transparent) {
156163
transVertexCount = indexBuffer.limit();
@@ -198,6 +205,14 @@ private void createMesh(ChunkMesh chunkMesh, boolean transparent) {
198205
glEnableVertexAttribArray(3);
199206
glVertexAttribPointer(3, 1, GL_FLOAT, false, 0, 0);
200207

208+
// --- Ambient Occlusion (Attribute 4) ---
209+
int lightVBO = glGenBuffers();
210+
glBindBuffer(GL_ARRAY_BUFFER, lightVBO);
211+
glBufferData(GL_ARRAY_BUFFER, lightBuffer, GL_STATIC_DRAW);
212+
213+
glEnableVertexAttribArray(4);
214+
glVertexAttribPointer(4, 1, GL_FLOAT, false, 0, 0);
215+
201216
// --- Index Buffer ---
202217
int ibo = glGenBuffers();
203218
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
@@ -267,19 +282,22 @@ private static class ChunkMesh {
267282
ArrayList<float[]> uvs;
268283
ArrayList<Integer> texOffset;
269284
ArrayList<float[]> aos;
285+
ArrayList<Integer> light;
270286

271287
public ChunkMesh(
272288
ArrayList<float[]> vertices,
273289
ArrayList<int[]> indices,
274290
ArrayList<float[]> uvs,
275291
ArrayList<Integer> texOffset,
276-
ArrayList<float[]> aos
292+
ArrayList<float[]> aos,
293+
ArrayList<Integer> light
277294
) {
278295
this.vertices = vertices;
279296
this.indices = indices;
280297
this.uvs = uvs;
281298
this.texOffset = texOffset;
282299
this.aos = aos;
300+
this.light = light;
283301
}
284302
}
285303

@@ -385,6 +403,10 @@ private int getAo(int[] currentPos, int[] step, int axis, boolean positive) {
385403
((aoLevels[3] & 0b11) << 6); // BR
386404
}
387405

406+
private int getLightLevel(int currID, int[] pos, int[] step) {
407+
return ThreadLocalRandom.current().nextInt(0, 16 + 1);
408+
}
409+
388410
private int getMaskValue(int id, int[] pos, int[] step) {
389411
Block block = Blocks.get(id);
390412
Block neighbor = BlockGame.getInstance().getWorld().getChunkBlock(
@@ -433,12 +455,14 @@ private int getTextureValue(int id, int axis, boolean positive) {
433455
private ChunkMesh generateMesh(int[] dims, int[] voxels) {
434456
int[] mask = new int[0];
435457
int[] aoMask = new int[0];
458+
int[] lightMask = new int[0];
436459
int[] texMask = new int[0];
437460

438461
ArrayList<float[]> vertices = new ArrayList<>();
439462
ArrayList<int[]> indices = new ArrayList<>();
440463
ArrayList<float[]> uvs = new ArrayList<>();
441464
ArrayList<Integer> textures = new ArrayList<>();
465+
ArrayList<Integer> light = new ArrayList<>();
442466
ArrayList<float[]> aos = new ArrayList<>();
443467

444468
// Sweep across 3 dimensions: X, Y, Z (0, 1, 2)
@@ -453,6 +477,7 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
453477
if (mask.length < dims[u] * dims[v]) {
454478
mask = new int[dims[u] * dims[v]];
455479
aoMask = new int[dims[u] * dims[v]];
480+
lightMask = new int[dims[u] * dims[v]];
456481
texMask = new int[dims[u] * dims[v]];
457482
}
458483

@@ -473,11 +498,13 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
473498
if ((currID != 0) == (nextID != 0)) {
474499
mask[n] = 0;
475500
aoMask[n] = 3;
501+
lightMask[n] = 0;
476502
texMask[n] = 0;
477503
} else {
478504
// Generate an AO for the block, the value will be a bitwise total unique to the AO pattern
479505
if (currID != 0) {
480506
mask[n] = getMaskValue(currID, pos, step);
507+
lightMask[n] = getLightLevel(currID, pos, step);
481508
aoMask[n] = this.getAo(
482509
nextPos,
483510
step,
@@ -487,6 +514,7 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
487514
texMask[n] = getTextureValue(currID, axis, true);
488515
} else {
489516
mask[n] = -getMaskValue(nextID, pos, new int[] { 0, 0, 0 });
517+
lightMask[n] = -getLightLevel(currID, pos, step);
490518
aoMask[n] = -this.getAo(
491519
nextPos,
492520
step,
@@ -507,11 +535,18 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
507535
for (int i = 0; i < dims[u]; ) {
508536
int blockId = mask[n];
509537
int aoVal = aoMask[n];
538+
int lightLevel = lightMask[n];
510539
int texVal = texMask[n];
511540
if (blockId != 0) {
512541
// Calculate quad width
513542
int width = 1;
514-
while (i + width < dims[u] && blockId == mask[n + width] && aoVal == aoMask[n + width] && texVal == texMask[n + width]) {
543+
while (
544+
i + width < dims[u] &&
545+
blockId == mask[n + width] &&
546+
lightLevel == lightMask[n + width] &&
547+
aoVal == aoMask[n + width] &&
548+
texVal == texMask[n + width]
549+
) {
515550
++width;
516551
}
517552

@@ -520,7 +555,12 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
520555
boolean stop = false;
521556
while (j + height < dims[v]) {
522557
for (int k = 0; k < width; ++k) {
523-
if (blockId != mask[n + k + height * dims[u]] || aoVal != aoMask[n + k + height * dims[u]] || texVal != texMask[n + k + height * dims[u]]) {
558+
if (
559+
blockId != mask[n + k + height * dims[u]] ||
560+
lightLevel == lightMask[n + k + height * dims[u]] ||
561+
aoVal != aoMask[n + k + height * dims[u]] ||
562+
texVal != texMask[n + k + height * dims[u]]
563+
) {
524564
stop = true;
525565
break;
526566
}
@@ -543,6 +583,7 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
543583
du[u] = width;
544584
dv[v] = height;
545585
} else {
586+
lightLevel = -lightLevel;
546587
aoVal = -aoVal;
547588
dv[u] = width;
548589
du[v] = height;
@@ -620,6 +661,9 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
620661
// UV
621662
uvs.add(uv);
622663

664+
// LightVal
665+
light.add(lightLevel);
666+
623667
// Tex Offset
624668
textures.add(texVal);
625669

@@ -644,6 +688,6 @@ private ChunkMesh generateMesh(int[] dims, int[] voxels) {
644688
}
645689
}
646690
}
647-
return new ChunkMesh(vertices, indices, uvs, textures, aos);
691+
return new ChunkMesh(vertices, indices, uvs, textures, aos, light);
648692
}
649693
}

‎src/main/java/com/james090500/utils/NoiseManager.java‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.james090500.utils;
22

33
import com.james090500.BlockGame;
4-
import com.james090500.world.Biomes;
54

65
public class NoiseManager {
76

@@ -12,7 +11,7 @@ public class NoiseManager {
1211
* @param z The Z Coordinate
1312
* @return The resulting noise
1413
*/
15-
public static double chunkNoise(Biomes biome, int x, int y, int z) {
14+
public static double chunkNoise(int x, int y, int z) {
1615
int octaves = 4;
1716
double persistence = 0.5;
1817
double lacunarity = 2.0;

‎src/main/java/com/james090500/world/BiomeGenerator.java‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ public class BiomeGenerator {
2020
* @return
2121
*/
2222
public static Biomes getBiome(int x, int z) {
23-
double elev = (NoiseManager.elevationNoise(x, z) + 1.0) / 2.0; // 0..1
24-
if (elev < 0.5) return Biomes.OCEAN;
25-
2623
double noise = NoiseManager.biomeNoise(x, z); // [-1, 1]
2724
double n = (noise + 1.0) / 2.0;
2825

‎src/main/java/com/james090500/world/Chunk.java‎

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ public void generate() {
146146
* Generates the actual terrain
147147
*/
148148
private void generateTerrain() {
149-
int landLevel = 70;
149+
int lowestLevel = 45;
150150
int waterLevel = 64;
151151

152152
for (int x = 0; x < chunkSize; x++) {
@@ -156,37 +156,26 @@ private void generateTerrain() {
156156

157157
Biomes biome = BiomeGenerator.getBiome(nx, nz);
158158

159-
// column elevation noise is 0..1
160-
double colElev = (NoiseManager.elevationNoise(nx, nz) + 1.0) / 2.0; // already 0..1 per you
161-
int colTargetY = mapElevToSurfaceY(colElev, waterLevel, this.chunkHeight - 1);
162-
163-
boolean enforceBelowWater = (colElev < 0.5); // only force down when elevation ≤ 0.5
164-
165159
int topSoilDepth = -1;
166160

167161
for (int y = this.chunkHeight - 1; y >= 0; y--) {
168-
double density = NoiseManager.chunkNoise(biome, nx, y, nz);
162+
double density = NoiseManager.chunkNoise(nx, y, nz);
169163

170164
// your original heightFactor adjustments (keeps caves/overhang feel)
171-
double heightFactor = (landLevel - y) / (double) landLevel;
172-
173-
// *** NEW: if this column must be below water, smoothly push density negative above colTargetY ***
174-
if (enforceBelowWater) {
175-
// smoothstep goes 0 at colTargetY and 1 at (colTargetY + FORCE_TRANSITION)
176-
density += heightFactor * 2.0;
177-
double t = smoothstep(colTargetY, colTargetY + 6, y);
178-
density -= t * 2.0;
179-
// result: density unaffected below target, gradually reduced above target,
180-
// strongly reduced above target + FORCE_TRANSITION.
181-
} else if (y > waterLevel) {
182-
if (density > 0.35) {
183-
density += heightFactor;
165+
double heightFactor = (waterLevel - y) / (double) waterLevel;
166+
167+
if (y > lowestLevel) {
168+
if (y > waterLevel) {
169+
if (density > 0.35 && (biome.equals(Biomes.FOREST) || biome.equals(Biomes.PLAINS))) {
170+
density += heightFactor / 2;
171+
} else {
172+
density += heightFactor * 1.5;
173+
}
184174
} else {
185-
density += heightFactor * 2.0;
175+
density += heightFactor;
186176
}
187177
} else {
188178
density += heightFactor * 6.0;
189-
density += (smoothstep(colTargetY, colTargetY + 6, y) * 2.0);
190179
}
191180

192181
byte nextBlock = 0;
@@ -287,21 +276,6 @@ private void generateDecorations() {
287276
}
288277
}
289278

290-
private int mapElevToSurfaceY(double elev01, int waterLevel, int maxHeight) {
291-
if (elev01 <= 0.5) {
292-
return (int)Math.round((elev01 / 0.5) * waterLevel);
293-
} else {
294-
return waterLevel + (int)Math.round(((elev01 - 0.5) / 0.5) * (maxHeight - waterLevel));
295-
}
296-
}
297-
298-
private static double smoothstep(double edge0, double edge1, double y) {
299-
if (edge0 == edge1) return y < edge0 ? 0.0 : 1.0;
300-
double t = (y - edge0) / (edge1 - edge0);
301-
t = Math.clamp(t, 0.0, 1.0);
302-
return t * t * (3.0 - 2.0 * t);
303-
}
304-
305279
public void saveChunk() {
306280
if(this.chunkData != null && this.needsSaving && !BlockGame.getInstance().getWorld().isRemote()) {
307281
this.needsSaving = false;

0 commit comments

Comments
 (0)