Реймарчинг в уменьшеном разрешении
This commit is contained in:
@@ -22,55 +22,61 @@ import java.nio.FloatBuffer;
|
||||
|
||||
public class PostProcessingManager {
|
||||
|
||||
private static GLProgram program;
|
||||
private static GLProgram raymarchProgram;
|
||||
private static GLProgram compositeProgram;
|
||||
private static GLProgram depthDownsampleProgram;
|
||||
|
||||
/*
|
||||
* Матрицы
|
||||
*/
|
||||
private static int dd_depthSamplerLocation;
|
||||
private static int dd_screenSizeLocation;
|
||||
|
||||
// Фреймбуфер для scaled raymarching
|
||||
private static int scaledFBO;
|
||||
private static int scaledTexture;
|
||||
private static int scaledWidth;
|
||||
private static int scaledHeight;
|
||||
private static final float scale = 0.5f;
|
||||
|
||||
private static final Matrix4f projection = new Matrix4f();
|
||||
private static final Matrix4f inverseProjection = new Matrix4f();
|
||||
|
||||
private static final FloatBuffer projectionBuffer =
|
||||
BufferUtils.createFloatBuffer(16);
|
||||
|
||||
private static final FloatBuffer inverseProjectionBuffer =
|
||||
BufferUtils.createFloatBuffer(16);
|
||||
private static final FloatBuffer projectionBuffer = BufferUtils.createFloatBuffer(16);
|
||||
private static final FloatBuffer inverseProjectionBuffer = BufferUtils.createFloatBuffer(16);
|
||||
|
||||
/*
|
||||
* Uniform locations
|
||||
* Uniform locations - Raymarch Program
|
||||
*/
|
||||
private static int rm_projectionLocation;
|
||||
private static int rm_inverseProjectionLocation;
|
||||
private static int rm_depthSamplerLocation;
|
||||
private static int rm_fogVolumeLocation;
|
||||
private static int rm_lightVolumeLocation;
|
||||
private static int rm_fogOriginLocation;
|
||||
private static int rm_ringOffsetLocation;
|
||||
private static int rm_cameraPositionLocation;
|
||||
private static int rm_screenSizeLocation;
|
||||
private static int rm_viewLocation;
|
||||
private static int rm_inverseViewLocation;
|
||||
private static int rm_fogColorLocation;
|
||||
private static int rm_skyBrightnessLocation;
|
||||
|
||||
private static int projectionLocation;
|
||||
private static int inverseProjectionLocation;
|
||||
/*
|
||||
* Uniform locations - Composite Program (JBU)
|
||||
*/
|
||||
private static int comp_diffuseSamplerLocation;
|
||||
private static int comp_fogSamplerLocation;
|
||||
private static int comp_depthSamplerLocation;
|
||||
private static int comp_scaledDepthSamplerLocation;
|
||||
private static int comp_screenSizeLocation;
|
||||
private static int comp_scaledScreenSizeLocation;
|
||||
private static int comp_inverseProjectionLocation;
|
||||
|
||||
private static int diffuseSamplerLocation;
|
||||
private static int depthSamplerLocation;
|
||||
|
||||
private static int cameraPositionLocation;
|
||||
private static int screenSizeLocation;
|
||||
private static int scaledDepthTexture;
|
||||
|
||||
private static final Matrix4f view = new Matrix4f();
|
||||
private static final Matrix4f inverseView = new Matrix4f();
|
||||
|
||||
private static final FloatBuffer viewBuffer =
|
||||
BufferUtils.createFloatBuffer(16);
|
||||
|
||||
private static final FloatBuffer inverseViewBuffer =
|
||||
BufferUtils.createFloatBuffer(16);
|
||||
|
||||
private static int viewLocation;
|
||||
private static int inverseViewLocation;
|
||||
|
||||
private static int fogVolumeLocation;
|
||||
private static int lightVolumeLocation;
|
||||
|
||||
private static int fogOriginLocation;
|
||||
private static int ringOffsetLocation;
|
||||
private static final FloatBuffer viewBuffer = BufferUtils.createFloatBuffer(16);
|
||||
private static final FloatBuffer inverseViewBuffer = BufferUtils.createFloatBuffer(16);
|
||||
|
||||
private static float fogR, fogG, fogB;
|
||||
private static int fogColorLocation;
|
||||
private static int skyBrightnessLocation;
|
||||
|
||||
public static void setFogColor(float r, float g, float b) {
|
||||
fogR = r;
|
||||
@@ -79,56 +85,116 @@ public class PostProcessingManager {
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
|
||||
if (program != null)
|
||||
if (raymarchProgram != null)
|
||||
return;
|
||||
|
||||
setFogColor(0.75f, 0.80f, 0.90f);
|
||||
|
||||
GLShader vertex = new GLShader(
|
||||
// Инициализация raymarch программы
|
||||
GLShader rmVertex = new GLShader(
|
||||
GL20.GL_VERTEX_SHADER,
|
||||
ResourceUtil.load("shaders/fullscreen.vert")
|
||||
);
|
||||
|
||||
GLShader fragment = new GLShader(
|
||||
GLShader rmFragment = new GLShader(
|
||||
GL20.GL_FRAGMENT_SHADER,
|
||||
ResourceUtil.load("shaders/fog_raymarching.frag")
|
||||
);
|
||||
raymarchProgram = new GLProgram(rmVertex, rmFragment);
|
||||
|
||||
program = new GLProgram(vertex, fragment);
|
||||
rm_projectionLocation = raymarchProgram.uniform("Projection");
|
||||
rm_inverseProjectionLocation = raymarchProgram.uniform("InverseProjection");
|
||||
rm_depthSamplerLocation = raymarchProgram.uniform("DepthSampler");
|
||||
rm_fogVolumeLocation = raymarchProgram.uniform("FogVolume");
|
||||
rm_lightVolumeLocation = raymarchProgram.uniform("LightVolume");
|
||||
rm_fogOriginLocation = raymarchProgram.uniform("FogOrigin");
|
||||
rm_ringOffsetLocation = raymarchProgram.uniform("RingBlockOffset");
|
||||
rm_cameraPositionLocation = raymarchProgram.uniform("CameraPosition");
|
||||
rm_screenSizeLocation = raymarchProgram.uniform("ScreenSize");
|
||||
rm_viewLocation = raymarchProgram.uniform("View");
|
||||
rm_inverseViewLocation = raymarchProgram.uniform("InverseView");
|
||||
rm_fogColorLocation = raymarchProgram.uniform("FogColor");
|
||||
rm_skyBrightnessLocation = raymarchProgram.uniform("SkyBrightness");
|
||||
|
||||
projectionLocation = program.uniform("Projection");
|
||||
inverseProjectionLocation = program.uniform("InverseProjection");
|
||||
rmVertex.delete();
|
||||
rmFragment.delete();
|
||||
|
||||
diffuseSamplerLocation = program.uniform("DiffuseSampler");
|
||||
depthSamplerLocation = program.uniform("DepthSampler");
|
||||
// Инициализация composite программы с JBU
|
||||
GLShader compVertex = new GLShader(
|
||||
GL20.GL_VERTEX_SHADER,
|
||||
ResourceUtil.load("shaders/fullscreen.vert")
|
||||
);
|
||||
GLShader compFragment = new GLShader(
|
||||
GL20.GL_FRAGMENT_SHADER,
|
||||
ResourceUtil.load("shaders/fog_composite.frag")
|
||||
);
|
||||
compositeProgram = new GLProgram(compVertex, compFragment);
|
||||
|
||||
fogVolumeLocation = program.uniform("FogVolume");
|
||||
lightVolumeLocation = program.uniform("LightVolume");
|
||||
comp_diffuseSamplerLocation = compositeProgram.uniform("DiffuseSampler");
|
||||
comp_fogSamplerLocation = compositeProgram.uniform("FogSampler");
|
||||
comp_depthSamplerLocation = compositeProgram.uniform("DepthSampler");
|
||||
comp_scaledDepthSamplerLocation = compositeProgram.uniform("ScaledDepthSampler");
|
||||
comp_screenSizeLocation = compositeProgram.uniform("ScreenSize");
|
||||
comp_scaledScreenSizeLocation = compositeProgram.uniform("ScaledScreenSize");
|
||||
comp_inverseProjectionLocation = compositeProgram.uniform("InverseProjection");
|
||||
|
||||
fogOriginLocation = program.uniform("FogOrigin");
|
||||
ringOffsetLocation = program.uniform("RingBlockOffset");
|
||||
compVertex.delete();
|
||||
compFragment.delete();
|
||||
|
||||
cameraPositionLocation = program.uniform("CameraPosition");
|
||||
screenSizeLocation = program.uniform("ScreenSize");
|
||||
GLShader ddVertex = new GLShader(
|
||||
GL20.GL_VERTEX_SHADER,
|
||||
ResourceUtil.load("shaders/fullscreen.vert")
|
||||
);
|
||||
GLShader ddFragment = new GLShader(
|
||||
GL20.GL_FRAGMENT_SHADER,
|
||||
ResourceUtil.load("shaders/depth_downsample.frag")
|
||||
);
|
||||
depthDownsampleProgram = new GLProgram(ddVertex, ddFragment);
|
||||
|
||||
viewLocation = program.uniform("View");
|
||||
inverseViewLocation = program.uniform("InverseView");
|
||||
dd_depthSamplerLocation = depthDownsampleProgram.uniform("DepthSampler");
|
||||
dd_screenSizeLocation = depthDownsampleProgram.uniform("ScreenSize");
|
||||
|
||||
fogColorLocation = program.uniform("FogColor");
|
||||
skyBrightnessLocation = program.uniform("SkyBrightness");
|
||||
ddVertex.delete();
|
||||
ddFragment.delete();
|
||||
|
||||
FullscreenQuad.init();
|
||||
|
||||
vertex.delete();
|
||||
fragment.delete();
|
||||
System.out.println("VEILA shaders compiled!");
|
||||
}
|
||||
|
||||
System.out.println("VEILA shader compiled!");
|
||||
private static void initScaledFramebuffer(int width, int height) {
|
||||
scaledWidth = (int)(width * scale);
|
||||
scaledHeight = (int)(height * scale);
|
||||
|
||||
scaledFBO = GL30.glGenFramebuffers();
|
||||
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, scaledFBO);
|
||||
|
||||
scaledTexture = GL11.glGenTextures();
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, scaledTexture);
|
||||
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL30.GL_RGBA16F, scaledWidth, scaledHeight, 0, GL11.GL_RGBA, GL11.GL_FLOAT, 0);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
|
||||
|
||||
GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, scaledTexture, 0);
|
||||
|
||||
// Half-res depth buffer
|
||||
scaledDepthTexture = GL11.glGenTextures();
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, scaledDepthTexture);
|
||||
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL30.GL_R32F, scaledWidth, scaledHeight, 0, GL11.GL_RED, GL11.GL_FLOAT, 0);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
|
||||
|
||||
GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT1, GL11.GL_TEXTURE_2D, scaledDepthTexture, 0);
|
||||
|
||||
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
public static void render(float tickDelta) {
|
||||
|
||||
if (program == null)
|
||||
if (raymarchProgram == null)
|
||||
return;
|
||||
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
@@ -141,174 +207,176 @@ public class PostProcessingManager {
|
||||
int width = framebuffer.textureWidth;
|
||||
int height = framebuffer.textureHeight;
|
||||
|
||||
GL30.glBindFramebuffer(
|
||||
GL30.GL_READ_FRAMEBUFFER,
|
||||
framebuffer.fbo
|
||||
);
|
||||
// Инициализация scaled фреймбуфера
|
||||
if (scaledFBO == 0 || scaledWidth != (int)(width * scale) || scaledHeight != (int)(height * scale)) {
|
||||
if (scaledFBO != 0) {
|
||||
GL30.glDeleteFramebuffers(scaledFBO);
|
||||
GL11.glDeleteTextures(scaledTexture);
|
||||
GL11.glDeleteTextures(scaledDepthTexture);
|
||||
}
|
||||
initScaledFramebuffer(width, height);
|
||||
}
|
||||
|
||||
GL30.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, framebuffer.fbo);
|
||||
|
||||
DepthCopy.init(width, height);
|
||||
DepthCopy.copy(width, height);
|
||||
|
||||
program.bind();
|
||||
renderDepthDownsample(width, height);
|
||||
|
||||
/*
|
||||
* Diffuse
|
||||
*/
|
||||
// === Этап 1: Raymarching в scaled разрешении ===
|
||||
renderRaymarching(tickDelta, client);
|
||||
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
GL11.glBindTexture(
|
||||
GL11.GL_TEXTURE_2D,
|
||||
framebuffer.getColorAttachment()
|
||||
);
|
||||
GL20.glUniform1i(diffuseSamplerLocation, 0);
|
||||
|
||||
/*
|
||||
* Depth
|
||||
*/
|
||||
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE1);
|
||||
GL11.glBindTexture(
|
||||
GL11.GL_TEXTURE_2D,
|
||||
DepthCopy.getTexture()
|
||||
);
|
||||
GL20.glUniform1i(depthSamplerLocation, 1);
|
||||
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE2);
|
||||
|
||||
GL11.glBindTexture(
|
||||
GL12.GL_TEXTURE_3D,
|
||||
FogSimulationManager.getCurrentDensityTexture()
|
||||
);
|
||||
|
||||
GL20.glUniform1i(
|
||||
fogVolumeLocation,
|
||||
2
|
||||
);
|
||||
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE3);
|
||||
GL11.glBindTexture(
|
||||
GL12.GL_TEXTURE_3D,
|
||||
FogLightVolume.getTexture()
|
||||
);
|
||||
GL20.glUniform1i(lightVolumeLocation, 3);
|
||||
|
||||
GL20.glUniform2i(
|
||||
fogOriginLocation,
|
||||
FogSystem.originChunkX() * FogWorldVolume.CHUNK_SIZE,
|
||||
FogSystem.originChunkZ() * FogWorldVolume.CHUNK_SIZE
|
||||
);
|
||||
|
||||
GL20.glUniform2i(
|
||||
ringOffsetLocation,
|
||||
FogSystem.ringChunkOffsetX() * FogWorldVolume.CHUNK_SIZE,
|
||||
FogSystem.ringChunkOffsetZ() * FogWorldVolume.CHUNK_SIZE
|
||||
);
|
||||
|
||||
/*
|
||||
* Матрицы
|
||||
*/
|
||||
|
||||
updateProjectionMatrices();
|
||||
|
||||
GL20.glUniformMatrix4fv(
|
||||
projectionLocation,
|
||||
false,
|
||||
projectionBuffer
|
||||
);
|
||||
|
||||
GL20.glUniformMatrix4fv(
|
||||
inverseProjectionLocation,
|
||||
false,
|
||||
inverseProjectionBuffer
|
||||
);
|
||||
|
||||
GL20.glUniformMatrix4fv(
|
||||
viewLocation,
|
||||
false,
|
||||
viewBuffer
|
||||
);
|
||||
|
||||
GL20.glUniformMatrix4fv(
|
||||
inverseViewLocation,
|
||||
false,
|
||||
inverseViewBuffer
|
||||
);
|
||||
|
||||
/*
|
||||
* Камера
|
||||
*/
|
||||
|
||||
Camera camera = client.gameRenderer.getCamera();
|
||||
Vec3d pos = camera.getPos();
|
||||
|
||||
GL20.glUniform3f(
|
||||
cameraPositionLocation,
|
||||
(float) pos.x,
|
||||
(float) pos.y,
|
||||
(float) pos.z
|
||||
);
|
||||
|
||||
/*
|
||||
* Размер экрана
|
||||
*/
|
||||
|
||||
GL20.glUniform2f(
|
||||
screenSizeLocation,
|
||||
width,
|
||||
height
|
||||
);
|
||||
|
||||
/*
|
||||
* Цвет тумана
|
||||
*/
|
||||
|
||||
GL20.glUniform3f(
|
||||
fogColorLocation,
|
||||
fogR,
|
||||
fogG,
|
||||
fogB
|
||||
);
|
||||
|
||||
/*
|
||||
* Яркость тумана
|
||||
*/
|
||||
|
||||
GL20.glUniform1f(
|
||||
skyBrightnessLocation,
|
||||
client.world.getSkyBrightness(tickDelta)
|
||||
);
|
||||
|
||||
FullscreenQuad.draw();
|
||||
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE3);
|
||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, 0);
|
||||
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE2);
|
||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, 0);
|
||||
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE1);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
|
||||
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
|
||||
|
||||
program.unbind();
|
||||
|
||||
GL30.glBindFramebuffer(
|
||||
GL30.GL_READ_FRAMEBUFFER,
|
||||
0
|
||||
);
|
||||
// === Этап 2: Композитинг с JBU в полном разрешении ===
|
||||
renderComposite(framebuffer, width, height);
|
||||
|
||||
GL30.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, 0);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
}
|
||||
|
||||
private static void renderDepthDownsample(int width, int height) {
|
||||
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, scaledFBO);
|
||||
|
||||
// Настраиваем draw buffers для MRT
|
||||
GL30.glDrawBuffer(GL30.GL_COLOR_ATTACHMENT1);
|
||||
|
||||
GL11.glViewport(0, 0, scaledWidth, scaledHeight);
|
||||
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
depthDownsampleProgram.bind();
|
||||
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, DepthCopy.getTexture());
|
||||
GL20.glUniform1i(dd_depthSamplerLocation, 0);
|
||||
|
||||
GL20.glUniform2f(dd_screenSizeLocation, width, height);
|
||||
|
||||
FullscreenQuad.draw();
|
||||
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
|
||||
depthDownsampleProgram.unbind();
|
||||
}
|
||||
|
||||
private static void renderRaymarching(float tickDelta, MinecraftClient client) {
|
||||
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, scaledFBO);
|
||||
|
||||
// Настраиваем draw buffer для raymarching
|
||||
GL30.glDrawBuffer(GL30.GL_COLOR_ATTACHMENT0);
|
||||
|
||||
GL11.glViewport(0, 0, scaledWidth, scaledHeight);
|
||||
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
raymarchProgram.bind();
|
||||
|
||||
// Depth
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, scaledDepthTexture);
|
||||
GL20.glUniform1i(rm_depthSamplerLocation, 0);
|
||||
|
||||
// Fog Volume
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE1);
|
||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, FogSimulationManager.getCurrentDensityTexture());
|
||||
GL20.glUniform1i(rm_fogVolumeLocation, 1);
|
||||
|
||||
// Light Volume
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE2);
|
||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, FogLightVolume.getTexture());
|
||||
GL20.glUniform1i(rm_lightVolumeLocation, 2);
|
||||
|
||||
GL20.glUniform2i(rm_fogOriginLocation,
|
||||
FogSystem.originChunkX() * FogWorldVolume.CHUNK_SIZE,
|
||||
FogSystem.originChunkZ() * FogWorldVolume.CHUNK_SIZE);
|
||||
|
||||
GL20.glUniform2i(rm_ringOffsetLocation,
|
||||
FogSystem.ringChunkOffsetX() * FogWorldVolume.CHUNK_SIZE,
|
||||
FogSystem.ringChunkOffsetZ() * FogWorldVolume.CHUNK_SIZE);
|
||||
|
||||
// Матрицы
|
||||
updateProjectionMatrices();
|
||||
GL20.glUniformMatrix4fv(rm_projectionLocation, false, projectionBuffer);
|
||||
GL20.glUniformMatrix4fv(rm_inverseProjectionLocation, false, inverseProjectionBuffer);
|
||||
GL20.glUniformMatrix4fv(rm_viewLocation, false, viewBuffer);
|
||||
GL20.glUniformMatrix4fv(rm_inverseViewLocation, false, inverseViewBuffer);
|
||||
|
||||
// Камера
|
||||
Camera camera = client.gameRenderer.getCamera();
|
||||
Vec3d pos = camera.getPos();
|
||||
GL20.glUniform3f(rm_cameraPositionLocation, (float) pos.x, (float) pos.y, (float) pos.z);
|
||||
|
||||
// Размер экрана (scaled)
|
||||
GL20.glUniform2f(rm_screenSizeLocation, scaledWidth, scaledHeight);
|
||||
|
||||
// Цвет тумана
|
||||
GL20.glUniform3f(rm_fogColorLocation, fogR, fogG, fogB);
|
||||
|
||||
// Яркость неба
|
||||
GL20.glUniform1f(rm_skyBrightnessLocation, client.world.getSkyBrightness(tickDelta));
|
||||
|
||||
FullscreenQuad.draw();
|
||||
|
||||
// Очистка текстур
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE2);
|
||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, 0);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE1);
|
||||
GL11.glBindTexture(GL12.GL_TEXTURE_3D, 0);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
|
||||
|
||||
raymarchProgram.unbind();
|
||||
}
|
||||
|
||||
private static void renderComposite(Framebuffer framebuffer, int width, int height) {
|
||||
GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, framebuffer.fbo);
|
||||
GL11.glViewport(0, 0, width, height);
|
||||
|
||||
compositeProgram.bind();
|
||||
|
||||
// Original scene (Diffuse)
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, framebuffer.getColorAttachment());
|
||||
GL20.glUniform1i(comp_diffuseSamplerLocation, 0);
|
||||
|
||||
// Scaled fog results
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE1);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, scaledTexture);
|
||||
GL20.glUniform1i(comp_fogSamplerLocation, 1);
|
||||
|
||||
// Full-res depth для JBU
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE2);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, DepthCopy.getTexture());
|
||||
GL20.glUniform1i(comp_depthSamplerLocation, 2);
|
||||
|
||||
// Half-res depth для JBU
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE3);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, scaledDepthTexture);
|
||||
GL20.glUniform1i(comp_scaledDepthSamplerLocation, 3);
|
||||
|
||||
// Матрицы для линеаризации depth
|
||||
updateProjectionMatrices();
|
||||
GL20.glUniformMatrix4fv(comp_inverseProjectionLocation, false, inverseProjectionBuffer);
|
||||
|
||||
// Screen size
|
||||
GL20.glUniform2f(comp_screenSizeLocation, width, height);
|
||||
GL20.glUniform2f(comp_scaledScreenSizeLocation, scaledWidth, scaledHeight);
|
||||
|
||||
FullscreenQuad.draw();
|
||||
|
||||
// Очистка
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE3);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE2);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE1);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
|
||||
|
||||
compositeProgram.unbind();
|
||||
}
|
||||
|
||||
private static void updateProjectionMatrices() {
|
||||
|
||||
projection.set(RenderSystem.getProjectionMatrix());
|
||||
|
||||
inverseProjection
|
||||
.set(projection)
|
||||
.invert();
|
||||
inverseProjection.set(projection).invert();
|
||||
|
||||
projectionBuffer.clear();
|
||||
projection.get(projectionBuffer);
|
||||
@@ -318,12 +386,8 @@ public class PostProcessingManager {
|
||||
}
|
||||
|
||||
public static void updateViewMatrix(Matrix4f matrix) {
|
||||
|
||||
view.set(matrix);
|
||||
|
||||
inverseView
|
||||
.set(matrix)
|
||||
.invert();
|
||||
inverseView.set(matrix).invert();
|
||||
|
||||
viewBuffer.clear();
|
||||
view.get(viewBuffer);
|
||||
@@ -331,5 +395,4 @@ public class PostProcessingManager {
|
||||
inverseViewBuffer.clear();
|
||||
inverseView.get(inverseViewBuffer);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#version 150
|
||||
|
||||
uniform sampler2D DepthSampler;
|
||||
uniform vec2 ScreenSize;
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 texelSize = 1.0 / ScreenSize;
|
||||
|
||||
// Берём минимальный depth из 2x2 блока (ближайший объект)
|
||||
float d00 = texture(DepthSampler, texCoord + vec2(-0.5, -0.5) * texelSize).r;
|
||||
float d10 = texture(DepthSampler, texCoord + vec2( 0.5, -0.5) * texelSize).r;
|
||||
float d01 = texture(DepthSampler, texCoord + vec2(-0.5, 0.5) * texelSize).r;
|
||||
float d11 = texture(DepthSampler, texCoord + vec2( 0.5, 0.5) * texelSize).r;
|
||||
|
||||
float minDepth = min(min(d00, d10), min(d01, d11));
|
||||
|
||||
FragColor = vec4(minDepth, 0.0, 0.0, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
#version 150
|
||||
|
||||
uniform sampler2D DiffuseSampler;
|
||||
uniform sampler2D FogSampler;
|
||||
uniform sampler2D DepthSampler;
|
||||
uniform sampler2D ScaledDepthSampler;
|
||||
uniform vec2 ScreenSize;
|
||||
uniform vec2 ScaledScreenSize;
|
||||
uniform mat4 InverseProjection;
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Параметры JBU
|
||||
//------------------------------------------------------------
|
||||
|
||||
const int WINDOW_SIZE = 5;
|
||||
const int WINDOW_RADIUS = WINDOW_SIZE / 2;
|
||||
|
||||
const float SIGMA_SPATIAL = 2.0;
|
||||
const float SIGMA_SPECTRAL = 0.3; // Меньше = резче границы
|
||||
|
||||
const float MIN_WEIGHT = 0.0001;
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
// Предвычисленные spatial weights для окна 5x5
|
||||
const float spatialWeights[25] = float[25](
|
||||
0.003765, 0.015019, 0.023792, 0.015019, 0.003765,
|
||||
0.015019, 0.059912, 0.094907, 0.059912, 0.015019,
|
||||
0.023792, 0.094907, 0.150342, 0.094907, 0.023792,
|
||||
0.015019, 0.059912, 0.094907, 0.059912, 0.015019,
|
||||
0.003765, 0.015019, 0.023792, 0.015019, 0.003765
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
float linearizeDepth(float depth)
|
||||
{
|
||||
vec4 clip = vec4(0.0, 0.0, depth * 2.0 - 1.0, 1.0);
|
||||
vec4 view = InverseProjection * clip;
|
||||
return -view.z / view.w;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 sceneColor = texture(DiffuseSampler, texCoord).rgb;
|
||||
|
||||
// Линеаризованный depth текущего full-res пикселя
|
||||
float depthFull = linearizeDepth(texture(DepthSampler, texCoord).r);
|
||||
|
||||
vec2 lowResCoord = texCoord;
|
||||
vec2 texelSize = 1.0 / ScaledScreenSize;
|
||||
|
||||
vec4 sumColor = vec4(0.0);
|
||||
float sumWeight = 0.0;
|
||||
|
||||
int sampleIndex = 0;
|
||||
|
||||
for (int y = -WINDOW_RADIUS; y <= WINDOW_RADIUS; y++) {
|
||||
for (int x = -WINDOW_RADIUS; x <= WINDOW_RADIUS; x++) {
|
||||
vec2 neighborCoord = lowResCoord + vec2(float(x), float(y)) * texelSize;
|
||||
|
||||
if (any(lessThan(neighborCoord, vec2(0.0))) || any(greaterThan(neighborCoord, vec2(1.0)))) {
|
||||
sampleIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
float wSpatial = spatialWeights[sampleIndex];
|
||||
|
||||
// Линеаризованный depth из half-res depth buffer
|
||||
float depthNeighbor = linearizeDepth(texture(ScaledDepthSampler, neighborCoord).r);
|
||||
float depthDiff = abs(depthFull - depthNeighbor);
|
||||
|
||||
// Range weight с линеаризованным depth в метрах
|
||||
float wRange = exp(-(depthDiff * depthDiff) / (2.0 * SIGMA_SPECTRAL * SIGMA_SPECTRAL));
|
||||
|
||||
float weight = wSpatial * wRange;
|
||||
|
||||
vec4 fogSample = texture(FogSampler, neighborCoord);
|
||||
|
||||
sumColor += fogSample * weight;
|
||||
sumWeight += weight;
|
||||
|
||||
sampleIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
vec4 result;
|
||||
if (sumWeight < MIN_WEIGHT) {
|
||||
result = texture(FogSampler, lowResCoord);
|
||||
} else {
|
||||
result = sumColor / sumWeight;
|
||||
}
|
||||
|
||||
vec3 scattered = result.rgb;
|
||||
float transmittance = result.a;
|
||||
|
||||
vec3 finalColor = sceneColor * transmittance + scattered;
|
||||
|
||||
FragColor = vec4(finalColor, 1.0);
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
#version 150
|
||||
|
||||
uniform sampler2D DiffuseSampler;
|
||||
uniform sampler2D DepthSampler;
|
||||
uniform sampler3D FogVolume;
|
||||
uniform sampler3D LightVolume;
|
||||
@@ -38,22 +37,9 @@ const float GAMMA = 2.0;
|
||||
|
||||
const bool USE_JITTERING = false;
|
||||
|
||||
// Физические коэффициенты volumetric rendering
|
||||
// EXTINCTION: насколько сильно туман поглощает/рассеивает свет (0.1-2.0)
|
||||
// Больше значение = туман сильнее затеняет далёкие объекты
|
||||
const float EXTINCTION_COEFF = 1.0;
|
||||
|
||||
// SCATTERING: насколько сильно туман сам светится от источников
|
||||
// Обычно равен EXTINCTION (консервативная среда), но можно варьировать
|
||||
const float SCATTERING_COEFF = 1.0;
|
||||
|
||||
// Ambient — базовое освещение среды (воздух, микрочастицы).
|
||||
// Не зависит от времени суток и от skyLight/blockLight.
|
||||
// Даёт минимальную видимость тумана даже в полной темноте.
|
||||
const float AMBIENT_INTENSITY = 0.10;
|
||||
|
||||
// Порог transmittance для early termination (оптимизация)
|
||||
// Если transmittance упал ниже этого значения, дальнейшие шаги ничего не внесут
|
||||
const float MIN_TRANSMITTANCE = 0.01;
|
||||
|
||||
//------------------------------------------------------------
|
||||
@@ -145,8 +131,6 @@ float mapParameterToDistance(float t)
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 sceneColor = texture(DiffuseSampler, texCoord);
|
||||
|
||||
vec3 worldPos = reconstructWorldPosition(texCoord);
|
||||
vec3 rayDir = normalize(worldPos - CameraPosition);
|
||||
|
||||
@@ -156,14 +140,10 @@ void main()
|
||||
vec3 samplePos = CameraPosition;
|
||||
float currentDistance = 0.0;
|
||||
|
||||
// Transmittance: сколько света от сцены дошло до текущего шага
|
||||
// Начинается с 1.0 (всё доходит) и экспоненциально падает
|
||||
float transmittance = 1.0;
|
||||
|
||||
// Накопленный in-scattered свет (взвешенный по transmittance)
|
||||
float skyScattered = 0.0;
|
||||
float blockScattered = 0.0;
|
||||
|
||||
float ambientScattered = 0.0;
|
||||
|
||||
float jitter = 0.0;
|
||||
@@ -192,36 +172,25 @@ void main()
|
||||
|
||||
float d = density(samplePos);
|
||||
|
||||
// Оптическая толщина этого шага
|
||||
float opticalDepth = d * stepSize * EXTINCTION_COEFF;
|
||||
|
||||
if (d > 0.0) {
|
||||
// Получаем освещение в текущей точке
|
||||
vec2 lightValues = light(samplePos);
|
||||
float totalLightAtPoint = lightValues.x + lightValues.y;
|
||||
|
||||
// Базовая формула in-scattering для каждого источника
|
||||
float baseScattering = d * stepSize * SCATTERING_COEFF;
|
||||
|
||||
// In-scattering: свет, рассеянный в камерy из этого шага.
|
||||
// Умножается на transmittance до этого шага (дальний туман затенён ближним).
|
||||
// Умножается на плотность (больше частиц = больше рассеяния).
|
||||
float stepScattering = totalLightAtPoint * d * stepSize * SCATTERING_COEFF;
|
||||
|
||||
// Вклад ослабляется текущим transmittance
|
||||
skyScattered += lightValues.x * baseScattering * transmittance;
|
||||
//Свет от блоков не должен делать значимо ярче те воксели, которые и так подсвечены солнцем. Солнечный свет очень яркий, с ним сложно сравниться
|
||||
blockScattered += lightValues.y * baseScattering * transmittance*((lightValues.y-lightValues.x)*0.9+0.1);
|
||||
blockScattered += lightValues.y * baseScattering * transmittance * ((lightValues.y - lightValues.x) * 0.9 + 0.1);
|
||||
ambientScattered += AMBIENT_INTENSITY * baseScattering * transmittance;
|
||||
|
||||
// Обновляем transmittance: Beer-Lambert law
|
||||
transmittance *= exp(-opticalDepth);
|
||||
}
|
||||
|
||||
currentDistance = nextDistance;
|
||||
|
||||
// Early termination: если transmittance упал почти до нуля,
|
||||
// дальние шаги ничего не внесут в итоговый цвет
|
||||
if (transmittance < MIN_TRANSMITTANCE) {
|
||||
transmittance = 0.0;
|
||||
break;
|
||||
@@ -232,18 +201,10 @@ void main()
|
||||
}
|
||||
}
|
||||
|
||||
// Суммарное освещение, рассеянное в камеру
|
||||
float totalScattered = skyScattered + blockScattered + ambientScattered;
|
||||
|
||||
// Финальный цвет:
|
||||
// - sceneColor × transmittance: сцена, ослабленная туманом (Beer-Lambert)
|
||||
// - FogColor × totalScattered: свет, который рассеялся в тумане и попал в камеру
|
||||
//
|
||||
// Эта формула физически корректна:
|
||||
// - Когда тумана нет (transmittance=1, scattered=0): result = sceneColor ✓
|
||||
// - Когда туман очень плотный (transmittance=0): result = FogColor × scattered ✓
|
||||
// - Фонарь в толще тумана: ближние слои дают scattered, дальние уже не видны
|
||||
vec3 finalColor = sceneColor.rgb * transmittance + FogColor * totalScattered;
|
||||
// Выводим: RGB = вложенный свет тумана, A = transmittance
|
||||
vec3 fogColor = FogColor * totalScattered;
|
||||
|
||||
FragColor = vec4(finalColor, 1.0);
|
||||
FragColor = vec4(fogColor, transmittance);
|
||||
}
|
||||
Reference in New Issue
Block a user