Симуляция работает
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.GLShader;
|
||||
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.FogWorldVolume;
|
||||
|
||||
@@ -154,7 +155,7 @@ public class PostProcessingManager {
|
||||
|
||||
GL11.glBindTexture(
|
||||
GL12.GL_TEXTURE_3D,
|
||||
FogWorldVolume.getTexture()
|
||||
FogSimulationManager.getCurrentDensityTexture()
|
||||
);
|
||||
|
||||
GL20.glUniform1i(
|
||||
|
||||
@@ -242,6 +242,8 @@ public final class FogChunkStreamer {
|
||||
int physicalIndex = physicalZ * FogWorldVolume.CHUNKS_X + physicalX;
|
||||
|
||||
FogWorldVolume.uploadZeros(physicalX, physicalZ);
|
||||
FogDensityTextures.clearColumn(physicalX, physicalZ);
|
||||
|
||||
statuses[physicalIndex] = ChunkStatus.PENDING;
|
||||
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();
|
||||
|
||||
FogSimulationManager.update();
|
||||
}
|
||||
|
||||
public static void tick() {
|
||||
@@ -36,6 +38,7 @@ public final class FogSystem {
|
||||
|
||||
private static void initialize() {
|
||||
FogWorldVolume.init();
|
||||
FogSimulationManager.init();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,9 @@ public class GameRendererMixin {
|
||||
boolean tick,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
FogSystem.beginRender();
|
||||
net.minecraft.client.MinecraftClient client = net.minecraft.client.MinecraftClient.getInstance();
|
||||
if (client.world != null && client.player != null) {
|
||||
FogSystem.beginRender();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
uniform sampler2D DiffuseSampler;
|
||||
uniform sampler2D DepthSampler;
|
||||
uniform usampler3D FogVolume;
|
||||
uniform sampler3D FogVolume;
|
||||
|
||||
uniform mat4 InverseProjection;
|
||||
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