Реймарчинг в уменьшеном разрешении
This commit is contained in:
@@ -22,55 +22,61 @@ import java.nio.FloatBuffer;
|
|||||||
|
|
||||||
public class PostProcessingManager {
|
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 projection = new Matrix4f();
|
||||||
private static final Matrix4f inverseProjection = new Matrix4f();
|
private static final Matrix4f inverseProjection = new Matrix4f();
|
||||||
|
private static final FloatBuffer projectionBuffer = BufferUtils.createFloatBuffer(16);
|
||||||
private static final FloatBuffer projectionBuffer =
|
private static final FloatBuffer inverseProjectionBuffer = BufferUtils.createFloatBuffer(16);
|
||||||
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 scaledDepthTexture;
|
||||||
private static int depthSamplerLocation;
|
|
||||||
|
|
||||||
private static int cameraPositionLocation;
|
|
||||||
private static int screenSizeLocation;
|
|
||||||
|
|
||||||
private static final Matrix4f view = new Matrix4f();
|
private static final Matrix4f view = new Matrix4f();
|
||||||
private static final Matrix4f inverseView = new Matrix4f();
|
private static final Matrix4f inverseView = new Matrix4f();
|
||||||
|
private static final FloatBuffer viewBuffer = BufferUtils.createFloatBuffer(16);
|
||||||
private static final FloatBuffer viewBuffer =
|
private static final FloatBuffer inverseViewBuffer = BufferUtils.createFloatBuffer(16);
|
||||||
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 float fogR, fogG, fogB;
|
private static float fogR, fogG, fogB;
|
||||||
private static int fogColorLocation;
|
|
||||||
private static int skyBrightnessLocation;
|
|
||||||
|
|
||||||
public static void setFogColor(float r, float g, float b) {
|
public static void setFogColor(float r, float g, float b) {
|
||||||
fogR = r;
|
fogR = r;
|
||||||
@@ -79,56 +85,116 @@ public class PostProcessingManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
|
if (raymarchProgram != null)
|
||||||
if (program != null)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
setFogColor(0.75f, 0.80f, 0.90f);
|
setFogColor(0.75f, 0.80f, 0.90f);
|
||||||
|
|
||||||
GLShader vertex = new GLShader(
|
// Инициализация raymarch программы
|
||||||
|
GLShader rmVertex = new GLShader(
|
||||||
GL20.GL_VERTEX_SHADER,
|
GL20.GL_VERTEX_SHADER,
|
||||||
ResourceUtil.load("shaders/fullscreen.vert")
|
ResourceUtil.load("shaders/fullscreen.vert")
|
||||||
);
|
);
|
||||||
|
GLShader rmFragment = new GLShader(
|
||||||
GLShader fragment = new GLShader(
|
|
||||||
GL20.GL_FRAGMENT_SHADER,
|
GL20.GL_FRAGMENT_SHADER,
|
||||||
ResourceUtil.load("shaders/fog_raymarching.frag")
|
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");
|
rmVertex.delete();
|
||||||
inverseProjectionLocation = program.uniform("InverseProjection");
|
rmFragment.delete();
|
||||||
|
|
||||||
diffuseSamplerLocation = program.uniform("DiffuseSampler");
|
// Инициализация composite программы с JBU
|
||||||
depthSamplerLocation = program.uniform("DepthSampler");
|
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");
|
comp_diffuseSamplerLocation = compositeProgram.uniform("DiffuseSampler");
|
||||||
lightVolumeLocation = program.uniform("LightVolume");
|
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");
|
compVertex.delete();
|
||||||
ringOffsetLocation = program.uniform("RingBlockOffset");
|
compFragment.delete();
|
||||||
|
|
||||||
cameraPositionLocation = program.uniform("CameraPosition");
|
GLShader ddVertex = new GLShader(
|
||||||
screenSizeLocation = program.uniform("ScreenSize");
|
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");
|
dd_depthSamplerLocation = depthDownsampleProgram.uniform("DepthSampler");
|
||||||
inverseViewLocation = program.uniform("InverseView");
|
dd_screenSizeLocation = depthDownsampleProgram.uniform("ScreenSize");
|
||||||
|
|
||||||
fogColorLocation = program.uniform("FogColor");
|
ddVertex.delete();
|
||||||
skyBrightnessLocation = program.uniform("SkyBrightness");
|
ddFragment.delete();
|
||||||
|
|
||||||
FullscreenQuad.init();
|
FullscreenQuad.init();
|
||||||
|
|
||||||
vertex.delete();
|
System.out.println("VEILA shaders compiled!");
|
||||||
fragment.delete();
|
}
|
||||||
|
|
||||||
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) {
|
public static void render(float tickDelta) {
|
||||||
|
if (raymarchProgram == null)
|
||||||
if (program == null)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MinecraftClient client = MinecraftClient.getInstance();
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
@@ -141,174 +207,176 @@ public class PostProcessingManager {
|
|||||||
int width = framebuffer.textureWidth;
|
int width = framebuffer.textureWidth;
|
||||||
int height = framebuffer.textureHeight;
|
int height = framebuffer.textureHeight;
|
||||||
|
|
||||||
GL30.glBindFramebuffer(
|
// Инициализация scaled фреймбуфера
|
||||||
GL30.GL_READ_FRAMEBUFFER,
|
if (scaledFBO == 0 || scaledWidth != (int)(width * scale) || scaledHeight != (int)(height * scale)) {
|
||||||
framebuffer.fbo
|
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.init(width, height);
|
||||||
DepthCopy.copy(width, height);
|
DepthCopy.copy(width, height);
|
||||||
|
|
||||||
program.bind();
|
renderDepthDownsample(width, height);
|
||||||
|
|
||||||
/*
|
// === Этап 1: Raymarching в scaled разрешении ===
|
||||||
* Diffuse
|
renderRaymarching(tickDelta, client);
|
||||||
*/
|
|
||||||
|
|
||||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
// === Этап 2: Композитинг с JBU в полном разрешении ===
|
||||||
GL11.glBindTexture(
|
renderComposite(framebuffer, width, height);
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
|
GL30.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, 0);
|
||||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
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() {
|
private static void updateProjectionMatrices() {
|
||||||
|
|
||||||
projection.set(RenderSystem.getProjectionMatrix());
|
projection.set(RenderSystem.getProjectionMatrix());
|
||||||
|
inverseProjection.set(projection).invert();
|
||||||
inverseProjection
|
|
||||||
.set(projection)
|
|
||||||
.invert();
|
|
||||||
|
|
||||||
projectionBuffer.clear();
|
projectionBuffer.clear();
|
||||||
projection.get(projectionBuffer);
|
projection.get(projectionBuffer);
|
||||||
@@ -318,12 +386,8 @@ public class PostProcessingManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void updateViewMatrix(Matrix4f matrix) {
|
public static void updateViewMatrix(Matrix4f matrix) {
|
||||||
|
|
||||||
view.set(matrix);
|
view.set(matrix);
|
||||||
|
inverseView.set(matrix).invert();
|
||||||
inverseView
|
|
||||||
.set(matrix)
|
|
||||||
.invert();
|
|
||||||
|
|
||||||
viewBuffer.clear();
|
viewBuffer.clear();
|
||||||
view.get(viewBuffer);
|
view.get(viewBuffer);
|
||||||
@@ -331,5 +395,4 @@ public class PostProcessingManager {
|
|||||||
inverseViewBuffer.clear();
|
inverseViewBuffer.clear();
|
||||||
inverseView.get(inverseViewBuffer);
|
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
|
#version 150
|
||||||
|
|
||||||
uniform sampler2D DiffuseSampler;
|
|
||||||
uniform sampler2D DepthSampler;
|
uniform sampler2D DepthSampler;
|
||||||
uniform sampler3D FogVolume;
|
uniform sampler3D FogVolume;
|
||||||
uniform sampler3D LightVolume;
|
uniform sampler3D LightVolume;
|
||||||
@@ -38,22 +37,9 @@ const float GAMMA = 2.0;
|
|||||||
|
|
||||||
const bool USE_JITTERING = false;
|
const bool USE_JITTERING = false;
|
||||||
|
|
||||||
// Физические коэффициенты volumetric rendering
|
|
||||||
// EXTINCTION: насколько сильно туман поглощает/рассеивает свет (0.1-2.0)
|
|
||||||
// Больше значение = туман сильнее затеняет далёкие объекты
|
|
||||||
const float EXTINCTION_COEFF = 1.0;
|
const float EXTINCTION_COEFF = 1.0;
|
||||||
|
|
||||||
// SCATTERING: насколько сильно туман сам светится от источников
|
|
||||||
// Обычно равен EXTINCTION (консервативная среда), но можно варьировать
|
|
||||||
const float SCATTERING_COEFF = 1.0;
|
const float SCATTERING_COEFF = 1.0;
|
||||||
|
|
||||||
// Ambient — базовое освещение среды (воздух, микрочастицы).
|
|
||||||
// Не зависит от времени суток и от skyLight/blockLight.
|
|
||||||
// Даёт минимальную видимость тумана даже в полной темноте.
|
|
||||||
const float AMBIENT_INTENSITY = 0.10;
|
const float AMBIENT_INTENSITY = 0.10;
|
||||||
|
|
||||||
// Порог transmittance для early termination (оптимизация)
|
|
||||||
// Если transmittance упал ниже этого значения, дальнейшие шаги ничего не внесут
|
|
||||||
const float MIN_TRANSMITTANCE = 0.01;
|
const float MIN_TRANSMITTANCE = 0.01;
|
||||||
|
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
@@ -145,8 +131,6 @@ float mapParameterToDistance(float t)
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec4 sceneColor = texture(DiffuseSampler, texCoord);
|
|
||||||
|
|
||||||
vec3 worldPos = reconstructWorldPosition(texCoord);
|
vec3 worldPos = reconstructWorldPosition(texCoord);
|
||||||
vec3 rayDir = normalize(worldPos - CameraPosition);
|
vec3 rayDir = normalize(worldPos - CameraPosition);
|
||||||
|
|
||||||
@@ -156,14 +140,10 @@ void main()
|
|||||||
vec3 samplePos = CameraPosition;
|
vec3 samplePos = CameraPosition;
|
||||||
float currentDistance = 0.0;
|
float currentDistance = 0.0;
|
||||||
|
|
||||||
// Transmittance: сколько света от сцены дошло до текущего шага
|
|
||||||
// Начинается с 1.0 (всё доходит) и экспоненциально падает
|
|
||||||
float transmittance = 1.0;
|
float transmittance = 1.0;
|
||||||
|
|
||||||
// Накопленный in-scattered свет (взвешенный по transmittance)
|
|
||||||
float skyScattered = 0.0;
|
float skyScattered = 0.0;
|
||||||
float blockScattered = 0.0;
|
float blockScattered = 0.0;
|
||||||
|
|
||||||
float ambientScattered = 0.0;
|
float ambientScattered = 0.0;
|
||||||
|
|
||||||
float jitter = 0.0;
|
float jitter = 0.0;
|
||||||
@@ -192,36 +172,25 @@ void main()
|
|||||||
|
|
||||||
float d = density(samplePos);
|
float d = density(samplePos);
|
||||||
|
|
||||||
// Оптическая толщина этого шага
|
|
||||||
float opticalDepth = d * stepSize * EXTINCTION_COEFF;
|
float opticalDepth = d * stepSize * EXTINCTION_COEFF;
|
||||||
|
|
||||||
if (d > 0.0) {
|
if (d > 0.0) {
|
||||||
// Получаем освещение в текущей точке
|
|
||||||
vec2 lightValues = light(samplePos);
|
vec2 lightValues = light(samplePos);
|
||||||
float totalLightAtPoint = lightValues.x + lightValues.y;
|
float totalLightAtPoint = lightValues.x + lightValues.y;
|
||||||
|
|
||||||
// Базовая формула in-scattering для каждого источника
|
|
||||||
float baseScattering = d * stepSize * SCATTERING_COEFF;
|
float baseScattering = d * stepSize * SCATTERING_COEFF;
|
||||||
|
|
||||||
// In-scattering: свет, рассеянный в камерy из этого шага.
|
|
||||||
// Умножается на transmittance до этого шага (дальний туман затенён ближним).
|
|
||||||
// Умножается на плотность (больше частиц = больше рассеяния).
|
|
||||||
float stepScattering = totalLightAtPoint * d * stepSize * SCATTERING_COEFF;
|
float stepScattering = totalLightAtPoint * d * stepSize * SCATTERING_COEFF;
|
||||||
|
|
||||||
// Вклад ослабляется текущим transmittance
|
|
||||||
skyScattered += lightValues.x * baseScattering * 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;
|
ambientScattered += AMBIENT_INTENSITY * baseScattering * transmittance;
|
||||||
|
|
||||||
// Обновляем transmittance: Beer-Lambert law
|
|
||||||
transmittance *= exp(-opticalDepth);
|
transmittance *= exp(-opticalDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentDistance = nextDistance;
|
currentDistance = nextDistance;
|
||||||
|
|
||||||
// Early termination: если transmittance упал почти до нуля,
|
|
||||||
// дальние шаги ничего не внесут в итоговый цвет
|
|
||||||
if (transmittance < MIN_TRANSMITTANCE) {
|
if (transmittance < MIN_TRANSMITTANCE) {
|
||||||
transmittance = 0.0;
|
transmittance = 0.0;
|
||||||
break;
|
break;
|
||||||
@@ -232,18 +201,10 @@ void main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Суммарное освещение, рассеянное в камеру
|
|
||||||
float totalScattered = skyScattered + blockScattered + ambientScattered;
|
float totalScattered = skyScattered + blockScattered + ambientScattered;
|
||||||
|
|
||||||
// Финальный цвет:
|
// Выводим: RGB = вложенный свет тумана, A = transmittance
|
||||||
// - sceneColor × transmittance: сцена, ослабленная туманом (Beer-Lambert)
|
vec3 fogColor = FogColor * totalScattered;
|
||||||
// - FogColor × totalScattered: свет, который рассеялся в тумане и попал в камеру
|
|
||||||
//
|
|
||||||
// Эта формула физически корректна:
|
|
||||||
// - Когда тумана нет (transmittance=1, scattered=0): result = sceneColor ✓
|
|
||||||
// - Когда туман очень плотный (transmittance=0): result = FogColor × scattered ✓
|
|
||||||
// - Фонарь в толще тумана: ближние слои дают scattered, дальние уже не видны
|
|
||||||
vec3 finalColor = sceneColor.rgb * transmittance + FogColor * totalScattered;
|
|
||||||
|
|
||||||
FragColor = vec4(finalColor, 1.0);
|
FragColor = vec4(fogColor, transmittance);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user