Симуляция работает
This commit is contained in:
@@ -13,6 +13,7 @@ import su.divan2000.veila.client.gl.FullscreenQuad;
|
|||||||
import su.divan2000.veila.client.gl.GLProgram;
|
import su.divan2000.veila.client.gl.GLProgram;
|
||||||
import su.divan2000.veila.client.gl.GLShader;
|
import su.divan2000.veila.client.gl.GLShader;
|
||||||
import su.divan2000.veila.client.gl.ResourceUtil;
|
import su.divan2000.veila.client.gl.ResourceUtil;
|
||||||
|
import su.divan2000.veila.client.render.fog.FogSimulationManager;
|
||||||
import su.divan2000.veila.client.render.fog.FogSystem;
|
import su.divan2000.veila.client.render.fog.FogSystem;
|
||||||
import su.divan2000.veila.client.render.fog.FogWorldVolume;
|
import su.divan2000.veila.client.render.fog.FogWorldVolume;
|
||||||
|
|
||||||
@@ -154,7 +155,7 @@ public class PostProcessingManager {
|
|||||||
|
|
||||||
GL11.glBindTexture(
|
GL11.glBindTexture(
|
||||||
GL12.GL_TEXTURE_3D,
|
GL12.GL_TEXTURE_3D,
|
||||||
FogWorldVolume.getTexture()
|
FogSimulationManager.getCurrentDensityTexture()
|
||||||
);
|
);
|
||||||
|
|
||||||
GL20.glUniform1i(
|
GL20.glUniform1i(
|
||||||
|
|||||||
@@ -242,6 +242,8 @@ public final class FogChunkStreamer {
|
|||||||
int physicalIndex = physicalZ * FogWorldVolume.CHUNKS_X + physicalX;
|
int physicalIndex = physicalZ * FogWorldVolume.CHUNKS_X + physicalX;
|
||||||
|
|
||||||
FogWorldVolume.uploadZeros(physicalX, physicalZ);
|
FogWorldVolume.uploadZeros(physicalX, physicalZ);
|
||||||
|
FogDensityTextures.clearColumn(physicalX, physicalZ);
|
||||||
|
|
||||||
statuses[physicalIndex] = ChunkStatus.PENDING;
|
statuses[physicalIndex] = ChunkStatus.PENDING;
|
||||||
readyToUpload[physicalIndex] = false;
|
readyToUpload[physicalIndex] = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package su.divan2000.veila.client.render.fog;
|
||||||
|
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL12;
|
||||||
|
import org.lwjgl.opengl.GL30;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
|
public final class FogDensityTextures {
|
||||||
|
|
||||||
|
private static int textureA = -1;
|
||||||
|
private static int textureB = -1;
|
||||||
|
private static int readIndex = 0;
|
||||||
|
|
||||||
|
// Float буфер с нулями для одного столбца 16×384×16
|
||||||
|
private static final FloatBuffer ZEROS_BUFFER =
|
||||||
|
BufferUtils.createFloatBuffer(
|
||||||
|
FogWorldVolume.CHUNK_SIZE *
|
||||||
|
FogWorldVolume.SIZE_Y *
|
||||||
|
FogWorldVolume.CHUNK_SIZE
|
||||||
|
);
|
||||||
|
|
||||||
|
static {
|
||||||
|
int size = FogWorldVolume.CHUNK_SIZE * FogWorldVolume.SIZE_Y * FogWorldVolume.CHUNK_SIZE;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
ZEROS_BUFFER.put(0.0f);
|
||||||
|
}
|
||||||
|
ZEROS_BUFFER.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FogDensityTextures() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
if (textureA != -1) return;
|
||||||
|
|
||||||
|
textureA = createDensityTexture();
|
||||||
|
textureB = createDensityTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int createDensityTexture() {
|
||||||
|
int texture = GL11.glGenTextures();
|
||||||
|
|
||||||
|
GL11.glBindTexture(GL12.GL_TEXTURE_3D, texture);
|
||||||
|
|
||||||
|
GL30.glTexImage3D(
|
||||||
|
GL12.GL_TEXTURE_3D,
|
||||||
|
0,
|
||||||
|
GL30.GL_R16F,
|
||||||
|
FogWorldVolume.SIZE_X,
|
||||||
|
FogWorldVolume.SIZE_Y,
|
||||||
|
FogWorldVolume.SIZE_Z,
|
||||||
|
0,
|
||||||
|
GL11.GL_RED,
|
||||||
|
GL11.GL_FLOAT,
|
||||||
|
(ByteBuffer) null
|
||||||
|
);
|
||||||
|
|
||||||
|
GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
|
||||||
|
GL11.glTexParameteri(GL12.GL_TEXTURE_3D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
|
||||||
|
|
||||||
|
GL11.glTexParameteri(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);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void swap() {
|
||||||
|
readIndex = 1 - readIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getReadTexture() {
|
||||||
|
return readIndex == 0 ? textureA : textureB;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getWriteTexture() {
|
||||||
|
return readIndex == 0 ? textureB : textureA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обнуляет столбец (один чанк) в ОБОИХ density текстурах.
|
||||||
|
* Вызывается при смене окна, чтобы не было фантомного тумана.
|
||||||
|
*/
|
||||||
|
public static void clearColumn(int textureChunkX, int textureChunkZ) {
|
||||||
|
clearColumnInTexture(textureA, textureChunkX, textureChunkZ);
|
||||||
|
clearColumnInTexture(textureB, textureChunkX, textureChunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void clearColumnInTexture(int texture, int textureChunkX, int textureChunkZ) {
|
||||||
|
GL11.glBindTexture(GL12.GL_TEXTURE_3D, texture);
|
||||||
|
|
||||||
|
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
GL11.glPixelStorei(GL11.GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_PIXELS, 0);
|
||||||
|
GL11.glPixelStorei(GL11.GL_UNPACK_SKIP_ROWS, 0);
|
||||||
|
|
||||||
|
// Сбрасываем position буфера
|
||||||
|
ZEROS_BUFFER.rewind();
|
||||||
|
|
||||||
|
GL30.glTexSubImage3D(
|
||||||
|
GL12.GL_TEXTURE_3D,
|
||||||
|
0,
|
||||||
|
textureChunkX * FogWorldVolume.CHUNK_SIZE,
|
||||||
|
0,
|
||||||
|
textureChunkZ * FogWorldVolume.CHUNK_SIZE,
|
||||||
|
FogWorldVolume.CHUNK_SIZE,
|
||||||
|
FogWorldVolume.SIZE_Y,
|
||||||
|
FogWorldVolume.CHUNK_SIZE,
|
||||||
|
GL11.GL_RED,
|
||||||
|
GL11.GL_FLOAT,
|
||||||
|
ZEROS_BUFFER
|
||||||
|
);
|
||||||
|
|
||||||
|
GL11.glBindTexture(GL12.GL_TEXTURE_3D, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package su.divan2000.veila.client.render.fog;
|
||||||
|
|
||||||
|
public final class FogSimulationManager {
|
||||||
|
|
||||||
|
private static boolean initialized = false;
|
||||||
|
private static long lastSimulationTime = 0;
|
||||||
|
|
||||||
|
// Симулируем каждые 100 мс (10 раз в секунду)
|
||||||
|
private static final long SIMULATION_INTERVAL_NS = 100_000_000L;
|
||||||
|
|
||||||
|
private static float globalEmissionMultiplier = 1.0f;
|
||||||
|
private static float globalAbsorptionMultiplier = 1.0f;
|
||||||
|
private static float globalDecay = 0.01f;
|
||||||
|
private static float diffusionRate = 0.1f;
|
||||||
|
private static float upDiffusion = 0.9f;
|
||||||
|
private static float downDiffusion = 1.1f;
|
||||||
|
private static float horizontalDiffusion = 1.0f;
|
||||||
|
|
||||||
|
private FogSimulationManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
if (initialized) return;
|
||||||
|
|
||||||
|
FogDensityTextures.init();
|
||||||
|
FogSimulationShader.init();
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
lastSimulationTime = System.nanoTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Вызывается из RENDER THREAD в beginRender()
|
||||||
|
*/
|
||||||
|
public static void update() {
|
||||||
|
if (!initialized) return;
|
||||||
|
|
||||||
|
long currentTime = System.nanoTime();
|
||||||
|
|
||||||
|
if (currentTime - lastSimulationTime >= SIMULATION_INTERVAL_NS) {
|
||||||
|
lastSimulationTime = currentTime;
|
||||||
|
simulate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void simulate() {
|
||||||
|
FogSimulationShader.simulate(
|
||||||
|
globalEmissionMultiplier,
|
||||||
|
globalAbsorptionMultiplier,
|
||||||
|
globalDecay,
|
||||||
|
diffusionRate,
|
||||||
|
upDiffusion,
|
||||||
|
downDiffusion,
|
||||||
|
horizontalDiffusion
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getCurrentDensityTexture() {
|
||||||
|
return FogDensityTextures.getReadTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setGlobalEmissionMultiplier(float value) {
|
||||||
|
globalEmissionMultiplier = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setGlobalAbsorptionMultiplier(float value) {
|
||||||
|
globalAbsorptionMultiplier = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setGlobalDecay(float value) {
|
||||||
|
globalDecay = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
package su.divan2000.veila.client.render.fog;
|
||||||
|
|
||||||
|
import su.divan2000.veila.client.gl.FullscreenQuad;
|
||||||
|
import su.divan2000.veila.client.gl.GLProgram;
|
||||||
|
import su.divan2000.veila.client.gl.GLShader;
|
||||||
|
import su.divan2000.veila.client.gl.ResourceUtil;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL12;
|
||||||
|
import org.lwjgl.opengl.GL13;
|
||||||
|
import org.lwjgl.opengl.GL20;
|
||||||
|
import org.lwjgl.opengl.GL30;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_TEXTURE_BINDING_2D;
|
||||||
|
import static org.lwjgl.opengl.GL12.GL_TEXTURE_BINDING_3D;
|
||||||
|
|
||||||
|
public final class FogSimulationShader {
|
||||||
|
|
||||||
|
private static GLProgram program;
|
||||||
|
private static int fbo = -1;
|
||||||
|
|
||||||
|
private static int worldInfoSamplerLocation;
|
||||||
|
private static int fogReadSamplerLocation;
|
||||||
|
private static int globalEmissionMultiplierLocation;
|
||||||
|
private static int globalAbsorptionMultiplierLocation;
|
||||||
|
private static int globalDecayLocation;
|
||||||
|
private static int diffusionRateLocation;
|
||||||
|
private static int upDiffusionLocation;
|
||||||
|
private static int downDiffusionLocation;
|
||||||
|
private static int horizontalDiffusionLocation;
|
||||||
|
private static int voxelSizeLocation;
|
||||||
|
private static int currentZLocation;
|
||||||
|
|
||||||
|
private FogSimulationShader() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
if (program != null) return;
|
||||||
|
|
||||||
|
FullscreenQuad.init();
|
||||||
|
|
||||||
|
GLShader vertex = new GLShader(
|
||||||
|
GL20.GL_VERTEX_SHADER,
|
||||||
|
ResourceUtil.load("shaders/fullscreen.vert")
|
||||||
|
);
|
||||||
|
|
||||||
|
GLShader fragment = new GLShader(
|
||||||
|
GL20.GL_FRAGMENT_SHADER,
|
||||||
|
ResourceUtil.load("shaders/sim.frag")
|
||||||
|
);
|
||||||
|
|
||||||
|
program = new GLProgram(vertex, fragment);
|
||||||
|
|
||||||
|
worldInfoSamplerLocation = program.uniform("WorldInfoSampler");
|
||||||
|
fogReadSamplerLocation = program.uniform("FogReadSampler");
|
||||||
|
globalEmissionMultiplierLocation = program.uniform("GlobalEmissionMultiplier");
|
||||||
|
globalAbsorptionMultiplierLocation = program.uniform("GlobalAbsorptionMultiplier");
|
||||||
|
globalDecayLocation = program.uniform("GlobalDecay");
|
||||||
|
diffusionRateLocation = program.uniform("DiffusionRate");
|
||||||
|
upDiffusionLocation = program.uniform("UpDiffusion");
|
||||||
|
downDiffusionLocation = program.uniform("DownDiffusion");
|
||||||
|
horizontalDiffusionLocation = program.uniform("HorizontalDiffusion");
|
||||||
|
voxelSizeLocation = program.uniform("VoxelSize");
|
||||||
|
currentZLocation = program.uniform("CurrentZ");
|
||||||
|
|
||||||
|
fbo = GL30.glGenFramebuffers();
|
||||||
|
|
||||||
|
vertex.delete();
|
||||||
|
fragment.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void simulate(
|
||||||
|
float globalEmissionMultiplier,
|
||||||
|
float globalAbsorptionMultiplier,
|
||||||
|
float globalDecay,
|
||||||
|
float diffusionRate,
|
||||||
|
float upDiffusion,
|
||||||
|
float downDiffusion,
|
||||||
|
float horizontalDiffusion
|
||||||
|
) {
|
||||||
|
if (program == null) return;
|
||||||
|
|
||||||
|
int fogRead = FogDensityTextures.getReadTexture();
|
||||||
|
int fogWrite = FogDensityTextures.getWriteTexture();
|
||||||
|
int worldInfo = FogWorldVolume.getTexture();
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// ПОЛНОЕ СОХРАНЕНИЕ СОСТОЯНИЯ OPENGL
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
// FBO и viewport
|
||||||
|
int previousFBO = GL11.glGetInteger(GL30.GL_FRAMEBUFFER_BINDING);
|
||||||
|
int[] previousViewport = new int[4];
|
||||||
|
GL11.glGetIntegerv(GL11.GL_VIEWPORT, previousViewport);
|
||||||
|
|
||||||
|
// Program
|
||||||
|
int previousProgram = GL11.glGetInteger(GL20.GL_CURRENT_PROGRAM);
|
||||||
|
|
||||||
|
// VAO
|
||||||
|
int previousVAO = GL11.glGetInteger(GL30.GL_VERTEX_ARRAY_BINDING);
|
||||||
|
|
||||||
|
// Активный текстурный юнит
|
||||||
|
int previousActiveTexture = GL11.glGetInteger(GL13.GL_ACTIVE_TEXTURE);
|
||||||
|
|
||||||
|
// Привязки текстур для юнитов 0 и 1 (2D и 3D)
|
||||||
|
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||||
|
int previousTex0_2D = GL11.glGetInteger(GL_TEXTURE_BINDING_2D);
|
||||||
|
int previousTex0_3D = GL11.glGetInteger(GL_TEXTURE_BINDING_3D);
|
||||||
|
|
||||||
|
GL13.glActiveTexture(GL13.GL_TEXTURE1);
|
||||||
|
int previousTex1_2D = GL11.glGetInteger(GL_TEXTURE_BINDING_2D);
|
||||||
|
int previousTex1_3D = GL11.glGetInteger(GL_TEXTURE_BINDING_3D);
|
||||||
|
|
||||||
|
// Blend state (на всякий случай)
|
||||||
|
boolean previousBlend = GL11.glIsEnabled(GL11.GL_BLEND);
|
||||||
|
boolean previousDepthTest = GL11.glIsEnabled(GL11.GL_DEPTH_TEST);
|
||||||
|
boolean previousCullFace = GL11.glIsEnabled(GL11.GL_CULL_FACE);
|
||||||
|
|
||||||
|
// Color mask
|
||||||
|
ByteBuffer previousColorMask = org.lwjgl.BufferUtils.createByteBuffer(4);
|
||||||
|
GL11.glGetBooleanv(GL11.GL_COLOR_WRITEMASK, previousColorMask);
|
||||||
|
|
||||||
|
// Depth mask
|
||||||
|
boolean previousDepthMask = GL11.glGetBoolean(GL11.GL_DEPTH_WRITEMASK);
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// НАСТРОЙКА СОСТОЯНИЯ ДЛЯ СИМУЛЯЦИИ
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
// Отключаем всё лишнее
|
||||||
|
GL11.glDisable(GL11.GL_BLEND);
|
||||||
|
GL11.glDisable(GL11.GL_DEPTH_TEST);
|
||||||
|
GL11.glDisable(GL11.GL_CULL_FACE);
|
||||||
|
GL11.glColorMask(true, true, true, true);
|
||||||
|
GL11.glDepthMask(false);
|
||||||
|
|
||||||
|
// Привязываем framebuffer
|
||||||
|
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, fbo);
|
||||||
|
|
||||||
|
// Настраиваем viewport
|
||||||
|
GL11.glViewport(0, 0, FogWorldVolume.SIZE_X, FogWorldVolume.SIZE_Y);
|
||||||
|
|
||||||
|
// Привязываем программу
|
||||||
|
program.bind();
|
||||||
|
|
||||||
|
// Привязываем текстуры
|
||||||
|
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||||
|
GL11.glBindTexture(GL12.GL_TEXTURE_3D, worldInfo);
|
||||||
|
GL20.glUniform1i(worldInfoSamplerLocation, 0);
|
||||||
|
|
||||||
|
GL13.glActiveTexture(GL13.GL_TEXTURE1);
|
||||||
|
GL11.glBindTexture(GL12.GL_TEXTURE_3D, fogRead);
|
||||||
|
GL20.glUniform1i(fogReadSamplerLocation, 1);
|
||||||
|
|
||||||
|
// Устанавливаем параметры
|
||||||
|
GL20.glUniform1f(globalEmissionMultiplierLocation, globalEmissionMultiplier);
|
||||||
|
GL20.glUniform1f(globalAbsorptionMultiplierLocation, globalAbsorptionMultiplier);
|
||||||
|
GL20.glUniform1f(globalDecayLocation, globalDecay);
|
||||||
|
GL20.glUniform1f(diffusionRateLocation, diffusionRate);
|
||||||
|
GL20.glUniform1f(upDiffusionLocation, upDiffusion);
|
||||||
|
GL20.glUniform1f(downDiffusionLocation, downDiffusion);
|
||||||
|
GL20.glUniform1f(horizontalDiffusionLocation, horizontalDiffusion);
|
||||||
|
GL20.glUniform3f(voxelSizeLocation,
|
||||||
|
1.0f / FogWorldVolume.SIZE_X,
|
||||||
|
1.0f / FogWorldVolume.SIZE_Y,
|
||||||
|
1.0f / FogWorldVolume.SIZE_Z
|
||||||
|
);
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// РЕНДЕРИНГ
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
for (int z = 0; z < FogWorldVolume.SIZE_Z; z++) {
|
||||||
|
GL30.glFramebufferTexture3D(
|
||||||
|
GL30.GL_FRAMEBUFFER,
|
||||||
|
GL30.GL_COLOR_ATTACHMENT0,
|
||||||
|
GL12.GL_TEXTURE_3D,
|
||||||
|
fogWrite,
|
||||||
|
0,
|
||||||
|
z
|
||||||
|
);
|
||||||
|
|
||||||
|
GL20.glUniform1f(currentZLocation, (float) z / FogWorldVolume.SIZE_Z);
|
||||||
|
|
||||||
|
FullscreenQuad.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// ПОЛНОЕ ВОССТАНОВЛЕНИЕ СОСТОЯНИЯ
|
||||||
|
// ========================================
|
||||||
|
|
||||||
|
// Отвязываем программу
|
||||||
|
GL20.glUseProgram(previousProgram);
|
||||||
|
|
||||||
|
// Отвязываем FBO
|
||||||
|
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, previousFBO);
|
||||||
|
|
||||||
|
// Восстанавливаем viewport
|
||||||
|
GL11.glViewport(previousViewport[0], previousViewport[1],
|
||||||
|
previousViewport[2], previousViewport[3]);
|
||||||
|
|
||||||
|
// Восстанавливаем VAO
|
||||||
|
GL30.glBindVertexArray(previousVAO);
|
||||||
|
|
||||||
|
// Восстанавливаем текстуры
|
||||||
|
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||||
|
GL11.glBindTexture(GL11.GL_TEXTURE_2D, previousTex0_2D);
|
||||||
|
GL11.glBindTexture(GL12.GL_TEXTURE_3D, previousTex0_3D);
|
||||||
|
|
||||||
|
GL13.glActiveTexture(GL13.GL_TEXTURE1);
|
||||||
|
GL11.glBindTexture(GL11.GL_TEXTURE_2D, previousTex1_2D);
|
||||||
|
GL11.glBindTexture(GL12.GL_TEXTURE_3D, previousTex1_3D);
|
||||||
|
|
||||||
|
// Восстанавливаем активный текстурный юнит
|
||||||
|
GL13.glActiveTexture(previousActiveTexture);
|
||||||
|
|
||||||
|
// Восстанавливаем blend/depth/cull
|
||||||
|
if (previousBlend) GL11.glEnable(GL11.GL_BLEND);
|
||||||
|
else GL11.glDisable(GL11.GL_BLEND);
|
||||||
|
|
||||||
|
if (previousDepthTest) GL11.glEnable(GL11.GL_DEPTH_TEST);
|
||||||
|
else GL11.glDisable(GL11.GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
if (previousCullFace) GL11.glEnable(GL11.GL_CULL_FACE);
|
||||||
|
else GL11.glDisable(GL11.GL_CULL_FACE);
|
||||||
|
|
||||||
|
// Восстанавливаем color mask
|
||||||
|
GL11.glColorMask(
|
||||||
|
previousColorMask.get(0) != 0,
|
||||||
|
previousColorMask.get(1) != 0,
|
||||||
|
previousColorMask.get(2) != 0,
|
||||||
|
previousColorMask.get(3) != 0
|
||||||
|
);
|
||||||
|
|
||||||
|
// Восстанавливаем depth mask
|
||||||
|
GL11.glDepthMask(previousDepthMask);
|
||||||
|
|
||||||
|
// Меняем текстуры местами
|
||||||
|
FogDensityTextures.swap();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,8 @@ public final class FogSystem {
|
|||||||
|
|
||||||
// Всегда обрабатываем изменения блоков
|
// Всегда обрабатываем изменения блоков
|
||||||
FogChunkStreamer.processBlockChanges();
|
FogChunkStreamer.processBlockChanges();
|
||||||
|
|
||||||
|
FogSimulationManager.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void tick() {
|
public static void tick() {
|
||||||
@@ -36,6 +38,7 @@ public final class FogSystem {
|
|||||||
|
|
||||||
private static void initialize() {
|
private static void initialize() {
|
||||||
FogWorldVolume.init();
|
FogWorldVolume.init();
|
||||||
|
FogSimulationManager.init();
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ public class GameRendererMixin {
|
|||||||
boolean tick,
|
boolean tick,
|
||||||
CallbackInfo ci
|
CallbackInfo ci
|
||||||
) {
|
) {
|
||||||
|
net.minecraft.client.MinecraftClient client = net.minecraft.client.MinecraftClient.getInstance();
|
||||||
|
if (client.world != null && client.player != null) {
|
||||||
FogSystem.beginRender();
|
FogSystem.beginRender();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
uniform sampler2D DiffuseSampler;
|
uniform sampler2D DiffuseSampler;
|
||||||
uniform sampler2D DepthSampler;
|
uniform sampler2D DepthSampler;
|
||||||
uniform usampler3D FogVolume;
|
uniform sampler3D FogVolume;
|
||||||
|
|
||||||
uniform mat4 InverseProjection;
|
uniform mat4 InverseProjection;
|
||||||
uniform mat4 InverseView;
|
uniform mat4 InverseView;
|
||||||
|
|||||||
@@ -0,0 +1,191 @@
|
|||||||
|
#version 150
|
||||||
|
|
||||||
|
uniform usampler3D WorldInfoSampler;
|
||||||
|
uniform sampler3D FogReadSampler;
|
||||||
|
|
||||||
|
uniform float GlobalEmissionMultiplier;
|
||||||
|
uniform float GlobalAbsorptionMultiplier;
|
||||||
|
uniform float GlobalDecay;
|
||||||
|
uniform float DiffusionRate;
|
||||||
|
uniform float UpDiffusion;
|
||||||
|
uniform float DownDiffusion;
|
||||||
|
uniform float HorizontalDiffusion;
|
||||||
|
|
||||||
|
uniform vec3 VoxelSize;
|
||||||
|
uniform float CurrentZ;
|
||||||
|
|
||||||
|
in vec2 texCoord;
|
||||||
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
// Получение эмиссии из magnitude
|
||||||
|
float getEmission(uint magnitude, bool isAbsorber) {
|
||||||
|
if (isAbsorber || magnitude == 0u) return 0.0;
|
||||||
|
return float(magnitude) / 63.0 * 0.05;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получение абсорбции из magnitude
|
||||||
|
float getAbsorption(uint magnitude, bool isAbsorber) {
|
||||||
|
if (!isAbsorber || magnitude == 0u) return 0.0;
|
||||||
|
return float(magnitude) / 63.0 * 0.05;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 uv = vec3(texCoord, CurrentZ);
|
||||||
|
|
||||||
|
// Читаем упакованное значение
|
||||||
|
uint packedSelf = texture(WorldInfoSampler, uv).r;
|
||||||
|
|
||||||
|
// Распаковываем через арифметику (битовые операции не доступны в GLSL 1.50)
|
||||||
|
bool selfSolid = (packedSelf >= 128u);
|
||||||
|
uint tempSelf = packedSelf;
|
||||||
|
if (selfSolid) tempSelf -= 128u;
|
||||||
|
|
||||||
|
bool selfIsAbsorber = (tempSelf >= 64u);
|
||||||
|
if (selfIsAbsorber) tempSelf -= 64u;
|
||||||
|
|
||||||
|
uint selfMagnitude = tempSelf;
|
||||||
|
|
||||||
|
// Если solid, плотность всегда 0
|
||||||
|
if (selfSolid) {
|
||||||
|
FragColor = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Читаем текущую плотность
|
||||||
|
float fogOld = texture(FogReadSampler, uv).r;
|
||||||
|
float fogNew = fogOld;
|
||||||
|
|
||||||
|
// === 1. Emission ===
|
||||||
|
float emission = 0.0;
|
||||||
|
|
||||||
|
// Эмиссия от текущего вокселя (если non-solid источник)
|
||||||
|
emission += getEmission(selfMagnitude, selfIsAbsorber) * GlobalEmissionMultiplier;
|
||||||
|
|
||||||
|
// Эмиссия от соседних solid источников
|
||||||
|
// Инициализируем массив через индексы (так надежнее в GLSL 1.50)
|
||||||
|
vec3 offsets[6];
|
||||||
|
offsets[0] = vec3(VoxelSize.x, 0.0, 0.0); // +X
|
||||||
|
offsets[1] = vec3(-VoxelSize.x, 0.0, 0.0); // -X
|
||||||
|
offsets[2] = vec3(0.0, VoxelSize.y, 0.0); // +Y (Up)
|
||||||
|
offsets[3] = vec3(0.0, -VoxelSize.y, 0.0); // -Y (Down)
|
||||||
|
offsets[4] = vec3(0.0, 0.0, VoxelSize.z); // +Z
|
||||||
|
offsets[5] = vec3(0.0, 0.0, -VoxelSize.z); // -Z
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
vec3 neighborUV = uv + offsets[i];
|
||||||
|
uint packedNeighbor = texture(WorldInfoSampler, neighborUV).r;
|
||||||
|
|
||||||
|
// Распаковываем соседа
|
||||||
|
bool neighborSolid = (packedNeighbor >= 128u);
|
||||||
|
uint tempNeighbor = packedNeighbor;
|
||||||
|
if (neighborSolid) tempNeighbor -= 128u;
|
||||||
|
|
||||||
|
bool neighborIsAbsorber = (tempNeighbor >= 64u);
|
||||||
|
if (neighborIsAbsorber) tempNeighbor -= 64u;
|
||||||
|
|
||||||
|
uint neighborMagnitude = tempNeighbor;
|
||||||
|
|
||||||
|
// Solid источник влияет на non-solid соседей
|
||||||
|
if (neighborSolid) {
|
||||||
|
emission += getEmission(neighborMagnitude, neighborIsAbsorber) * GlobalEmissionMultiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fogNew += emission;
|
||||||
|
|
||||||
|
// === 2. Absorption ===
|
||||||
|
float absorption = 0.0;
|
||||||
|
|
||||||
|
// Поглощение от текущего вокселя (если non-solid поглотитель)
|
||||||
|
absorption += fogOld * getAbsorption(selfMagnitude, selfIsAbsorber) * GlobalAbsorptionMultiplier;
|
||||||
|
|
||||||
|
// Поглощение от соседних solid поглотителей
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
vec3 neighborUV = uv + offsets[i];
|
||||||
|
uint packedNeighbor = texture(WorldInfoSampler, neighborUV).r;
|
||||||
|
|
||||||
|
// Распаковываем соседа
|
||||||
|
bool neighborSolid = (packedNeighbor >= 128u);
|
||||||
|
uint tempNeighbor = packedNeighbor;
|
||||||
|
if (neighborSolid) tempNeighbor -= 128u;
|
||||||
|
|
||||||
|
bool neighborIsAbsorber = (tempNeighbor >= 64u);
|
||||||
|
if (neighborIsAbsorber) tempNeighbor -= 64u;
|
||||||
|
|
||||||
|
uint neighborMagnitude = tempNeighbor;
|
||||||
|
|
||||||
|
// Solid поглотитель влияет на non-solid соседей
|
||||||
|
if (neighborSolid) {
|
||||||
|
absorption += fogOld * getAbsorption(neighborMagnitude, neighborIsAbsorber) * GlobalAbsorptionMultiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fogNew -= absorption;
|
||||||
|
|
||||||
|
// === 3. Diffusion ===
|
||||||
|
float diffusion = 0.0;
|
||||||
|
|
||||||
|
// +X (right)
|
||||||
|
vec3 uvRight = uv + offsets[0];
|
||||||
|
uint packedRight = texture(WorldInfoSampler, uvRight).r;
|
||||||
|
bool rightSolid = (packedRight >= 128u);
|
||||||
|
if (!rightSolid) {
|
||||||
|
float fogRight = texture(FogReadSampler, uvRight).r;
|
||||||
|
diffusion += (fogRight - fogOld) * HorizontalDiffusion * DiffusionRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -X (left)
|
||||||
|
vec3 uvLeft = uv + offsets[1];
|
||||||
|
uint packedLeft = texture(WorldInfoSampler, uvLeft).r;
|
||||||
|
bool leftSolid = (packedLeft >= 128u);
|
||||||
|
if (!leftSolid) {
|
||||||
|
float fogLeft = texture(FogReadSampler, uvLeft).r;
|
||||||
|
diffusion += (fogLeft - fogOld) * HorizontalDiffusion * DiffusionRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// +Y (up)
|
||||||
|
vec3 uvUp = uv + offsets[2];
|
||||||
|
uint packedUp = texture(WorldInfoSampler, uvUp).r;
|
||||||
|
bool upSolid = (packedUp >= 128u);
|
||||||
|
if (!upSolid) {
|
||||||
|
float fogUp = texture(FogReadSampler, uvUp).r;
|
||||||
|
diffusion += (fogUp - fogOld) * UpDiffusion * DiffusionRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -Y (down)
|
||||||
|
vec3 uvDown = uv + offsets[3];
|
||||||
|
uint packedDown = texture(WorldInfoSampler, uvDown).r;
|
||||||
|
bool downSolid = (packedDown >= 128u);
|
||||||
|
if (!downSolid) {
|
||||||
|
float fogDown = texture(FogReadSampler, uvDown).r;
|
||||||
|
diffusion += (fogDown - fogOld) * DownDiffusion * DiffusionRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// +Z
|
||||||
|
vec3 uvFront = uv + offsets[4];
|
||||||
|
uint packedFront = texture(WorldInfoSampler, uvFront).r;
|
||||||
|
bool frontSolid = (packedFront >= 128u);
|
||||||
|
if (!frontSolid) {
|
||||||
|
float fogFront = texture(FogReadSampler, uvFront).r;
|
||||||
|
diffusion += (fogFront - fogOld) * HorizontalDiffusion * DiffusionRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -Z
|
||||||
|
vec3 uvBack = uv + offsets[5];
|
||||||
|
uint packedBack = texture(WorldInfoSampler, uvBack).r;
|
||||||
|
bool backSolid = (packedBack >= 128u);
|
||||||
|
if (!backSolid) {
|
||||||
|
float fogBack = texture(FogReadSampler, uvBack).r;
|
||||||
|
diffusion += (fogBack - fogOld) * HorizontalDiffusion * DiffusionRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
fogNew += diffusion;
|
||||||
|
|
||||||
|
// === 4. Global Decay ===
|
||||||
|
fogNew -= fogOld * GlobalDecay;
|
||||||
|
|
||||||
|
// === 5. Clamp ===
|
||||||
|
fogNew = clamp(fogNew, 0.0, 1.0);
|
||||||
|
|
||||||
|
FragColor = vec4(fogNew, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user