Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve mipper by weighting based on block type and luminance #66

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/java/me/cortex/voxy/client/config/VoxyConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public static VoxyConfig loadOrCreate() {
config.defaultSaveConfig = ContextSelectionSystem.DEFAULT_STORAGE_CONFIG;
return config;
}

public void save() {
//Unsafe, todo: fixme! needs to be atomic!
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,10 @@ public static void mipSection(VoxelizedSection section, Mapper mapper) {
for (int z = 0; z < 16; z += 2) {
for (int x = 0; x < 16; x += 2) {
data[16*16*16 + i++] =
Mipper.mip(
data[G(x, y, z)], data[G(x+1, y, z)], data[G(x, y, z+1)], data[G(x+1, y, z+1)],
data[G(x, y+1, z)], data[G(x+1, y+1, z)], data[G(x, y+1, z+1)], data[G(x+1, y+1, z+1)],
Mipper.mip(new long[]{
data[G(x, y, z)], data[G(x+1, y, z)], data[G(x, y, z+1)], data[G(x+1, y, z+1)],
data[G(x, y+1, z)], data[G(x+1, y+1, z)], data[G(x, y+1, z+1)], data[G(x+1, y+1, z+1)]
},
mapper);
}
}
Expand All @@ -104,9 +105,10 @@ public static void mipSection(VoxelizedSection section, Mapper mapper) {
for (int z = 0; z < 8; z += 2) {
for (int x = 0; x < 8; x += 2) {
data[16*16*16 + 8*8*8 + i++] =
Mipper.mip(
data[H(x, y, z)], data[H(x+1, y, z)], data[H(x, y, z+1)], data[H(x+1, y, z+1)],
data[H(x, y+1, z)], data[H(x+1, y+1, z)], data[H(x, y+1, z+1)], data[H(x+1, y+1, z+1)],
Mipper.mip(new long[]{
data[H(x, y, z)], data[H(x + 1, y, z)], data[H(x, y, z + 1)], data[H(x + 1, y, z + 1)],
data[H(x, y + 1, z)], data[H(x + 1, y + 1, z)], data[H(x, y + 1, z + 1)], data[H(x + 1, y + 1, z + 1)]
},
mapper);
}
}
Expand All @@ -118,19 +120,21 @@ public static void mipSection(VoxelizedSection section, Mapper mapper) {
for (int z = 0; z < 4; z += 2) {
for (int x = 0; x < 4; x += 2) {
data[16*16*16 + 8*8*8 + 4*4*4 + i++] =
Mipper.mip(
data[I(x, y, z)], data[I(x+1, y, z)], data[I(x, y, z+1)], data[I(x+1, y, z+1)],
data[I(x, y+1, z)], data[I(x+1, y+1, z)], data[I(x, y+1, z+1)], data[I(x+1, y+1, z+1)],
Mipper.mip(new long[]{
data[I(x, y, z)], data[I(x + 1, y, z)], data[I(x, y, z + 1)], data[I(x + 1, y, z + 1)],
data[I(x, y + 1, z)], data[I(x + 1, y + 1, z)], data[I(x, y + 1, z + 1)], data[I(x + 1, y + 1, z + 1)],
},
mapper);
}
}
}

//Mip L4
data[16*16*16 + 8*8*8 + 4*4*4 + 2*2*2] =
Mipper.mip(
data[J(0, 0, 0)], data[J(1, 0, 0)], data[J(0, 0, 1)], data[J(1, 0, 1)],
data[J(0, 1, 0)], data[J(1, 1, 0)], data[J(0, 1, 1)], data[J(1, 1, 1)],
Mipper.mip(new long[]{
data[J(0, 0, 0)], data[J(1, 0, 0)], data[J(0, 0, 1)], data[J(1, 0, 1)],
data[J(0, 1, 0)], data[J(1, 1, 0)], data[J(0, 1, 1)], data[J(1, 1, 1)],
},
mapper);
}
}
153 changes: 111 additions & 42 deletions src/main/java/me/cortex/voxy/common/world/other/Mipper.java
Original file line number Diff line number Diff line change
@@ -1,53 +1,122 @@
package me.cortex.voxy.common.world.other;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;

import java.util.HashMap;
import java.util.Map;

import static me.cortex.voxy.common.world.other.Mapper.withLight;

//Mipper for data
public class Mipper {
//TODO: also pass in the level its mipping from, cause at lower levels you want to preserve block details
// but at higher details you want more air
public static long mip(long I000, long I100, long I001, long I101,
long I010, long I110, long I011, long I111,
Mapper mapper) {
//TODO: mip with respect to all the variables, what that means is take whatever has the highest count and return that
//TODO: also average out the light level and set that as the new light level
//For now just take the most top corner

//TODO: i think it needs to compute the _max_ light level, since e.g. if a point is bright irl
// you can see it from really really damn far away.
// it could be a heavily weighted average with a huge preference to the top most lighting value
if (!Mapper.isAir(I111)) {
return I111;
}
if (!Mapper.isAir(I110)) {
return I110;
}
if (!Mapper.isAir(I011)) {
return I011;
}
if (!Mapper.isAir(I010)) {
return I010;
}
if (!Mapper.isAir(I101)) {
return I101;
}
if (!Mapper.isAir(I100)) {
return I100;
}
if (!Mapper.isAir(I001)) {
return I001;
}
if (!Mapper.isAir(I000)) {
return I000;
// public static long mip(long I000, long I100, long I001, long I101,
// long I010, long I110, long I011, long I111,
// Mapper mapper) {
// //TODO: mip with respect to all the variables, what that means is take whatever has the highest count and return that
// //TODO: also average out the light level and set that as the new light level
// //For now just take the most top corner
//
// //TODO: i think it needs to compute the _max_ light level, since e.g. if a point is bright irl
// // you can see it from really really damn far away.
// // it could be a heavily weighted average with a huge preference to the top most lighting value
// if (!Mapper.isAir(I111)) {
// return I111;
// }
// if (!Mapper.isAir(I110)) {
// return I110;
// }
// if (!Mapper.isAir(I011)) {
// return I011;
// }
// if (!Mapper.isAir(I010)) {
// return I010;
// }
// if (!Mapper.isAir(I101)) {
// return I101;
// }
// if (!Mapper.isAir(I100)) {
// return I100;
// }
// if (!Mapper.isAir(I001)) {
// return I001;
// }
// if (!Mapper.isAir(I000)) {
// return I000;
// }
//
// int blockLight = (Mapper.getLightId(I000)&0xF0)+(Mapper.getLightId(I001)&0xF0)+(Mapper.getLightId(I010)&0xF0)+(Mapper.getLightId(I011)&0xF0)+
// (Mapper.getLightId(I100)&0xF0)+(Mapper.getLightId(I101)&0xF0)+(Mapper.getLightId(I110)&0xF0)+(Mapper.getLightId(I111)&0xF0);
// int skyLight = (Mapper.getLightId(I000)&0x0F)+(Mapper.getLightId(I001)&0x0F)+(Mapper.getLightId(I010)&0x0F)+(Mapper.getLightId(I011)&0x0F)+
// (Mapper.getLightId(I100)&0x0F)+(Mapper.getLightId(I101)&0x0F)+(Mapper.getLightId(I110)&0x0F)+(Mapper.getLightId(I111)&0x0F);
// blockLight = blockLight/8;
// skyLight = (int) Math.ceil((double)skyLight/8);
//
// return withLight(I111, (blockLight<<4)|skyLight);
// }

//TODO: also pass in the level its mipping from, cause at lower levels you want to preserve block details
// but at higher details you want more air

private static HashMap<Block, Float> blockWeights = new HashMap<>(
Map.of(
Blocks.AIR, 0.0f,
Blocks.CAVE_AIR, 0.0f,
Blocks.VOID_AIR, 0.0f,
Blocks.SHORT_GRASS, 0.25f,
Blocks.TALL_GRASS, 0.5f,
Blocks.WATER, 0.75f,
Blocks.DIRT_PATH, 1.5f,
Blocks.LAVA, 1.5f
)
);

private static float getWeight(BlockState blockState) {
int luminance = blockState.getLuminance();
float brightnessBoost = 1.0f + (luminance / 31.0f);

float weight = blockWeights.getOrDefault(blockState.getBlock(), 1.0f);

return weight * brightnessBoost;
}

public static long mip(long[] blocks, Mapper mapper) {
Map<Integer, Float> computedWeights = new HashMap<>();
float runningMax = -1.0f;
long maxIndex = 0;

int avgBlockLight = 0;
int avgSkyLight = 0;

for (int i = 7; i >= 0; i--) { // Iterate in reverse order to prioritize the top blocks
long block = blocks[i];

int blockId = Mapper.getBlockId(block);
int lightLevel = Mapper.getLightId(block);
BlockState blockState = mapper.getBlockStateFromBlockId(blockId);

float newWeight = computedWeights.getOrDefault(blockId, 0.0f) + getWeight(blockState);
computedWeights.put(blockId, newWeight);

if (newWeight > runningMax) {
runningMax = newWeight;
maxIndex = block;
}

avgBlockLight += (lightLevel & 0xF0) >> 4;

if(blockState.isOf(Blocks.SNOW) && i >= 4 ) { // If snow and a top block, remove lighting from block below
long blockBelow = blocks[i - 4];
avgSkyLight -= Mapper.getLightId(blockBelow) & 0x0F;
} else {
avgSkyLight += lightLevel & 0x0F;
}
}

int blockLight = (Mapper.getLightId(I000)&0xF0)+(Mapper.getLightId(I001)&0xF0)+(Mapper.getLightId(I010)&0xF0)+(Mapper.getLightId(I011)&0xF0)+
(Mapper.getLightId(I100)&0xF0)+(Mapper.getLightId(I101)&0xF0)+(Mapper.getLightId(I110)&0xF0)+(Mapper.getLightId(I111)&0xF0);
int skyLight = (Mapper.getLightId(I000)&0x0F)+(Mapper.getLightId(I001)&0x0F)+(Mapper.getLightId(I010)&0x0F)+(Mapper.getLightId(I011)&0x0F)+
(Mapper.getLightId(I100)&0x0F)+(Mapper.getLightId(I101)&0x0F)+(Mapper.getLightId(I110)&0x0F)+(Mapper.getLightId(I111)&0x0F);
blockLight = blockLight/8;
skyLight = (int) Math.ceil((double)skyLight/8);
avgBlockLight /= 8;
avgSkyLight = (int) Math.ceil((double) avgSkyLight / 8);

return withLight(I111, (blockLight<<4)|skyLight);
return withLight(maxIndex, (avgBlockLight << 4) | avgSkyLight);
}
}