Сделаны бескомпромиссные оптимизации
This commit is contained in:
@@ -5,7 +5,6 @@ import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gl.Framebuffer;
|
||||
import net.minecraft.client.render.Camera;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.LightType;
|
||||
import org.joml.Matrix4f;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.*;
|
||||
|
||||
@@ -60,6 +60,16 @@ public final class FogBlockRegistry {
|
||||
return new FogBlockProperties(solid, 1, 45).pack();
|
||||
}
|
||||
|
||||
if (block == Blocks.SOUL_CAMPFIRE || block == Blocks.SOUL_FIRE) {
|
||||
return new FogBlockProperties(solid, 1, 63).pack();
|
||||
}
|
||||
if (block == Blocks.SOUL_LANTERN) {
|
||||
return new FogBlockProperties(solid, 1, 31).pack();
|
||||
}
|
||||
if (block == Blocks.SOUL_TORCH || block == Blocks.SOUL_WALL_TORCH) {
|
||||
return new FogBlockProperties(solid, 1, 15).pack();
|
||||
}
|
||||
|
||||
// Поглотители тумана (sign = -1)
|
||||
if (block == Blocks.LAVA) {
|
||||
return new FogBlockProperties(solid, -1, 50).pack();
|
||||
@@ -67,18 +77,17 @@ public final class FogBlockRegistry {
|
||||
if (block == Blocks.MAGMA_BLOCK) {
|
||||
return new FogBlockProperties(solid, -1, 40).pack();
|
||||
}
|
||||
if (block == Blocks.FIRE || block == Blocks.SOUL_FIRE) {
|
||||
if (block == Blocks.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.CAMPFIRE) {
|
||||
return new FogBlockProperties(solid, -1, 63).pack();
|
||||
}
|
||||
if (block == Blocks.TORCH || block == Blocks.WALL_TORCH ||
|
||||
block == Blocks.SOUL_TORCH || block == Blocks.SOUL_WALL_TORCH) {
|
||||
if (block == Blocks.TORCH || block == Blocks.WALL_TORCH) {
|
||||
return new FogBlockProperties(solid, -1, 15).pack();
|
||||
}
|
||||
if (block == Blocks.LANTERN || block == Blocks.SOUL_LANTERN) {
|
||||
return new FogBlockProperties(solid, -1, 10).pack();
|
||||
if (block == Blocks.LANTERN) {
|
||||
return new FogBlockProperties(solid, -1, 25).pack();
|
||||
}
|
||||
|
||||
// Нейтральные блоки (sign = 0)
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package su.divan2000.veila.client.render.fog;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkSectionPos;
|
||||
import net.minecraft.world.LightType;
|
||||
import net.minecraft.world.chunk.ChunkNibbleArray;
|
||||
import net.minecraft.world.chunk.light.ChunkLightProvider;
|
||||
import net.minecraft.world.chunk.light.LightingProvider;
|
||||
@@ -13,6 +11,16 @@ public final class FogLightProvider {
|
||||
// Размер массива для одной секции: 16×16×16×2 = 8192 (×2 для двух каналов)
|
||||
public static final int SECTION_DATA_SIZE = 16 * 16 * 16 * 2;
|
||||
|
||||
// Pre-allocated buffer для чтения одной секции из LightingProvider
|
||||
// используется в fillSectionIntoArray для избежания аллокаций
|
||||
private static final byte[] SECTION_BUFFER = new byte[SECTION_DATA_SIZE];
|
||||
|
||||
// Флаг для отслеживания используется ли буфер сейчас (защита от race condition)
|
||||
// Так как fillSectionIntoArray может вызываться из разных потоков,
|
||||
// нужен второй буфер для параллельной работы
|
||||
private static final byte[] SECTION_BUFFER_ALT = new byte[SECTION_DATA_SIZE];
|
||||
private static volatile boolean bufferInUse = false;
|
||||
|
||||
private FogLightProvider() {
|
||||
}
|
||||
|
||||
@@ -38,7 +46,15 @@ public final class FogLightProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] result = new byte[SECTION_DATA_SIZE];
|
||||
// Используем один из двух pre-allocated буферов (double buffering)
|
||||
byte[] result;
|
||||
if (!bufferInUse) {
|
||||
bufferInUse = true;
|
||||
result = SECTION_BUFFER;
|
||||
} else {
|
||||
result = SECTION_BUFFER_ALT;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (int localZ = 0; localZ < 16; localZ++) {
|
||||
@@ -47,13 +63,17 @@ public final class FogLightProvider {
|
||||
int blockLight = (blockArray != null) ? blockArray.get(localX, localY, localZ) : 0;
|
||||
int skyLight = (skyArray != null) ? skyArray.get(localX, localY, localZ) : 0;
|
||||
|
||||
// Упаковка в два байта: R=blockLight, G=skyLight
|
||||
FogLightVolume.packLight(blockLight, skyLight, result, index);
|
||||
index += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Освобождаем буфер
|
||||
if (result == SECTION_BUFFER) {
|
||||
bufferInUse = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -286,34 +286,51 @@ public final class FogLightStreamer {
|
||||
}
|
||||
}
|
||||
|
||||
public static void prepareInitialLoads() {
|
||||
/**
|
||||
* Подготавливает все секции для загрузки (client thread).
|
||||
* Обрабатывает и initialLoadMask, и pendingSectionsMask.
|
||||
* Вызывается из FogSystem.tick().
|
||||
*/
|
||||
public static void prepareAllSections() {
|
||||
int processed = 0;
|
||||
int index = 0;
|
||||
|
||||
// Обрабатываем initial load
|
||||
int index = 0;
|
||||
while (processed < MAX_INITIAL_SECTIONS_PER_TICK) {
|
||||
index = nextSetBit(initialLoadMask, index);
|
||||
if (index < 0) break;
|
||||
|
||||
// Конвертируем индекс обратно в координаты секции
|
||||
int sectionX = currentOriginChunkX + (index % FogLightVolume.CHUNKS_X);
|
||||
int sectionZ = currentOriginChunkZ + ((index / FogLightVolume.CHUNKS_X) % FogLightVolume.CHUNKS_Z);
|
||||
int sectionY = (index / (FogLightVolume.CHUNKS_X * FogLightVolume.CHUNKS_Z)) + (FogWorldVolume.MIN_Y >> 4);
|
||||
|
||||
byte[] sectionData = FogLightProvider.fillSectionIntoArray(sectionX, sectionY, sectionZ);
|
||||
if (sectionData != null) {
|
||||
if (prepareSectionByIndex(index)) {
|
||||
clearBit(initialLoadMask, index);
|
||||
setBit(readySectionsMask, index);
|
||||
processed++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
// Обрабатываем инкрементальные обновления
|
||||
index = 0;
|
||||
while (processed < MAX_INITIAL_SECTIONS_PER_TICK + MAX_SECTIONS_PER_FRAME) {
|
||||
index = nextSetBit(pendingSectionsMask, index);
|
||||
if (index < 0) break;
|
||||
|
||||
if (prepareSectionByIndex(index)) {
|
||||
clearBit(pendingSectionsMask, index);
|
||||
processed++;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Загружает готовые секции в текстуру (render thread).
|
||||
* Только OpenGL вызовы, без чтения из LightingProvider.
|
||||
* Вызывается из FogSystem.beginRender().
|
||||
*/
|
||||
public static void uploadReadySections() {
|
||||
int processed = 0;
|
||||
int index = 0;
|
||||
|
||||
while (processed < MAX_SECTIONS_PER_FRAME) {
|
||||
while (processed < MAX_SECTIONS_PER_FRAME + MAX_INITIAL_SECTIONS_PER_TICK) {
|
||||
index = nextSetBit(readySectionsMask, index);
|
||||
if (index < 0) break;
|
||||
|
||||
@@ -325,22 +342,29 @@ public final class FogLightStreamer {
|
||||
}
|
||||
}
|
||||
|
||||
public static void processSectionUpdates() {
|
||||
int processed = 0;
|
||||
int index = 0;
|
||||
/**
|
||||
* Читает данные секции из LightingProvider и помечает как готовую к загрузке.
|
||||
* Вызывается из prepareAllSections() в client thread.
|
||||
*/
|
||||
private static boolean prepareSectionByIndex(int index) {
|
||||
int sectionX = currentOriginChunkX + (index % FogLightVolume.CHUNKS_X);
|
||||
int sectionZ = currentOriginChunkZ + ((index / FogLightVolume.CHUNKS_X) % FogLightVolume.CHUNKS_Z);
|
||||
int sectionY = (index / (FogLightVolume.CHUNKS_X * FogLightVolume.CHUNKS_Z)) + (FogWorldVolume.MIN_Y >> 4);
|
||||
|
||||
while (processed < MAX_SECTIONS_PER_FRAME) {
|
||||
index = nextSetBit(pendingSectionsMask, index);
|
||||
if (index < 0) break;
|
||||
|
||||
if (uploadSectionByIndex(index)) {
|
||||
clearBit(pendingSectionsMask, index);
|
||||
processed++;
|
||||
}
|
||||
index++;
|
||||
byte[] sectionData = FogLightProvider.fillSectionIntoArray(sectionX, sectionY, sectionZ);
|
||||
if (sectionData == null) {
|
||||
return false; // Секция не готова, пробуем позже
|
||||
}
|
||||
|
||||
// Помечаем как готовую к загрузке в render thread
|
||||
setBit(readySectionsMask, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Загружает готовую секцию в текстуру через OpenGL.
|
||||
* Вызывается из uploadReadySections() в render thread.
|
||||
*/
|
||||
private static boolean uploadSectionByIndex(int index) {
|
||||
int physicalX = index % FogLightVolume.CHUNKS_X;
|
||||
int physicalZ = (index / FogLightVolume.CHUNKS_X) % FogLightVolume.CHUNKS_Z;
|
||||
@@ -350,6 +374,7 @@ public final class FogLightStreamer {
|
||||
int sectionZ = currentOriginChunkZ + Math.floorMod(physicalZ - currentRingChunkOffsetZ, FogLightVolume.CHUNKS_Z);
|
||||
int sectionY = localSectionY + (FogWorldVolume.MIN_Y >> 4);
|
||||
|
||||
// Читаем данные повторно (они должны быть доступны быстро, так как уже в кэше)
|
||||
byte[] sectionData = FogLightProvider.fillSectionIntoArray(sectionX, sectionY, sectionZ);
|
||||
if (sectionData == null) {
|
||||
return false;
|
||||
|
||||
@@ -44,6 +44,13 @@ public final class FogLightVolume {
|
||||
private static int clearPBO = -1;
|
||||
private static final int MAX_CLEAR_SIZE = SIZE_X * SIZE_Y * SIZE_Z * 2; // ×2 для двух каналов
|
||||
|
||||
// Pre-allocated buffer для одной секции (4096 вокселей × 2 байта = 8192 байта)
|
||||
// Используется для загрузки секций через uploadSection
|
||||
private static final ByteBuffer SECTION_UPLOAD_BUFFER =
|
||||
BufferUtils.createByteBuffer(FogLightStreamer.SECTION_SIZE
|
||||
* FogLightStreamer.SECTION_SIZE
|
||||
* FogLightStreamer.SECTION_SIZE * 2);
|
||||
|
||||
private FogLightVolume() {
|
||||
}
|
||||
|
||||
@@ -160,9 +167,10 @@ public final class FogLightVolume {
|
||||
int textureSectionZ,
|
||||
byte[] data
|
||||
) {
|
||||
ByteBuffer sectionBuffer = BufferUtils.createByteBuffer(data.length);
|
||||
sectionBuffer.put(data);
|
||||
sectionBuffer.flip();
|
||||
// Переиспользуем статический буфер вместо создания нового
|
||||
SECTION_UPLOAD_BUFFER.clear();
|
||||
SECTION_UPLOAD_BUFFER.put(data);
|
||||
SECTION_UPLOAD_BUFFER.flip();
|
||||
|
||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, texture);
|
||||
|
||||
@@ -182,7 +190,7 @@ public final class FogLightVolume {
|
||||
16,
|
||||
GL30.GL_RG,
|
||||
GL11.GL_UNSIGNED_BYTE,
|
||||
sectionBuffer
|
||||
SECTION_UPLOAD_BUFFER
|
||||
);
|
||||
|
||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, 0);
|
||||
|
||||
@@ -31,7 +31,6 @@ public final class FogSystem {
|
||||
|
||||
// Освещение: загружаем готовые секции + инкрементальные обновления (render thread)
|
||||
FogLightStreamer.uploadReadySections();
|
||||
FogLightStreamer.processSectionUpdates();
|
||||
|
||||
FogSimulationManager.update();
|
||||
}
|
||||
@@ -41,7 +40,7 @@ public final class FogSystem {
|
||||
FogChunkStreamer.processPending();
|
||||
|
||||
// Освещение: читаем данные секций (client thread, без OpenGL)
|
||||
FogLightStreamer.prepareInitialLoads();
|
||||
FogLightStreamer.prepareAllSections();
|
||||
}
|
||||
|
||||
private static void initialize() {
|
||||
|
||||
@@ -210,7 +210,8 @@ void main()
|
||||
|
||||
// Вклад ослабляется текущим transmittance
|
||||
skyScattered += lightValues.x * baseScattering * transmittance;
|
||||
blockScattered += lightValues.y * baseScattering * transmittance;
|
||||
//Свет от блоков не должен делать значимо ярче те воксели, которые и так подсвечены солнцем. Солнечный свет очень яркий, с ним сложно сравниться
|
||||
blockScattered += lightValues.y * baseScattering * transmittance*((lightValues.y-lightValues.x)*0.9+0.1);
|
||||
ambientScattered += AMBIENT_INTENSITY * baseScattering * transmittance;
|
||||
|
||||
// Обновляем transmittance: Beer-Lambert law
|
||||
|
||||
Reference in New Issue
Block a user