Теперь строится worldinfo для будующей симуляции
This commit is contained in:
@@ -0,0 +1,49 @@
|
|||||||
|
package su.divan2000.veila.client.render.fog;
|
||||||
|
|
||||||
|
public record FogBlockProperties(
|
||||||
|
boolean solid,
|
||||||
|
int sign,
|
||||||
|
int magnitude
|
||||||
|
) {
|
||||||
|
public static final FogBlockProperties DEFAULT = new FogBlockProperties(false, 0, 0);
|
||||||
|
|
||||||
|
public FogBlockProperties {
|
||||||
|
if (sign < -1 || sign > 1) {
|
||||||
|
throw new IllegalArgumentException("sign must be -1, 0, or 1");
|
||||||
|
}
|
||||||
|
if (magnitude < 0 || magnitude > 63) {
|
||||||
|
throw new IllegalArgumentException("magnitude must be 0-63");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Упаковывает свойства в один байт:
|
||||||
|
* Бит 7: solid (1 = solid)
|
||||||
|
* Бит 6: sign (0 = source/neutral, 1 = absorber)
|
||||||
|
* Биты 0-5: magnitude (0-63)
|
||||||
|
*/
|
||||||
|
public byte pack() {
|
||||||
|
int packed = 0;
|
||||||
|
|
||||||
|
if (solid) {
|
||||||
|
packed |= 0b10000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sign < 0) {
|
||||||
|
packed |= 0b01000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
packed |= (magnitude & 0b00111111);
|
||||||
|
|
||||||
|
return (byte) packed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FogBlockProperties unpack(byte packed) {
|
||||||
|
boolean solid = (packed & 0b10000000) != 0;
|
||||||
|
boolean isAbsorber = (packed & 0b01000000) != 0;
|
||||||
|
int magnitude = packed & 0b00111111;
|
||||||
|
int sign = isAbsorber ? -1 : (magnitude > 0 ? 1 : 0);
|
||||||
|
|
||||||
|
return new FogBlockProperties(solid, sign, magnitude);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package su.divan2000.veila.client.render.fog;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.fluid.Fluids;
|
||||||
|
import net.minecraft.registry.Registries;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
|
||||||
|
public final class FogBlockRegistry {
|
||||||
|
|
||||||
|
private static final byte[] BLOCK_CACHE;
|
||||||
|
private static final boolean[] BLOCK_CACHE_INITIALIZED;
|
||||||
|
|
||||||
|
// Предвычисленное значение для waterlogged блоков (вода)
|
||||||
|
private static final byte WATER_VALUE;
|
||||||
|
|
||||||
|
static {
|
||||||
|
int blockCount = Registries.BLOCK.size();
|
||||||
|
BLOCK_CACHE = new byte[blockCount];
|
||||||
|
BLOCK_CACHE_INITIALIZED = new boolean[blockCount];
|
||||||
|
|
||||||
|
// Waterlogged блок всегда содержит воду
|
||||||
|
WATER_VALUE = new FogBlockProperties(true, 1, 60).pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FogBlockRegistry() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte getPackedProperties(BlockState state) {
|
||||||
|
// СНАЧАЛА проверяем конкретно воду (waterlogged или обычный блок воды)
|
||||||
|
if (state.getFluidState().getFluid() == Fluids.WATER) {
|
||||||
|
return WATER_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Block block = state.getBlock();
|
||||||
|
int id = Registries.BLOCK.getRawId(block);
|
||||||
|
|
||||||
|
if (BLOCK_CACHE_INITIALIZED[id]) {
|
||||||
|
return BLOCK_CACHE[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
byte packed = computePackedProperties(state);
|
||||||
|
BLOCK_CACHE[id] = packed;
|
||||||
|
BLOCK_CACHE_INITIALIZED[id] = true;
|
||||||
|
|
||||||
|
return packed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte computePackedProperties(BlockState state) {
|
||||||
|
Block block = state.getBlock();
|
||||||
|
boolean solid = computeSolid(state);
|
||||||
|
|
||||||
|
// Источники тумана (sign = +1)
|
||||||
|
// WATER уже обработан в getPackedProperties
|
||||||
|
if (block == Blocks.GRASS || block == Blocks.TALL_GRASS || block == Blocks.FERN) {
|
||||||
|
return new FogBlockProperties(solid, 1, 10).pack();
|
||||||
|
}
|
||||||
|
if (block == Blocks.VINE) {
|
||||||
|
return new FogBlockProperties(solid, 1, 5).pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Поглотители тумана (sign = -1)
|
||||||
|
if (block == Blocks.LAVA) {
|
||||||
|
return new FogBlockProperties(solid, -1, 50).pack();
|
||||||
|
}
|
||||||
|
if (block == Blocks.MAGMA_BLOCK) {
|
||||||
|
return new FogBlockProperties(solid, -1, 40).pack();
|
||||||
|
}
|
||||||
|
if (block == Blocks.FIRE || block == Blocks.SOUL_FIRE) {
|
||||||
|
return new FogBlockProperties(solid, -1, 30).pack();
|
||||||
|
}
|
||||||
|
if (block == Blocks.CAMPFIRE || block == Blocks.SOUL_CAMPFIRE) {
|
||||||
|
return new FogBlockProperties(solid, -1, 25).pack();
|
||||||
|
}
|
||||||
|
if (block == Blocks.TORCH || block == Blocks.WALL_TORCH ||
|
||||||
|
block == Blocks.SOUL_TORCH || block == Blocks.SOUL_WALL_TORCH) {
|
||||||
|
return new FogBlockProperties(solid, -1, 15).pack();
|
||||||
|
}
|
||||||
|
if (block == Blocks.LANTERN || block == Blocks.SOUL_LANTERN) {
|
||||||
|
return new FogBlockProperties(solid, -1, 10).pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Нейтральные блоки (sign = 0)
|
||||||
|
return new FogBlockProperties(solid, 0, 0).pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private static boolean computeSolid(BlockState state) {
|
||||||
|
if (state.isAir()) return false;
|
||||||
|
// Waterlogged уже обработан в getPackedProperties
|
||||||
|
if (!state.getFluidState().isEmpty()) return true; // лава и другие жидкости
|
||||||
|
if (state.isIn(BlockTags.LEAVES)) return false;
|
||||||
|
return state.blocksMovement();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,17 +20,7 @@ public final class FogChunkProvider {
|
|||||||
return client.world.getChunkManager().getWorldChunk(chunkX, chunkZ, false) != null;
|
return client.world.getChunkManager().getWorldChunk(chunkX, chunkZ, false) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float computeVoxelValue(BlockState state) {
|
public static boolean fillChunkIntoArray(int chunkX, int chunkZ, byte[] array) {
|
||||||
if (state.isOf(Blocks.POPPY)) {
|
|
||||||
return 0.2f;
|
|
||||||
} else if (state.isOf(Blocks.GRASS)) {
|
|
||||||
return 0.4f;
|
|
||||||
} else {
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean fillChunkIntoArray(int chunkX, int chunkZ, float[] array) {
|
|
||||||
MinecraftClient client = MinecraftClient.getInstance();
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
|
||||||
if (!isChunkLoaded(chunkX, chunkZ)) return false;
|
if (!isChunkLoaded(chunkX, chunkZ)) return false;
|
||||||
@@ -42,10 +32,9 @@ public final class FogChunkProvider {
|
|||||||
int topYExclusive = bottomY + sections.length * 16;
|
int topYExclusive = bottomY + sections.length * 16;
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
byte airValue = FogBlockRegistry.getPackedProperties(Blocks.AIR.getDefaultState());
|
||||||
|
|
||||||
// Порядок циклов Z -> Y -> X критичен для glTexSubImage3D
|
|
||||||
for (int z = 0; z < FogWorldVolume.CHUNK_SIZE; z++) {
|
for (int z = 0; z < FogWorldVolume.CHUNK_SIZE; z++) {
|
||||||
// Кэшируем секции и их состояние
|
|
||||||
int currentSectionIndex = -1;
|
int currentSectionIndex = -1;
|
||||||
ChunkSection currentSection = null;
|
ChunkSection currentSection = null;
|
||||||
PalettedContainer<BlockState> currentContainer = null;
|
PalettedContainer<BlockState> currentContainer = null;
|
||||||
@@ -54,9 +43,8 @@ public final class FogChunkProvider {
|
|||||||
for (int y = 0; y < FogWorldVolume.SIZE_Y; y++) {
|
for (int y = 0; y < FogWorldVolume.SIZE_Y; y++) {
|
||||||
int worldY = FogWorldVolume.MIN_Y + y;
|
int worldY = FogWorldVolume.MIN_Y + y;
|
||||||
|
|
||||||
// За пределами мира (например, ниже -64)
|
|
||||||
if (worldY < bottomY || worldY >= topYExclusive) {
|
if (worldY < bottomY || worldY >= topYExclusive) {
|
||||||
Arrays.fill(array, index, index + FogWorldVolume.CHUNK_SIZE, 0.0f);
|
Arrays.fill(array, index, index + FogWorldVolume.CHUNK_SIZE, airValue);
|
||||||
index += FogWorldVolume.CHUNK_SIZE;
|
index += FogWorldVolume.CHUNK_SIZE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -76,25 +64,25 @@ public final class FogChunkProvider {
|
|||||||
|
|
||||||
int localY = worldY & 15;
|
int localY = worldY & 15;
|
||||||
|
|
||||||
// ОПТИМИЗАЦИЯ: Если текущая секция полностью пустая (только воздух)
|
|
||||||
if (currentIsEmpty) {
|
if (currentIsEmpty) {
|
||||||
Arrays.fill(array, index, index + FogWorldVolume.CHUNK_SIZE, 0.0f);
|
Arrays.fill(array, index, index + FogWorldVolume.CHUNK_SIZE, airValue);
|
||||||
index += FogWorldVolume.CHUNK_SIZE;
|
index += FogWorldVolume.CHUNK_SIZE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Предварительное вычисление базового индекса для строки Y и Z
|
|
||||||
// Формула локального индекса в секции 16x16x16: (y << 8) | (z << 4) | x
|
|
||||||
int baseIndex = (localY << 8) | (z << 4);
|
int baseIndex = (localY << 8) | (z << 4);
|
||||||
|
|
||||||
for (int x = 0; x < FogWorldVolume.CHUNK_SIZE; x++) {
|
for (int x = 0; x < FogWorldVolume.CHUNK_SIZE; x++) {
|
||||||
BlockState currentBlock = currentContainer.get(baseIndex | x);
|
BlockState currentBlock = currentContainer.get(baseIndex | x);
|
||||||
|
array[index++] = FogBlockRegistry.getPackedProperties(currentBlock);
|
||||||
array[index++] = computeVoxelValue(currentBlock);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte computePackedVoxelValue(BlockState state) {
|
||||||
|
return FogBlockRegistry.getPackedProperties(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ public final class FogChunkStreamer {
|
|||||||
private static final ChunkStatus[] statuses = new ChunkStatus[TOTAL_CHUNKS];
|
private static final ChunkStatus[] statuses = new ChunkStatus[TOTAL_CHUNKS];
|
||||||
private static final boolean[] readyToUpload = new boolean[TOTAL_CHUNKS];
|
private static final boolean[] readyToUpload = new boolean[TOTAL_CHUNKS];
|
||||||
|
|
||||||
private static final float[][] preparedData = new float[TOTAL_CHUNKS][CHUNK_DATA_SIZE];
|
private static final byte[][] preparedData = new byte[TOTAL_CHUNKS][CHUNK_DATA_SIZE];
|
||||||
private static final int[] preparedWorldChunkX = new int[TOTAL_CHUNKS];
|
private static final int[] preparedWorldChunkX = new int[TOTAL_CHUNKS];
|
||||||
private static final int[] preparedWorldChunkZ = new int[TOTAL_CHUNKS];
|
private static final int[] preparedWorldChunkZ = new int[TOTAL_CHUNKS];
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ public final class FogChunkStreamer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Вычисляем значение для этого вокселя
|
// Вычисляем значение для этого вокселя
|
||||||
float value = FogChunkProvider.computeVoxelValue(event.newState);
|
byte value = FogChunkProvider.computePackedVoxelValue(event.newState());
|
||||||
|
|
||||||
// Обновляем один воксель в текстуре
|
// Обновляем один воксель в текстуре
|
||||||
FogWorldVolume.updateSingleVoxel(
|
FogWorldVolume.updateSingleVoxel(
|
||||||
|
|||||||
@@ -3,18 +3,12 @@ package su.divan2000.veila.client.render.fog;
|
|||||||
import org.lwjgl.BufferUtils;
|
import org.lwjgl.BufferUtils;
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
import org.lwjgl.opengl.GL12;
|
import org.lwjgl.opengl.GL12;
|
||||||
import org.lwjgl.opengl.GL13;
|
|
||||||
import org.lwjgl.opengl.GL30;
|
import org.lwjgl.opengl.GL30;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
|
|
||||||
public final class FogWorldVolume {
|
public final class FogWorldVolume {
|
||||||
|
|
||||||
/*
|
|
||||||
* Размер всего объёма
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static final int SIZE_X = 256;
|
public static final int SIZE_X = 256;
|
||||||
public static final int SIZE_Z = 256;
|
public static final int SIZE_Z = 256;
|
||||||
|
|
||||||
@@ -22,156 +16,81 @@ public final class FogWorldVolume {
|
|||||||
public static final int MAX_Y = 320;
|
public static final int MAX_Y = 320;
|
||||||
public static final int SIZE_Y = MAX_Y - MIN_Y;
|
public static final int SIZE_Y = MAX_Y - MIN_Y;
|
||||||
|
|
||||||
/*
|
|
||||||
* Размер одного чанка
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static final int CHUNK_SIZE = 16;
|
public static final int CHUNK_SIZE = 16;
|
||||||
|
|
||||||
public static final int CHUNKS_X = SIZE_X / CHUNK_SIZE;
|
public static final int CHUNKS_X = SIZE_X / CHUNK_SIZE;
|
||||||
public static final int CHUNKS_Z = SIZE_Z / CHUNK_SIZE;
|
public static final int CHUNKS_Z = SIZE_Z / CHUNK_SIZE;
|
||||||
|
|
||||||
/*
|
|
||||||
* OpenGL
|
|
||||||
*/
|
|
||||||
|
|
||||||
private static int texture = -1;
|
private static int texture = -1;
|
||||||
|
|
||||||
/*
|
private static final byte[] ZEROS_ARRAY;
|
||||||
* Буфер для одного чанка
|
|
||||||
*
|
|
||||||
* 16 × 384 × 16
|
|
||||||
*/
|
|
||||||
|
|
||||||
private static final float[] ZEROS_ARRAY = new float[CHUNK_SIZE * SIZE_Y * CHUNK_SIZE];
|
|
||||||
static {
|
static {
|
||||||
java.util.Arrays.fill(ZEROS_ARRAY, 0.0f);
|
ZEROS_ARRAY = new byte[CHUNK_SIZE * SIZE_Y * CHUNK_SIZE];
|
||||||
|
byte airValue = new FogBlockProperties(false, 0, 0).pack();
|
||||||
|
java.util.Arrays.fill(ZEROS_ARRAY, airValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final FloatBuffer CHUNK_BUFFER =
|
private static final ByteBuffer CHUNK_BUFFER =
|
||||||
BufferUtils.createFloatBuffer(
|
BufferUtils.createByteBuffer(CHUNK_SIZE * SIZE_Y * CHUNK_SIZE);
|
||||||
CHUNK_SIZE *
|
|
||||||
SIZE_Y *
|
|
||||||
CHUNK_SIZE
|
|
||||||
);
|
|
||||||
|
|
||||||
|
private static final ByteBuffer SINGLE_VOXEL_BUFFER =
|
||||||
private static final FloatBuffer SINGLE_VOXEL_BUFFER =
|
BufferUtils.createByteBuffer(1);
|
||||||
BufferUtils.createFloatBuffer(1);
|
|
||||||
|
|
||||||
private FogWorldVolume() {
|
private FogWorldVolume() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
|
if (texture != -1) return;
|
||||||
if (texture != -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
texture = GL11.glGenTextures();
|
texture = GL11.glGenTextures();
|
||||||
|
|
||||||
GL11.glBindTexture(
|
GL11.glBindTexture(GL12.GL_TEXTURE_3D, texture);
|
||||||
GL12.GL_TEXTURE_3D,
|
|
||||||
texture
|
|
||||||
);
|
|
||||||
|
|
||||||
GL30.glTexImage3D(
|
GL30.glTexImage3D(
|
||||||
GL12.GL_TEXTURE_3D,
|
GL12.GL_TEXTURE_3D,
|
||||||
0,
|
0,
|
||||||
GL30.GL_R16F,
|
GL30.GL_R8UI,
|
||||||
SIZE_X,
|
SIZE_X,
|
||||||
SIZE_Y,
|
SIZE_Y,
|
||||||
SIZE_Z,
|
SIZE_Z,
|
||||||
0,
|
0,
|
||||||
GL11.GL_RED,
|
GL30.GL_RED_INTEGER,
|
||||||
GL11.GL_FLOAT,
|
GL11.GL_UNSIGNED_BYTE,
|
||||||
(ByteBuffer) null
|
(ByteBuffer) null
|
||||||
);
|
);
|
||||||
|
|
||||||
GL11.glTexParameteri(
|
GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
||||||
GL12.GL_TEXTURE_3D,
|
GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||||
GL11.GL_TEXTURE_MIN_FILTER,
|
|
||||||
GL11.GL_LINEAR
|
|
||||||
);
|
|
||||||
|
|
||||||
GL11.glTexParameteri(
|
GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL12.GL_TEXTURE_WRAP_S, GL12.GL_REPEAT);
|
||||||
GL12.GL_TEXTURE_3D,
|
GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL12.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
|
||||||
GL11.GL_TEXTURE_MAG_FILTER,
|
GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL12.GL_TEXTURE_WRAP_R, GL12.GL_REPEAT);
|
||||||
GL11.GL_LINEAR
|
|
||||||
);
|
|
||||||
|
|
||||||
GL11.glTexParameteri(
|
GL11.glBindTexture(GL12.GL_TEXTURE_3D, 0);
|
||||||
GL12.GL_TEXTURE_3D,
|
|
||||||
GL12.GL_TEXTURE_WRAP_S,
|
|
||||||
GL12.GL_REPEAT
|
|
||||||
);
|
|
||||||
|
|
||||||
GL11.glTexParameteri(
|
|
||||||
GL12.GL_TEXTURE_3D,
|
|
||||||
GL12.GL_TEXTURE_WRAP_T,
|
|
||||||
GL12.GL_CLAMP_TO_EDGE
|
|
||||||
);
|
|
||||||
|
|
||||||
GL11.glTexParameteri(
|
|
||||||
GL12.GL_TEXTURE_3D,
|
|
||||||
GL12.GL_TEXTURE_WRAP_R,
|
|
||||||
GL12.GL_REPEAT
|
|
||||||
);
|
|
||||||
|
|
||||||
GL11.glBindTexture(
|
|
||||||
GL12.GL_TEXTURE_3D,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void clear() {
|
public static void clear() {
|
||||||
|
|
||||||
CHUNK_BUFFER.clear();
|
CHUNK_BUFFER.clear();
|
||||||
|
CHUNK_BUFFER.put(ZEROS_ARRAY);
|
||||||
int size =
|
|
||||||
CHUNK_SIZE *
|
|
||||||
SIZE_Y *
|
|
||||||
CHUNK_SIZE;
|
|
||||||
|
|
||||||
for (int i = 0; i < size; i++)
|
|
||||||
CHUNK_BUFFER.put(0.0f);
|
|
||||||
|
|
||||||
CHUNK_BUFFER.flip();
|
CHUNK_BUFFER.flip();
|
||||||
|
|
||||||
GL11.glBindTexture(
|
GL11.glBindTexture(GL12.GL_TEXTURE_3D, texture);
|
||||||
GL12.GL_TEXTURE_3D,
|
|
||||||
texture
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int chunkZ = 0; chunkZ < CHUNKS_Z; chunkZ++) {
|
for (int chunkZ = 0; chunkZ < CHUNKS_Z; chunkZ++) {
|
||||||
|
|
||||||
for (int chunkX = 0; chunkX < CHUNKS_X; chunkX++) {
|
for (int chunkX = 0; chunkX < CHUNKS_X; chunkX++) {
|
||||||
|
uploadChunk(chunkX, chunkZ, CHUNK_BUFFER);
|
||||||
uploadChunk(
|
|
||||||
chunkX,
|
|
||||||
chunkZ,
|
|
||||||
CHUNK_BUFFER
|
|
||||||
);
|
|
||||||
|
|
||||||
CHUNK_BUFFER.rewind();
|
CHUNK_BUFFER.rewind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GL11.glBindTexture(
|
GL11.glBindTexture(GL12.GL_TEXTURE_3D, 0);
|
||||||
GL12.GL_TEXTURE_3D,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void uploadChunk(
|
public static void uploadChunk(int textureChunkX, int textureChunkZ, ByteBuffer data) {
|
||||||
int textureChunkX,
|
|
||||||
int textureChunkZ,
|
|
||||||
FloatBuffer data
|
|
||||||
) {
|
|
||||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, texture);
|
GL11.glBindTexture(GL12.GL_TEXTURE_3D, texture);
|
||||||
|
|
||||||
// Сбрасываем ВСЕ pixel store параметры, которые мог оставить Minecraft
|
|
||||||
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
|
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
|
||||||
GL11.glPixelStorei(GL11.GL_UNPACK_ROW_LENGTH, 0);
|
GL11.glPixelStorei(GL11.GL_UNPACK_ROW_LENGTH, 0);
|
||||||
GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_PIXELS, 0);
|
GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_PIXELS, 0);
|
||||||
@@ -180,17 +99,14 @@ public final class FogWorldVolume {
|
|||||||
GL30.glTexSubImage3D(
|
GL30.glTexSubImage3D(
|
||||||
GL12.GL_TEXTURE_3D,
|
GL12.GL_TEXTURE_3D,
|
||||||
0,
|
0,
|
||||||
|
|
||||||
textureChunkX * CHUNK_SIZE,
|
textureChunkX * CHUNK_SIZE,
|
||||||
0,
|
0,
|
||||||
textureChunkZ * CHUNK_SIZE,
|
textureChunkZ * CHUNK_SIZE,
|
||||||
|
|
||||||
CHUNK_SIZE,
|
CHUNK_SIZE,
|
||||||
SIZE_Y,
|
SIZE_Y,
|
||||||
CHUNK_SIZE,
|
CHUNK_SIZE,
|
||||||
|
GL30.GL_RED_INTEGER,
|
||||||
GL11.GL_RED,
|
GL11.GL_UNSIGNED_BYTE,
|
||||||
GL11.GL_FLOAT,
|
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -203,7 +119,7 @@ public final class FogWorldVolume {
|
|||||||
int localX,
|
int localX,
|
||||||
int localY,
|
int localY,
|
||||||
int localZ,
|
int localZ,
|
||||||
float value
|
byte value
|
||||||
) {
|
) {
|
||||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, texture);
|
GL11.glBindTexture(GL12.GL_TEXTURE_3D, texture);
|
||||||
|
|
||||||
@@ -223,8 +139,8 @@ public final class FogWorldVolume {
|
|||||||
localY,
|
localY,
|
||||||
textureChunkZ * CHUNK_SIZE + localZ,
|
textureChunkZ * CHUNK_SIZE + localZ,
|
||||||
1, 1, 1,
|
1, 1, 1,
|
||||||
GL11.GL_RED,
|
GL30.GL_RED_INTEGER,
|
||||||
GL11.GL_FLOAT,
|
GL11.GL_UNSIGNED_BYTE,
|
||||||
SINGLE_VOXEL_BUFFER
|
SINGLE_VOXEL_BUFFER
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -232,7 +148,7 @@ public final class FogWorldVolume {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void uploadZeros(int textureChunkX, int textureChunkZ) {
|
public static void uploadZeros(int textureChunkX, int textureChunkZ) {
|
||||||
FloatBuffer buffer = chunkBuffer();
|
ByteBuffer buffer = chunkBuffer();
|
||||||
buffer.put(ZEROS_ARRAY);
|
buffer.put(ZEROS_ARRAY);
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
uploadChunk(textureChunkX, textureChunkZ, buffer);
|
uploadChunk(textureChunkX, textureChunkZ, buffer);
|
||||||
@@ -241,23 +157,20 @@ public final class FogWorldVolume {
|
|||||||
public static void uploadChunkFromArray(
|
public static void uploadChunkFromArray(
|
||||||
int textureChunkX,
|
int textureChunkX,
|
||||||
int textureChunkZ,
|
int textureChunkZ,
|
||||||
float[] data
|
byte[] data
|
||||||
) {
|
) {
|
||||||
FloatBuffer buffer = chunkBuffer();
|
ByteBuffer buffer = chunkBuffer();
|
||||||
buffer.put(data);
|
buffer.put(data);
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
uploadChunk(textureChunkX, textureChunkZ, buffer);
|
uploadChunk(textureChunkX, textureChunkZ, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FloatBuffer chunkBuffer() {
|
public static ByteBuffer chunkBuffer() {
|
||||||
|
|
||||||
CHUNK_BUFFER.clear();
|
CHUNK_BUFFER.clear();
|
||||||
|
|
||||||
return CHUNK_BUFFER;
|
return CHUNK_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getTexture() {
|
public static int getTexture() {
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
uniform sampler2D DiffuseSampler;
|
uniform sampler2D DiffuseSampler;
|
||||||
uniform sampler2D DepthSampler;
|
uniform sampler2D DepthSampler;
|
||||||
uniform sampler3D FogVolume;
|
uniform usampler3D FogVolume;
|
||||||
|
|
||||||
uniform mat4 InverseProjection;
|
uniform mat4 InverseProjection;
|
||||||
uniform mat4 InverseView;
|
uniform mat4 InverseView;
|
||||||
@@ -23,7 +23,7 @@ out vec4 FragColor;
|
|||||||
const float FOG_SIZE_X = 256.0;
|
const float FOG_SIZE_X = 256.0;
|
||||||
const float FOG_SIZE_Z = FOG_SIZE_X;
|
const float FOG_SIZE_Z = FOG_SIZE_X;
|
||||||
|
|
||||||
const int MAX_STEPS = 256; // Уменьшили количество шагов благодаря адаптивности
|
const int MAX_STEPS = 256;
|
||||||
|
|
||||||
// Высота мира
|
// Высота мира
|
||||||
const float WORLD_BOTTOM = -64.0;
|
const float WORLD_BOTTOM = -64.0;
|
||||||
@@ -39,7 +39,7 @@ const float MAX_DISTANCE = (FOG_SIZE_X / 2.0) - 18.0;
|
|||||||
const float GAMMA = 2.0;
|
const float GAMMA = 2.0;
|
||||||
|
|
||||||
// Включение jittering для устранения banding артефактов
|
// Включение jittering для устранения banding артефактов
|
||||||
const bool USE_JITTERING = true;
|
const bool USE_JITTERING = false;
|
||||||
|
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
|
|
||||||
@@ -103,7 +103,9 @@ float density(vec3 worldPos)
|
|||||||
// Псевдослучайное значение для jittering (детерминированное по UV)
|
// Псевдослучайное значение для jittering (детерминированное по UV)
|
||||||
float random(vec2 st)
|
float random(vec2 st)
|
||||||
{
|
{
|
||||||
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
|
vec3 p3 = fract(vec3(st.xyx) * 0.1031);
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Функция нелинейного маппинга параметра t [0,1] в расстояние
|
// Функция нелинейного маппинга параметра t [0,1] в расстояние
|
||||||
|
|||||||
Reference in New Issue
Block a user