Skip to content

Commit f03c94d

Browse files
authored
Fix hide water plane not working in chunks that don't use the biome color. (#1861)
* Generate the water texture even for chunks that don't require the biome color. Fixes #1688 * Omit chunks that contain no blocks from the water texture. * Fix indentation.
1 parent 3ba3367 commit f03c94d

File tree

1 file changed

+141
-117
lines changed
  • chunky/src/java/se/llbit/chunky/renderer/scene

1 file changed

+141
-117
lines changed

chunky/src/java/se/llbit/chunky/renderer/scene/Scene.java

Lines changed: 141 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,7 @@ public synchronized void loadChunks(TaskTracker taskTracker, World world, Map<Re
918918
loadedChunks.add(cp);
919919

920920
ChunkData chunkData = chunkDataPair.second();
921+
boolean didLoadVisibleBlocksFromChunk = false;
921922
if (chunkData == null) {
922923
chunkData = EmptyChunkData.INSTANCE;
923924
}
@@ -1163,6 +1164,8 @@ public synchronized void loadChunks(TaskTracker taskTracker, World world, Map<Re
11631164
// X and Z are Chunky position but Y is world position
11641165
emitterGrid.addEmitter(new Grid.EmitterPosition(x, y - origin.y, z, block));
11651166
}
1167+
1168+
didLoadVisibleBlocksFromChunk = didLoadVisibleBlocksFromChunk || !block.invisible;
11661169
}
11671170
}
11681171
}
@@ -1193,6 +1196,7 @@ public synchronized void loadChunks(TaskTracker taskTracker, World world, Map<Re
11931196
block = palette.get(id);
11941197
chunkData.setBlockAt(x, y, z, id);
11951198
worldOctree.set(id, cp.x * 16 + x - origin.x, y - origin.y, cp.z * 16 + z - origin.z);
1199+
didLoadVisibleBlocksFromChunk = didLoadVisibleBlocksFromChunk || !block.invisible;
11961200
}
11971201
}
11981202
if (block.isBlockEntity()) {
@@ -1220,7 +1224,7 @@ public synchronized void loadChunks(TaskTracker taskTracker, World world, Map<Re
12201224
}
12211225
}
12221226

1223-
if (!chunkData.isEmpty()) {
1227+
if (!chunkData.isEmpty() && didLoadVisibleBlocksFromChunk) {
12241228
nonEmptyChunks.add(cp);
12251229
if (dimension.getChunk(cp).getVersion() == ChunkVersion.PRE_FLATTENING) {
12261230
legacyChunks.add(cp);
@@ -1248,80 +1252,54 @@ public synchronized void loadChunks(TaskTracker taskTracker, World world, Map<Re
12481252
// Finalize grass and foliage textures.
12491253
// 3x3 box blur.
12501254
ChunkBiomeBlendingHelper chunkBiomeHelper = biomeBlendingHelper.get(cp);
1251-
if(chunkBiomeHelper.isBiomeUsed()) {
1252-
if(biomeBlendingRadius > 0) {
1253-
if(use3dBiomes) {
1254-
ChunkBiomeBlendingHelper[] neighboringChunks = new ChunkBiomeBlendingHelper[]{
1255-
biomeBlendingHelper.get(new ChunkPosition(cp.x - 1, cp.z - 1)),
1256-
biomeBlendingHelper.get(new ChunkPosition(cp.x - 1, cp.z)),
1257-
biomeBlendingHelper.get(new ChunkPosition(cp.x - 1, cp.z + 1)),
1258-
biomeBlendingHelper.get(new ChunkPosition(cp.x, cp.z - 1)),
1259-
biomeBlendingHelper.get(new ChunkPosition(cp.x, cp.z + 1)),
1260-
biomeBlendingHelper.get(new ChunkPosition(cp.x + 1, cp.z - 1)),
1261-
biomeBlendingHelper.get(new ChunkPosition(cp.x + 1, cp.z)),
1262-
biomeBlendingHelper.get(new ChunkPosition(cp.x + 1, cp.z + 1))
1263-
};
1264-
1265-
int[] combinedBiomeTransitions = chunkBiomeHelper.combineAndTrimTransitions(neighboringChunks, biomeBlendingRadius);
1266-
1267-
// When doing 3D blur we use the list of (vertical) biome transition
1268-
// in the chunk or in neighboring ones
1269-
// If there is no transition, a 2D blur is enough, otherwise we only
1270-
// need to compute the colors around the transitions
1271-
1272-
// For example, if loading from y=0 to y=200 with a biome transition at y=20
1273-
// and another one at y=50 and with a blur radius of 2 (5*5*5 box)
1274-
// We can compute a 2D blur at y=0 and use those color for up to y=17
1275-
// For y in [18, 21] we need to compute the real 3D blur (because of the biome transition
1276-
// at y=20 and the blur radius of 2)
1277-
// Then we can compute the 2D blur at y=22 and use those colors for up to y=47
1278-
// And so on, 3D blur for y in [48, 51] and 2D blur for y in [52,200]
1279-
1280-
// As such, in spirit every transition make us compute an additional 16*16*(2*biomeBlendingRadius) 3D blur
1281-
// and a 16*16 2D blur (that can be combined in a 16*16*(2*biomeBlendingRadius+1) 3D blur)
1282-
// (ignoring cases where transition are close to one another which are handled by the code)
1283-
1284-
// Note that having a single (x, y) column that effectively has a biome transition
1285-
// in the chunk are a neighboring chunk causes us to compute the 3D blur for the whole 16*16
1286-
// vertical slice of the chunk. Because vertical biome transition are pretty rare,
1287-
// that's probably ok.
1288-
int nextY = chunkBiomeHelper.getyMinBiomeRelevant();
1289-
1290-
for(int i = 0; i < combinedBiomeTransitions.length; ++i) {
1291-
int transition = combinedBiomeTransitions[i];
1292-
if(nextY < transition - biomeBlendingRadius) {
1293-
// Do a 2d blur to fill up to the height affected by the transition
1294-
BiomeBlendingUtility.chunk2DBlur(
1295-
cp,
1296-
biomeBlendingRadius,
1297-
nextY,
1298-
transition - biomeBlendingRadius,
1299-
origin,
1300-
biomePaletteIdxStructure,
1301-
biomePalette,
1302-
nonEmptyChunks,
1303-
grassTexture,
1304-
foliageTexture,
1305-
dryFoliageTexture,
1306-
waterTexture);
1307-
nextY = transition - biomeBlendingRadius;
1308-
}
1309-
1310-
// Do a 3D blur to fill the next 2*biomeBlendingRadius layers
1311-
// or more if the next transition is close by, in which case
1312-
// both transition (or even more) are handled by a bigger 3D blur
1313-
int maxYWorkedOn = transition + biomeBlendingRadius;
1314-
while(i < combinedBiomeTransitions.length - 1 && maxYWorkedOn >= combinedBiomeTransitions[i + 1] - biomeBlendingRadius) {
1315-
// Extends the 3D blur to enclose the next transition as well
1316-
maxYWorkedOn = combinedBiomeTransitions[i + 1] + biomeBlendingRadius;
1317-
++i;
1318-
}
1319-
int maxYWorkedOnClamped = Math.min(maxYWorkedOn, chunkBiomeHelper.getyMaxBiomeRelevant());
1320-
BiomeBlendingUtility.chunk3DBlur(
1255+
boolean biomeUsed = chunkBiomeHelper.isBiomeUsed();
1256+
if (biomeBlendingRadius > 0) {
1257+
if (use3dBiomes) {
1258+
ChunkBiomeBlendingHelper[] neighboringChunks = new ChunkBiomeBlendingHelper[]{
1259+
biomeBlendingHelper.get(new ChunkPosition(cp.x - 1, cp.z - 1)),
1260+
biomeBlendingHelper.get(new ChunkPosition(cp.x - 1, cp.z)),
1261+
biomeBlendingHelper.get(new ChunkPosition(cp.x - 1, cp.z + 1)),
1262+
biomeBlendingHelper.get(new ChunkPosition(cp.x, cp.z - 1)),
1263+
biomeBlendingHelper.get(new ChunkPosition(cp.x, cp.z + 1)),
1264+
biomeBlendingHelper.get(new ChunkPosition(cp.x + 1, cp.z - 1)),
1265+
biomeBlendingHelper.get(new ChunkPosition(cp.x + 1, cp.z)),
1266+
biomeBlendingHelper.get(new ChunkPosition(cp.x + 1, cp.z + 1))
1267+
};
1268+
1269+
int[] combinedBiomeTransitions = chunkBiomeHelper.combineAndTrimTransitions(neighboringChunks, biomeBlendingRadius);
1270+
1271+
// When doing 3D blur we use the list of (vertical) biome transition
1272+
// in the chunk or in neighboring ones
1273+
// If there is no transition, a 2D blur is enough, otherwise we only
1274+
// need to compute the colors around the transitions
1275+
1276+
// For example, if loading from y=0 to y=200 with a biome transition at y=20
1277+
// and another one at y=50 and with a blur radius of 2 (5*5*5 box)
1278+
// We can compute a 2D blur at y=0 and use those color for up to y=17
1279+
// For y in [18, 21] we need to compute the real 3D blur (because of the biome transition
1280+
// at y=20 and the blur radius of 2)
1281+
// Then we can compute the 2D blur at y=22 and use those colors for up to y=47
1282+
// And so on, 3D blur for y in [48, 51] and 2D blur for y in [52,200]
1283+
1284+
// As such, in spirit every transition make us compute an additional 16*16*(2*biomeBlendingRadius) 3D blur
1285+
// and a 16*16 2D blur (that can be combined in a 16*16*(2*biomeBlendingRadius+1) 3D blur)
1286+
// (ignoring cases where transition are close to one another which are handled by the code)
1287+
1288+
// Note that having a single (x, y) column that effectively has a biome transition
1289+
// in the chunk are a neighboring chunk causes us to compute the 3D blur for the whole 16*16
1290+
// vertical slice of the chunk. Because vertical biome transition are pretty rare,
1291+
// that's probably ok.
1292+
int nextY = chunkBiomeHelper.getyMinBiomeRelevant();
1293+
1294+
for(int i = 0; i < combinedBiomeTransitions.length; ++i) {
1295+
int transition = combinedBiomeTransitions[i];
1296+
if(nextY < transition - biomeBlendingRadius) {
1297+
// Do a 2d blur to fill up to the height affected by the transition
1298+
BiomeBlendingUtility.chunk2DBlur(
13211299
cp,
13221300
biomeBlendingRadius,
13231301
nextY,
1324-
maxYWorkedOnClamped + 1,
1302+
transition - biomeBlendingRadius,
13251303
origin,
13261304
biomePaletteIdxStructure,
13271305
biomePalette,
@@ -1330,30 +1308,42 @@ public synchronized void loadChunks(TaskTracker taskTracker, World world, Map<Re
13301308
foliageTexture,
13311309
dryFoliageTexture,
13321310
waterTexture);
1333-
nextY = maxYWorkedOnClamped + 1;
1311+
nextY = transition - biomeBlendingRadius;
13341312
}
13351313

1336-
// Last 2D blur that extent up to the top
1337-
if(nextY <= chunkBiomeHelper.getyMaxBiomeRelevant()) {
1338-
BiomeBlendingUtility.chunk2DBlur(
1339-
cp,
1340-
biomeBlendingRadius,
1341-
nextY,
1342-
chunkBiomeHelper.getyMaxBiomeRelevant() + 1,
1343-
origin,
1344-
biomePaletteIdxStructure,
1345-
biomePalette,
1346-
nonEmptyChunks,
1347-
grassTexture,
1348-
foliageTexture,
1349-
dryFoliageTexture,
1350-
waterTexture);
1314+
// Do a 3D blur to fill the next 2*biomeBlendingRadius layers
1315+
// or more if the next transition is close by, in which case
1316+
// both transition (or even more) are handled by a bigger 3D blur
1317+
int maxYWorkedOn = transition + biomeBlendingRadius;
1318+
while(i < combinedBiomeTransitions.length - 1 && maxYWorkedOn >= combinedBiomeTransitions[i + 1] - biomeBlendingRadius) {
1319+
// Extends the 3D blur to enclose the next transition as well
1320+
maxYWorkedOn = combinedBiomeTransitions[i + 1] + biomeBlendingRadius;
1321+
++i;
13511322
}
1352-
} else {
1323+
int maxYWorkedOnClamped = Math.min(maxYWorkedOn, chunkBiomeHelper.getyMaxBiomeRelevant());
1324+
BiomeBlendingUtility.chunk3DBlur(
1325+
cp,
1326+
biomeBlendingRadius,
1327+
nextY,
1328+
maxYWorkedOnClamped + 1,
1329+
origin,
1330+
biomePaletteIdxStructure,
1331+
biomePalette,
1332+
nonEmptyChunks,
1333+
grassTexture,
1334+
foliageTexture,
1335+
dryFoliageTexture,
1336+
waterTexture);
1337+
nextY = maxYWorkedOnClamped + 1;
1338+
}
1339+
1340+
// Last 2D blur that extent up to the top
1341+
if(nextY <= chunkBiomeHelper.getyMaxBiomeRelevant()) {
13531342
BiomeBlendingUtility.chunk2DBlur(
13541343
cp,
13551344
biomeBlendingRadius,
1356-
0, 1,
1345+
nextY,
1346+
chunkBiomeHelper.getyMaxBiomeRelevant() + 1,
13571347
origin,
13581348
biomePaletteIdxStructure,
13591349
biomePalette,
@@ -1363,41 +1353,75 @@ public synchronized void loadChunks(TaskTracker taskTracker, World world, Map<Re
13631353
dryFoliageTexture,
13641354
waterTexture);
13651355
}
1356+
1357+
// TODO we could skip blending the grass, foliage and dry foliage textures in this case
1358+
if (!biomeUsed) {
1359+
grassTexture = biomeStructureFactory.create();
1360+
foliageTexture = biomeStructureFactory.create();
1361+
dryFoliageTexture = biomeStructureFactory.create();
1362+
// the water texture is still used to check for loaded chunks and tint the water plane
1363+
}
13661364
} else {
1367-
if(use3dBiomes) {
1368-
for(int sectionY = yMin >> 4; sectionY < (yMax - 1 >> 4) + 1; sectionY++) {
1369-
for(int y = 0; y < 16; y++) {
1370-
int wy = sectionY * 16 + y;
1371-
for(int x = 0; x < 16; ++x) {
1372-
int wx = cp.x * Chunk.X_MAX + x;
1373-
for(int z = 0; z < 16; ++z) {
1374-
int wz = cp.z * Chunk.Z_MAX + z;
1375-
1376-
int id = biomePaletteIdxStructure.get(wx, wy, wz);
1377-
1378-
Biome biome = biomePalette.get(id);
1379-
grassTexture.set(cp.x * 16 + x - origin.x, sectionY * 16 + y - origin.y, cp.z * 16 + z - origin.z, biome.grassColorLinear);
1380-
foliageTexture.set(cp.x * 16 + x - origin.x, sectionY * 16 + y - origin.y, cp.z * 16 + z - origin.z, biome.foliageColorLinear);
1381-
dryFoliageTexture.set(cp.x * 16 + x - origin.x, sectionY * 16 + y - origin.y, cp.z * 16 + z - origin.z, biome.dryFoliageColorLinear);
1382-
waterTexture.set(cp.x * 16 + x - origin.x, sectionY * 16 + y - origin.y, cp.z * 16 + z - origin.z, biome.waterColorLinear);
1383-
}
1365+
BiomeBlendingUtility.chunk2DBlur(
1366+
cp,
1367+
biomeBlendingRadius,
1368+
0, 1,
1369+
origin,
1370+
biomePaletteIdxStructure,
1371+
biomePalette,
1372+
nonEmptyChunks,
1373+
grassTexture,
1374+
foliageTexture,
1375+
dryFoliageTexture,
1376+
waterTexture);
1377+
1378+
// TODO we could skip blending the grass, foliage and dry foliage textures in this case
1379+
if (!biomeUsed) {
1380+
grassTexture = biomeStructureFactory.create();
1381+
foliageTexture = biomeStructureFactory.create();
1382+
dryFoliageTexture = biomeStructureFactory.create();
1383+
// the water texture is still used to check for loaded chunks and tint the water plane
1384+
}
1385+
}
1386+
} else {
1387+
if(use3dBiomes) {
1388+
for(int sectionY = yMin >> 4; sectionY < (yMax - 1 >> 4) + 1; sectionY++) {
1389+
for(int y = 0; y < 16; y++) {
1390+
int wy = sectionY * 16 + y;
1391+
for(int x = 0; x < 16; ++x) {
1392+
int wx = cp.x * Chunk.X_MAX + x;
1393+
for(int z = 0; z < 16; ++z) {
1394+
int wz = cp.z * Chunk.Z_MAX + z;
1395+
1396+
int id = biomePaletteIdxStructure.get(wx, wy, wz);
1397+
1398+
Biome biome = biomePalette.get(id);
1399+
if (biomeUsed) {
1400+
grassTexture.set(cp.x * 16 + x - origin.x, sectionY * 16 + y - origin.y, cp.z * 16 + z - origin.z, biome.grassColorLinear);
1401+
foliageTexture.set(cp.x * 16 + x - origin.x, sectionY * 16 + y - origin.y, cp.z * 16 + z - origin.z, biome.foliageColorLinear);
1402+
dryFoliageTexture.set(cp.x * 16 + x - origin.x, sectionY * 16 + y - origin.y, cp.z * 16 + z - origin.z, biome.dryFoliageColorLinear);
1403+
}
1404+
// the water texture is used to check for loaded chunks and tint the water plane, so we always need that one
1405+
waterTexture.set(cp.x * 16 + x - origin.x, sectionY * 16 + y - origin.y, cp.z * 16 + z - origin.z, biome.waterColorLinear);
13841406
}
13851407
}
13861408
}
1387-
} else {
1388-
for(int x = 0; x < 16; ++x) {
1389-
int wx = cp.x * 16 + x;
1390-
for(int z = 0; z < 16; ++z) {
1391-
int wz = cp.z * 16 + z;
1392-
1393-
int id = biomePaletteIdxStructure.get(wx, 0, wz);
1394-
Biome biome = biomePalette.get(id);
1395-
1409+
}
1410+
} else {
1411+
for(int x = 0; x < 16; ++x) {
1412+
int wx = cp.x * 16 + x;
1413+
for(int z = 0; z < 16; ++z) {
1414+
int wz = cp.z * 16 + z;
1415+
1416+
int id = biomePaletteIdxStructure.get(wx, 0, wz);
1417+
Biome biome = biomePalette.get(id);
1418+
if (biomeUsed) {
13961419
grassTexture.set(cp.x * 16 + x - origin.x, 0, cp.z * 16 + z - origin.z, biome.grassColorLinear);
13971420
foliageTexture.set(cp.x * 16 + x - origin.x, 0, cp.z * 16 + z - origin.z, biome.foliageColorLinear);
13981421
dryFoliageTexture.set(cp.x * 16 + x - origin.x, 0, cp.z * 16 + z - origin.z, biome.dryFoliageColorLinear);
1399-
waterTexture.set(cp.x * 16 + x - origin.x, 0, cp.z * 16 + z - origin.z, biome.waterColorLinear);
14001422
}
1423+
// the water texture is used to check for loaded chunks and tint the water plane, so we always need that one
1424+
waterTexture.set(cp.x * 16 + x - origin.x, 0, cp.z * 16 + z - origin.z, biome.waterColorLinear);
14011425
}
14021426
}
14031427
}

0 commit comments

Comments
 (0)