Merge branch 'distant-horizons-core-ssao.improvements'

This commit is contained in:
James Seibel
2023-09-06 17:54:20 -05:00
12 changed files with 360 additions and 279 deletions
@@ -86,6 +86,18 @@ public interface IDhApiGraphicsConfig extends IDhApiConfigGroup
IDhApiConfigValue<Boolean> ambientOcclusion();
IDhApiConfigValue<Integer> ambientOcclusion_SampleCount();
IDhApiConfigValue<Double> ambientOcclusion_Radius();
IDhApiConfigValue<Double> ambientOcclusion_Strength();
IDhApiConfigValue<Double> ambientOcclusion_Bias();
IDhApiConfigValue<Double> ambientOcclusion_MinLight();
IDhApiConfigValue<Integer> ambientOcclusion_BlurRadius();
IDhApiConfigValue<ETransparency> transparency();
/** Defines what blocks won't be rendered as LODs. */
@@ -84,6 +84,30 @@ public class DhApiGraphicsConfig implements IDhApiGraphicsConfig
public IDhApiConfigValue<Boolean> ambientOcclusion()
{ return new DhApiConfigValue<Boolean, Boolean>(Config.Client.Advanced.Graphics.Quality.ssao); }
@Override
public IDhApiConfigValue<Integer> ambientOcclusion_SampleCount()
{ return new DhApiConfigValue<Integer, Integer>(Config.Client.Advanced.Graphics.Quality.ssaoSampleCount); }
@Override
public IDhApiConfigValue<Double> ambientOcclusion_Radius()
{ return new DhApiConfigValue<Double, Double>(Config.Client.Advanced.Graphics.Quality.ssaoRadius); }
@Override
public IDhApiConfigValue<Double> ambientOcclusion_Strength()
{ return new DhApiConfigValue<Double, Double>(Config.Client.Advanced.Graphics.Quality.ssaoStrength); }
@Override
public IDhApiConfigValue<Double> ambientOcclusion_Bias()
{ return new DhApiConfigValue<Double, Double>(Config.Client.Advanced.Graphics.Quality.ssaoBias); }
@Override
public IDhApiConfigValue<Double> ambientOcclusion_MinLight()
{ return new DhApiConfigValue<Double, Double>(Config.Client.Advanced.Graphics.Quality.ssaoMinLight); }
@Override
public IDhApiConfigValue<Integer> ambientOcclusion_BlurRadius()
{ return new DhApiConfigValue<Integer, Integer>(Config.Client.Advanced.Graphics.Quality.ssaoBlurRadius); }
@Override
public IDhApiConfigValue<ETransparency> transparency()
{ return new DhApiConfigValue<ETransparency, ETransparency>(Config.Client.Advanced.Graphics.Quality.transparency); }
@@ -179,6 +179,36 @@ public class Config
.comment("Enable Screen Space Ambient Occlusion")
.build();
public static ConfigEntry<Integer> ssaoSampleCount = new ConfigEntry.Builder<Integer>()
.set(6)
.comment("Number of samples to use for Screen Space Ambient Occlusion")
.build();
public static ConfigEntry<Double> ssaoRadius = new ConfigEntry.Builder<Double>()
.set(4.0)
.comment("Radius of Screen Space Ambient Occlusion effect in blocks")
.build();
public static ConfigEntry<Double> ssaoStrength = new ConfigEntry.Builder<Double>()
.set(0.2)
.comment("Strength of Screen Space Ambient Occlusion effect")
.build();
public static ConfigEntry<Double> ssaoBias = new ConfigEntry.Builder<Double>()
.set(0.02)
.comment("Bias of Screen Space Ambient Occlusion effect")
.build();
public static ConfigEntry<Double> ssaoMinLight = new ConfigEntry.Builder<Double>()
.set(0.25)
.comment("Minimum brightness of Screen Space Ambient Occlusion effect")
.build();
public static ConfigEntry<Integer> ssaoBlurRadius = new ConfigEntry.Builder<Integer>()
.set(2)
.comment("Radius in pixels of Screen Space Ambient Occlusion blurring")
.build();
public static ConfigEntry<EHorizontalQuality> horizontalQuality = new ConfigEntry.Builder<EHorizontalQuality>()
.set(EHorizontalQuality.MEDIUM)
.comment(""
@@ -85,7 +85,7 @@ public class RenderQualityPresetConfigEventHandler extends AbstractPresetConfigE
this.put(EQualityPreset.HIGH, true);
this.put(EQualityPreset.EXTREME, true);
}});
//==============//
@@ -20,6 +20,7 @@
package com.seibel.distanthorizons.core.render.renderer.shaders;
import com.seibel.distanthorizons.api.enums.config.EGpuUploadMethod;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.render.glObject.GLState;
import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer;
@@ -41,7 +42,6 @@ public class SSAORenderer
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final int MAX_KERNEL_SIZE = 128;
private static final float[] box_vertices = {
-1, -1,
1, -1,
@@ -52,15 +52,13 @@ public class SSAORenderer
};
private ShaderProgram ssaoShader;
private ShaderProgram applyShader;
private GLVertexBuffer boxBuffer;
private VertexAttribute va;
private boolean init = false;
private float[] kernel = new float[MAX_KERNEL_SIZE * 3];
private int width = -1;
private int height = -1;
private int ssaoFramebuffer = -1;
@@ -73,10 +71,11 @@ public class SSAORenderer
{
public int gProjUniform;
public int gInvProjUniform;
public int gSampleRadUniform;
public int gFactorUniform;
public int gPowerUniform;
public int gKernelUniform;
public int gSampleCountUniform;
public int gRadiusUniform;
public int gStrengthUniform;
public int gMinLightUniform;
public int gBiasUniform;
public int gDepthMapUniform;
}
@@ -86,10 +85,13 @@ public class SSAORenderer
{
public int gSSAOMapUniform;
public int gDepthMapUniform;
public int gViewSizeUniform;
public int gBlurRadiusUniform;
public int gNearUniform;
public int gFarUniform;
}
//=============//
// constructor //
//=============//
@@ -98,43 +100,39 @@ public class SSAORenderer
public void init()
{
if (this.init)
{
return;
}
if (this.init) return;
this.init = true;
this.va = VertexAttribute.create();
this.va.bind();
// Pos
this.va.setVertexAttribute(0, 0, VertexAttribute.VertexPointer.addVec2Pointer(false));
this.va.completeAndCheck(Float.BYTES * 2);
this.ssaoShader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/ao.frag",
"fragColor", new String[]{"vPosition"});
this.applyShader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/apply-frag.frag",
this.applyShader = new ShaderProgram("shaders/normal.vert", "shaders/ssao/apply.frag",
"fragColor", new String[]{"vPosition"});
// SSAO uniform setup
this.ssaoShaderUniforms.gProjUniform = this.ssaoShader.getUniformLocation("gProj");
this.ssaoShaderUniforms.gInvProjUniform = this.ssaoShader.getUniformLocation("gInvProj");
this.ssaoShaderUniforms.gSampleRadUniform = this.ssaoShader.getUniformLocation("gSampleRad");
this.ssaoShaderUniforms.gFactorUniform = this.ssaoShader.getUniformLocation("gFactor");
this.ssaoShaderUniforms.gPowerUniform = this.ssaoShader.getUniformLocation("gPower");
this.ssaoShaderUniforms.gKernelUniform = this.ssaoShader.getUniformLocation("gKernel");
this.ssaoShaderUniforms.gSampleCountUniform = this.ssaoShader.getUniformLocation("gSampleCount");
this.ssaoShaderUniforms.gRadiusUniform = this.ssaoShader.getUniformLocation("gRadius");
this.ssaoShaderUniforms.gStrengthUniform = this.ssaoShader.getUniformLocation("gStrength");
this.ssaoShaderUniforms.gMinLightUniform = this.ssaoShader.getUniformLocation("gMinLight");
this.ssaoShaderUniforms.gBiasUniform = this.ssaoShader.getUniformLocation("gBias");
this.ssaoShaderUniforms.gDepthMapUniform = this.ssaoShader.getUniformLocation("gDepthMap");
// Apply uniform setup
this.applyShaderUniforms.gSSAOMapUniform = this.applyShader.getUniformLocation("gSSAOMap");
this.applyShaderUniforms.gDepthMapUniform = this.applyShader.getUniformLocation("gDepthMap");
this.applyShaderUniforms.gViewSizeUniform = tryGetUniformLocation(this.applyShader, "gViewSize");
this.applyShaderUniforms.gBlurRadiusUniform = tryGetUniformLocation(this.applyShader, "gBlurRadius");
this.applyShaderUniforms.gNearUniform = tryGetUniformLocation(this.applyShader, "gNear");
this.applyShaderUniforms.gFarUniform = tryGetUniformLocation(this.applyShader, "gFar");
// Generate kernel
this.kernel = genKernel();
// Framebuffer
this.createBuffer();
}
@@ -158,53 +156,24 @@ public class SSAORenderer
this.ssaoTexture = GL32.glGenTextures();
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.ssaoTexture);
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RED, width, height, 0, GL32.GL_RED, GL32.GL_FLOAT, (ByteBuffer) null);
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_NEAREST);
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_NEAREST);
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_R16F, width, height, 0, GL32.GL_RED, GL32.GL_HALF_FLOAT, (ByteBuffer) null);
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR);
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.ssaoTexture, 0);
}
private void createBuffer()
{
ByteBuffer buffer = ByteBuffer.allocateDirect(box_vertices.length * Float.BYTES);
buffer.order(ByteOrder.nativeOrder());
buffer.asFloatBuffer().put(box_vertices);
buffer.rewind();
this.boxBuffer = new GLVertexBuffer(false);
this.boxBuffer.bind();
this.boxBuffer.uploadBuffer(buffer, box_vertices.length, EGpuUploadMethod.DATA, box_vertices.length * Float.BYTES);
}
private static float[] genKernel()
{
float[] kernel = new float[MAX_KERNEL_SIZE * 3];
for (int i = 0; i < MAX_KERNEL_SIZE; i++)
{
float sampleX = (float) (Math.random() * 2.0 - 1.0);
float sampleY = (float) (Math.random() * 2.0 - 1.0);
float sampleZ = (float) Math.random();
// Normalize
float magnitude = (float) Math.sqrt(Math.pow(sampleX, 2) + Math.pow(sampleY, 2) + Math.pow(sampleZ, 2));
sampleX /= magnitude;
sampleY /= magnitude;
sampleZ /= magnitude;
float scale = i / (float) MAX_KERNEL_SIZE;
float interpolatedScale = (float) (0.1 + (scale * scale) * (0.9));
sampleX *= interpolatedScale;
sampleY *= interpolatedScale;
sampleZ *= interpolatedScale;
kernel[i * 3] = sampleX;
kernel[i * 3 + 1] = sampleY;
kernel[i * 3 + 2] = sampleZ;
}
return kernel;
}
//========//
// render //
@@ -213,7 +182,9 @@ public class SSAORenderer
public void render(float partialTicks)
{
GLState state = new GLState();
this.init();
int width = MC_RENDER.getTargetFrameBufferViewportWidth();
int height = MC_RENDER.getTargetFrameBufferViewportHeight();
@@ -226,27 +197,36 @@ public class SSAORenderer
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.ssaoFramebuffer);
GL32.glViewport(0, 0, width, height);
GL32.glDisable(GL32.GL_DEPTH_TEST);
GL32.glDisable(GL32.GL_BLEND);
GL32.glDisable(GL32.GL_SCISSOR_TEST);
GL32.glDisable(GL32.GL_DEPTH_TEST);
GL32.glDisable(GL11.GL_BLEND);
float near = RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks);
float far = (float) ((RenderUtil.getFarClipPlaneDistanceInBlocks() + LodUtil.REGION_WIDTH) * Math.sqrt(2));
Mat4f perspective = Mat4f.perspective(
(float) MC_RENDER.getFov(partialTicks),
MC_RENDER.getTargetFrameBufferViewportWidth() / (float) MC_RENDER.getTargetFrameBufferViewportHeight(),
RenderUtil.getNearClipPlaneDistanceInBlocks(partialTicks),
(float) ((RenderUtil.getFarClipPlaneDistanceInBlocks() + LodUtil.REGION_WIDTH) * Math.sqrt(2)));
width / (float) height,
near, far);
Mat4f invertedPerspective = new Mat4f(perspective);
invertedPerspective.invert();
int sampleCount = Config.Client.Advanced.Graphics.Quality.ssaoSampleCount.get();
int blurRadius = Config.Client.Advanced.Graphics.Quality.ssaoBlurRadius.get();
float radius = Config.Client.Advanced.Graphics.Quality.ssaoRadius.get().floatValue();
float strength = Config.Client.Advanced.Graphics.Quality.ssaoStrength.get().floatValue();
float minLight = Config.Client.Advanced.Graphics.Quality.ssaoMinLight.get().floatValue();
float bias = Config.Client.Advanced.Graphics.Quality.ssaoBias.get().floatValue();
this.ssaoShader.bind();
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gProjUniform, perspective);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gInvProjUniform, invertedPerspective);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gSampleRadUniform, 3.0f);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gFactorUniform, 0.8f);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gPowerUniform, 1.0f);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gSampleCountUniform, sampleCount);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gRadiusUniform, radius);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gStrengthUniform, strength);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gMinLightUniform, minLight);
this.ssaoShader.setUniform(this.ssaoShaderUniforms.gBiasUniform, bias);
this.va.bind();
this.va.bindBufferToAllBindingPoint(this.boxBuffer.getId());
@@ -254,35 +234,52 @@ public class SSAORenderer
GL32.glActiveTexture(GL32.GL_TEXTURE0);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId());
GL32.glUniform3fv(this.ssaoShaderUniforms.gKernelUniform, this.kernel);
GL32.glUniform1i(this.ssaoShaderUniforms.gDepthMapUniform, 0);
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6);
this.applyShader.bind();
GL32.glEnable(GL11.GL_BLEND);
GL32.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, MC_RENDER.getTargetFrameBuffer());
GL32.glEnable(GL11.GL_BLEND);
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
GL32.glBlendFuncSeparate(GL32.GL_ZERO, GL32.GL_SRC_ALPHA, GL32.GL_ZERO, GL32.GL_ONE);
GL32.glActiveTexture(GL32.GL_TEXTURE0);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.ssaoTexture);
GL32.glUniform1i(this.applyShaderUniforms.gSSAOMapUniform, 0);
GL32.glActiveTexture(GL32.GL_TEXTURE1);
GL32.glBindTexture(GL32.GL_TEXTURE_2D, MC_RENDER.getDepthTextureId());
GL32.glUniform1i(this.applyShaderUniforms.gDepthMapUniform, 1);
GL32.glUniform1i(this.applyShaderUniforms.gBlurRadiusUniform, blurRadius);
if (this.applyShaderUniforms.gViewSizeUniform >= 0)
GL32.glUniform2f(this.applyShaderUniforms.gViewSizeUniform, width, height);
if (this.applyShaderUniforms.gNearUniform >= 0)
GL32.glUniform1f(this.applyShaderUniforms.gNearUniform, near);
if (this.applyShaderUniforms.gFarUniform >= 0)
GL32.glUniform1f(this.applyShaderUniforms.gFarUniform, far);
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6);
state.restore();
}
private int tryGetUniformLocation(ShaderProgram shader, String uniformName)
{
try {
return shader.getUniformLocation(uniformName);
}
catch (RuntimeException error) {
return -1;
}
}
public void free()
{
this.ssaoShader.free();
this.applyShader.free();
}
}
@@ -98,6 +98,18 @@
"SSAO",
"distanthorizons.config.client.advanced.graphics.quality.ssao.@tooltip":
"Screen Space Ambient Occlusion adds depth to the lighting of blocks.",
"distanthorizons.config.client.advanced.graphics.quality.ssaoSampleCount":
"SSAO Sample Count",
"distanthorizons.config.client.advanced.graphics.quality.ssaoRadius":
"SSAO Radius",
"distanthorizons.config.client.advanced.graphics.quality.ssaoStrength":
"SSAO Strength",
"distanthorizons.config.client.advanced.graphics.quality.ssaoMinLight":
"SSAO Min Light",
"distanthorizons.config.client.advanced.graphics.quality.ssaoBias":
"SSAO Bias",
"distanthorizons.config.client.advanced.graphics.quality.ssaoBlurRadius":
"SSAO Blur Radius",
"distanthorizons.config.client.advanced.graphics.quality.horizontalQuality":
"Horizontal Quality",
"distanthorizons.config.client.advanced.graphics.quality.horizontalQuality.@tooltip":
@@ -2,7 +2,7 @@
in vec4 vertexColor;
in vec3 vertexWorldPos;
in float vertexYPos;
//in float vertexYPos;
in vec4 vPos;
out vec4 fragColor;
@@ -15,50 +15,19 @@ uniform float noiseIntensity;
uniform int noiseDropoff;
// method definitions
float fade(float value, float start, float end) {
return (clamp(value, start, end) - start) / (end - start);
}
// The random functions for diffrent dimentions
float rand(float co) { return fract(sin(co*(91.3458)) * 47453.5453); }
float rand(vec2 co){ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); }
float rand(vec3 co){ return rand(co.xy+rand(co.z)); }
float rand(vec2 co) { return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); }
float rand(vec3 co) { return rand(co.xy + rand(co.z)); }
// Puts steps in a float
// EG. setting stepSize to 4 then this would be the result of this function
// In: 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, ..., 1.1, 1.2, 1.3
// Out: 0.0, 0.0, 0.0, 0.25, 0.25, 0.5, 0.5, ..., 1.0, 1.0, 1.25
float quantize(float val, int stepSize) {
return floor(val*stepSize)/stepSize;
vec3 quantize(vec3 val, int stepSize) {
return floor(val * stepSize) / stepSize;
}
// The modulus function dosnt exist in GLSL so I made my own
// To speed up the mod function, this only accepts full numbers for y
float mod(float x, int y) {
return x - y * floor(x/y);
}
// Some HSV functions I stole somewhere online
vec3 RGB2HSV(vec3 c) {
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
vec3 HSV2RGB(vec3 c) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
/**
* Fragment Shader
@@ -71,66 +40,31 @@ void main()
{
fragColor = vertexColor;
// TODO: Move into its own function instead of in an if statement
if (noiseEnabled) {
vec3 vertexNormal = normalize(cross(dFdx(vPos.xyz), dFdy(vPos.xyz)));
vec3 vertexNormal = normalize(cross(dFdy(vPos.xyz), dFdx(vPos.xyz)));
// This bit of code is required to fix the vertex position problem cus of floats in the verted world position varuable
vec3 fixedVPos = vPos.xyz - vertexNormal * 0.001;
vec3 fixedVPos = vPos.xyz + vertexNormal * 0.001;
float noiseAmplification = noiseIntensity * 0.01;
noiseAmplification = (-1.0 * pow(2.0*((fragColor.x + fragColor.y + fragColor.z) / 3.0) - 1.0, 2.0) + 1.0) * noiseAmplification; // Lessen the effect on depending on how dark the object is, equasion for this is -(2x-1)^{2}+1
noiseAmplification *= fragColor.w; // The effect would lessen on transparent objects
float lum = (fragColor.r + fragColor.g + fragColor.b) / 3.0;
noiseAmplification = (1.0 - pow(lum * 2.0 - 1.0, 2.0)) * noiseAmplification; // Lessen the effect on depending on how dark the object is, equasion for this is -(2x-1)^{2}+1
noiseAmplification *= fragColor.a; // The effect would lessen on transparent objects
// Random value for each position
float randomValue = rand(vec3(
quantize(fixedVPos.x, noiseSteps),
quantize(fixedVPos.y, noiseSteps),
quantize(fixedVPos.z, noiseSteps)
))
* 2.0 * noiseAmplification - noiseAmplification;
float randomValue = rand(quantize(fixedVPos, noiseSteps))
* 2.0 * noiseAmplification - noiseAmplification;
// Modifies the color
// A value of 0 on the randomValue will result in the original color, while a value of 1 will result in a fully bright color
vec3 newCol = fragColor.rgb + (1.0 - fragColor.rgb) * randomValue;
newCol = clamp(newCol, 0.0, 1.0);
if (noiseDropoff != 0) {
float distF = min(length(vertexWorldPos) / noiseDropoff, 1.0);
newCol = mix(newCol, fragColor.rgb, distF); // The further away it gets, the less noise gets applied
}
// Clamps it and turns it back into a vec4
if (noiseDropoff == 0)
fragColor = vec4(clamp(newCol.rgb, 0.0, 1.0), fragColor.w);
else
fragColor = mix(
vec4(clamp(newCol.rgb, 0.0, 1.0), fragColor.w), fragColor,
min(length(vertexWorldPos) / noiseDropoff, 1.0) // The further away it gets, the less noise gets applied
);
// For testing
// if (fragColor.r != 69420.) {
// fragColor = vec4(
// mod(fixedVPos.x, 1),
// mod(fixedVPos.y, 1),
// mod(fixedVPos.z, 1),
// fragColor.w);
// }
fragColor.rgb = newCol;
}
}
// Are these still needed?
float linearFog(float x, float fogStart, float fogLength, float fogMin, float fogRange) {
x = clamp((x-fogStart)/fogLength, 0.0, 1.0);
return fogMin + fogRange * x;
}
float exponentialFog(float x, float fogStart, float fogLength,
float fogMin, float fogRange, float fogDensity) {
x = max((x-fogStart)/fogLength, 0.0) * fogDensity;
return fogMin + fogRange - fogRange/exp(x);
}
float exponentialSquaredFog(float x, float fogStart, float fogLength,
float fogMin, float fogRange, float fogDensity) {
x = max((x-fogStart)/fogLength, 0.0) * fogDensity;
return fogMin + fogRange - fogRange/exp(x*x);
}
+23 -38
View File
@@ -42,23 +42,14 @@ float mixFogThickness(float near, float far, float height);
// =========================================================
// Puts steps in a float
// EG. setting stepSize to 4 then this would be the result of this function
// In: 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, ..., 1.1, 1.2, 1.3
// Out: 0.0, 0.0, 0.0, 0.25, 0.25, 0.5, 0.5, ..., 1.0, 1.0, 1.25
float quantize(float val, int stepSize) {
return floor(val*stepSize)/stepSize;
const vec3 MAGIC = vec3(0.06711056, 0.00583715, 52.9829189);
float InterleavedGradientNoise(const in vec2 pixel) {
float x = dot(pixel, MAGIC.xy);
return fract(MAGIC.z * fract(x));
}
// The modulus function dosnt exist in GLSL so I made my own
// To speed up the mod function, this only accepts full numbers for y
float mod(float x, int y) {
return x - y * floor(x/y);
}
vec3 calcViewPosition(float fragmentDepth)
{
vec3 calcViewPosition(float fragmentDepth) {
vec4 ndc = vec4(TexCoord.xy, fragmentDepth, 1.0);
ndc.xyz = ndc.xyz * 2.0 - 1.0;
@@ -76,13 +67,12 @@ void main()
{
float vertexYPos = 100.0f;
float fragmentDepth = texture(gDepthMap, TexCoord).r;
fragColor = vec4(fogColor.rgb, 0.0);
// a fragment depth of "1" means the fragment wasn't drawn to,
// we only want to apply Fog to LODs, not to the sky outside the LODs
if (fragmentDepth < 1)
{
if (fullFogMode == 0)
{
if (fragmentDepth < 1.0) {
if (fullFogMode == 0) {
// render fog based on distance from the camera
vec3 vertexWorldPos = calcViewPosition(fragmentDepth);
@@ -94,17 +84,16 @@ void main()
float farFogThickness = getFarFogThickness(farDist);
float heightFogThickness = getHeightFogThickness(heightDist);
float mixedFogThickness = mixFogThickness(nearFogThickness, farFogThickness, heightFogThickness);
mixedFogThickness = clamp(mixedFogThickness, 0.0, 1.0);
fragColor.a = clamp(mixedFogThickness, 0.0, 1.0);
fragColor = vec4(fogColor.rgb, mixedFogThickness);
float dither = InterleavedGradientNoise(gl_FragCoord.xy) - 0.5;
fragColor.a += dither / 255.0;
}
else if (fullFogMode == 1)
{
else if (fullFogMode == 1) {
// render everything with the fog color
fragColor = vec4(fogColor.rgb, 1.0);
fragColor.a = 1.0;
}
else
{
else {
// test code.
// this can be fired by manually changing the fullFogMode to a (normally)
@@ -112,19 +101,13 @@ void main()
// a uniform we don't have to worry about GLSL optimizing away different
// options when testing, causing a bunch of headaches if we just want to render the screen red.
float depthValue = texture(gDepthMap, TexCoord).r;
fragColor = vec4(vec3(depthValue), 1.0); // Convert depth value to grayscale color
float depthValue = textureLod(gDepthMap, TexCoord, 0).r;
fragColor.rgb = vec3(depthValue); // Convert depth value to grayscale color
fragColor.a = 1.0;
}
}
else
{
// every pixel needs to be set to something, otherwise the pixel may be undefined by some drivers (specifically Intel)
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
}
}
// Are these still needed?
float linearFog(float x, float fogStart, float fogLength, float fogMin, float fogRange) {
x = clamp((x-fogStart)/fogLength, 0.0, 1.0);
@@ -132,13 +115,15 @@ float linearFog(float x, float fogStart, float fogLength, float fogMin, float fo
}
float exponentialFog(float x, float fogStart, float fogLength,
float fogMin, float fogRange, float fogDensity) {
float fogMin, float fogRange, float fogDensity)
{
x = max((x-fogStart)/fogLength, 0.0) * fogDensity;
return fogMin + fogRange - fogRange/exp(x);
}
float exponentialSquaredFog(float x, float fogStart, float fogLength,
float fogMin, float fogRange, float fogDensity) {
float fogMin, float fogRange, float fogDensity)
{
x = max((x-fogStart)/fogLength, 0.0) * fogDensity;
return fogMin + fogRange - fogRange/exp(x*x);
}
}
@@ -30,14 +30,6 @@ vec3 quantize(vec3 val, int stepSize) {
return floor(val*stepSize)/stepSize;
}
// The modulus function dosnt exist in GLSL so I made my own
// To speed up the mod function, this only accepts full numbers for y
float mod(float x, int y) {
return x - y * floor(x/y);
}
/**
* Fragment shader for adding noise to lods.
+91 -46
View File
@@ -1,65 +1,110 @@
#version 150 core
#extension GL_ARB_derivative_control : enable
#define SAMPLE_MAX 64
#define saturate(x) (clamp((x), 0.0, 1.0))
in vec2 TexCoord;
out vec4 fragColor;
uniform sampler2D gDepthMap;
uniform float gSampleRad;
uniform float gFactor;
uniform float gPower;
uniform mat4 gProj;
uniform int gSampleCount;
uniform float gRadius;
uniform float gStrength;
uniform float gMinLight;
uniform float gBias;
uniform mat4 gInvProj;
uniform mat4 gProj;
const int MAX_KERNEL_SIZE = 128;
const float INV_MAX_KERNEL_SIZE_F = 1.0 / float(MAX_KERNEL_SIZE);
const vec2 HALF_2 = vec2(0.5);
uniform vec3 gKernel[MAX_KERNEL_SIZE];
const float EPSILON = 1.e-6;
const float GOLDEN_ANGLE = 2.39996323;
const vec3 MAGIC = vec3(0.06711056, 0.00583715, 52.9829189);
const float PI = 3.1415926538;
const float TAU = PI * 2.0;
vec3 calcViewPosition(vec2 coords) {
float fragmentDepth = texture(gDepthMap, coords).r;
vec4 ndc = vec4(
coords.x * 2.0 - 1.0,
coords.y * 2.0 - 1.0,
fragmentDepth * 2.0 - 1.0,
1.0
);
vec4 vs_pos = gInvProj * ndc;
vs_pos.xyz = vs_pos.xyz / vs_pos.w;
return vs_pos.xyz;
vec3 unproject(vec4 pos) {
return pos.xyz / pos.w;
}
void main()
{
vec3 viewPos = calcViewPosition(TexCoord);
vec3 viewNormal = normalize(cross(dFdy(viewPos.xyz), dFdx(viewPos.xyz)) * -1.0);
float InterleavedGradientNoise(const in vec2 pixel) {
float x = dot(pixel, MAGIC.xy);
return fract(MAGIC.z * fract(x));
}
vec3 randomVec = vec3(0.0, -1.0, 0.0);
vec3 calcViewPosition(const in vec3 clipPos) {
vec4 viewPos = gInvProj * vec4(clipPos * 2.0 - 1.0, 1.0);
return viewPos.xyz / viewPos.w;
}
vec3 tangent = normalize(randomVec - viewNormal * dot(randomVec, viewNormal));
vec3 bitangent = cross(viewNormal, tangent);
mat3 TBN = mat3(tangent, bitangent, viewNormal);
float occlusion_factor = 0.0;
for (int i = 0; i < MAX_KERNEL_SIZE; i++)
{
vec3 samplePos = vec3(0.0) + (TBN * gKernel[i]);
samplePos = viewPos + samplePos * gSampleRad;
vec4 offset = gProj * vec4(samplePos + viewPos, 1.0);
offset.xy /= offset.w;
offset.xy = offset.xy * HALF_2 + HALF_2;
float geometryDepth = calcViewPosition(offset.xy).z;
float rangeCheck = smoothstep(0.0, 1.0, gSampleRad / abs(viewPos.z - geometryDepth));
// the number added to the samplePos.z can be used to reduce noise in the SSAO application at the cost of reducing the overall affect
occlusion_factor += float(geometryDepth >= samplePos.z + 0.1) * rangeCheck;
float GetSpiralOcclusion(const in vec2 uv, const in vec3 viewPos, const in vec3 viewNormal) {
float dither = InterleavedGradientNoise(gl_FragCoord.xy);
float rotatePhase = dither * TAU;
float rStep = gRadius / gSampleCount;
vec2 offset;
float ao = 0.0;
int sampleCount = 0;
float radius = rStep;
for (int i = 0; i < clamp(gSampleCount, 1, SAMPLE_MAX); i++) {
vec2 offset = vec2(
sin(rotatePhase),
cos(rotatePhase)
) * radius;
radius += rStep;
rotatePhase += GOLDEN_ANGLE;
vec3 sampleViewPos = viewPos + vec3(offset, -0.1);
vec3 sampleClipPos = unproject(gProj * vec4(sampleViewPos, 1.0)) * 0.5 + 0.5;
sampleClipPos = saturate(sampleClipPos);
float sampleClipDepth = textureLod(gDepthMap, sampleClipPos.xy, 0.0).r;
if (sampleClipDepth >= 1.0 - EPSILON) continue;
sampleClipPos.z = sampleClipDepth;
sampleViewPos = unproject(gInvProj * vec4(sampleClipPos * 2.0 - 1.0, 1.0));
vec3 diff = sampleViewPos - viewPos;
float sampleDist = length(diff);
vec3 sampleNormal = diff / sampleDist;
float sampleNoLm = max(dot(viewNormal, sampleNormal) - gBias, 0.0);
float aoF = 1.0 - saturate(sampleDist / gRadius);
ao += sampleNoLm * aoF;
sampleCount++;
}
float visibility_factor = 1.0 - (occlusion_factor / MAX_KERNEL_SIZE);
fragColor = vec4(clamp(1.0 - ((1.0 - pow(visibility_factor, gFactor)) * gPower), 0.1, 1.0));
}
ao /= max(sampleCount, 1);
ao = smoothstep(0.0, gStrength, ao);
return ao * (1.0 - gMinLight);
}
void main() {
float fragmentDepth = textureLod(gDepthMap, TexCoord, 0).r;
float occlusion = 0.0;
// Do not apply to sky
if (fragmentDepth < 1.0) {
vec3 viewPos = calcViewPosition(vec3(TexCoord, fragmentDepth));
#ifdef GL_ARB_derivative_control
// Get higher precision derivatives when available
vec3 viewNormal = cross(dFdxFine(viewPos.xyz), dFdyFine(viewPos.xyz));
#else
vec3 viewNormal = cross(dFdx(viewPos.xyz), dFdy(viewPos.xyz));
#endif
viewNormal = normalize(viewNormal);
occlusion = GetSpiralOcclusion(TexCoord, viewPos, viewNormal);
}
fragColor = vec4(vec3(1.0 - occlusion), 1.0);
}
@@ -1,25 +0,0 @@
#version 150 core
in vec2 TexCoord;
in vec2 ViewRay;
out vec4 fragColor;
uniform sampler2D gSSAOMap;
uniform sampler2D gDepthMap;
void main()
{
float fragmentDepth = texture(gDepthMap, TexCoord).r;
// a fragment depth of "1" means the fragment wasn't drawn to,
// we only want to apply SSAO to LODs, not to the sky outside the LODs
if (fragmentDepth < 1)
{
fragColor = vec4(0.0, 0.0, 0.0, 1-texture(gSSAOMap, TexCoord).r);
}
else
{
// every pixel needs to be set to something, otherwise the pixel may be undefined by some drivers (specifically Intel)
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
}
}
@@ -0,0 +1,75 @@
#version 150 core
in vec2 TexCoord;
out vec4 fragColor;
uniform sampler2D gSSAOMap;
uniform sampler2D gDepthMap;
uniform vec2 gViewSize;
uniform int gBlurRadius;
uniform float gNear;
uniform float gFar;
float linearizeDepth(const in float depth) {
return (gNear * gFar) / (depth * (gNear - gFar) + gFar);
}
float Gaussian(const in float sigma, const in float x) {
return exp(-(x*x) / (2.0 * (sigma*sigma)));
}
float BilateralGaussianBlur(const in vec2 texcoord, const in float linearDepth, const in float g_sigmaV) {
float g_sigmaX = 1.6;
float g_sigmaY = 1.6;
int radius = clamp(gBlurRadius, 1, 3);
vec2 pixelSize = 1.0 / gViewSize;
float accum = 0.0;
float total = 0.0;
for (int iy = -radius; iy <= radius; iy++) {
float fy = Gaussian(g_sigmaY, iy);
for (int ix = -radius; ix <= radius; ix++) {
float fx = Gaussian(g_sigmaX, ix);
vec2 sampleTex = texcoord + ivec2(ix, iy) * pixelSize;
float sampleValue = textureLod(gSSAOMap, sampleTex, 0).r;
float sampleDepth = textureLod(gDepthMap, sampleTex, 0).r;
float sampleLinearDepth = linearizeDepth(sampleDepth);
float depthDiff = abs(sampleLinearDepth - linearDepth);
float fv = Gaussian(g_sigmaV, depthDiff);
float weight = fx*fy*fv;
accum += weight * sampleValue;
total += weight;
}
}
if (total <= 1.e-4) return 1.0;
return accum / total;
}
void main()
{
fragColor = vec4(1.0);
float fragmentDepth = textureLod(gDepthMap, TexCoord, 0).r;
// a fragment depth of "1" means the fragment wasn't drawn to,
// we only want to apply SSAO to LODs, not to the sky outside the LODs
if (fragmentDepth < 1) {
if (gBlurRadius > 0) {
float fragmentDepthLinear = linearizeDepth(fragmentDepth);
fragColor.a = BilateralGaussianBlur(TexCoord, fragmentDepthLinear, 1.6);
}
else {
fragColor.a = texelFetch(gSSAOMap, ivec2(gl_FragCoord.xy), 0).r;
}
}
}