Add bloom.

This commit is contained in:
IntegratedQuantum 2022-10-18 18:56:02 +02:00
parent a04fc3369d
commit 7d70bca35c
13 changed files with 285 additions and 11 deletions

View File

@ -0,0 +1,13 @@
#version 430
layout(location=0) out vec4 fragColor;
in vec2 texCoords;
layout(binding = 3) uniform sampler2D color;
void main() {
vec3 bufferData = texture(color, texCoords).rgb;
float bloomFactor = max(max(bufferData.x, max(bufferData.y, bufferData.z))*4 - 1.0, 0);
fragColor = vec4(bufferData*bloomFactor, 1);
}

View File

@ -0,0 +1,10 @@
#version 430
layout (location=0) in vec2 inTexCoords;
out vec2 texCoords;
void main() {
texCoords = inTexCoords;
gl_Position = vec4(inTexCoords*2 - vec2(1, 1), 0, 1);
}

View File

@ -0,0 +1,19 @@
#version 430
layout(location=0) out vec4 fragColor;
in vec2 texCoords;
layout(binding = 3) uniform sampler2D color;
float weights[16] = float[] (0.14804608426116522, 0.14511457538105424, 0.13666376040001485, 0.12365848409943446, 0.10750352152877563, 0.08979448915479665, 0.07206176550016223, 0.055563338564704794, 0.041162333610640485, 0.029298127479707798, 0.02003585874555622, 0.01316449727103141, 0.008310531828522687, 0.005040592352516703, 0.002937396384358805, 0.001644643437557613);
void main() {
vec2 tex_offset = 1.0/textureSize(color, 0);
vec3 result = texture(color, texCoords).rgb * weights[0];
for(int i = 1; i < 16; i++) {
result += texture(color, texCoords + vec2(tex_offset.x * i, 0.0)).rgb * weights[i];
result += texture(color, texCoords - vec2(tex_offset.x * i, 0.0)).rgb * weights[i];
}
fragColor = vec4(result, 1);
}

View File

@ -0,0 +1,10 @@
#version 430
layout (location=0) in vec2 inTexCoords;
out vec2 texCoords;
void main() {
texCoords = inTexCoords;
gl_Position = vec4(inTexCoords*2 - vec2(1, 1), 0, 1);
}

View File

@ -0,0 +1,11 @@
#version 430
layout(location=0) out vec4 fragColor;
in vec2 texCoords;
layout(binding = 3) uniform sampler2D color;
void main() {
fragColor = vec4(texture(color, texCoords).rgb, 1);
}

View File

@ -0,0 +1,10 @@
#version 430
layout (location=0) in vec2 inTexCoords;
out vec2 texCoords;
void main() {
texCoords = inTexCoords;
gl_Position = vec4(inTexCoords*2 - vec2(1, 1), 0, 1);
}

View File

@ -0,0 +1,19 @@
#version 430
layout(location=0) out vec4 fragColor;
in vec2 texCoords;
layout(binding = 3) uniform sampler2D color;
float weights[16] = float[] (0.14804608426116522, 0.14511457538105424, 0.13666376040001485, 0.12365848409943446, 0.10750352152877563, 0.08979448915479665, 0.07206176550016223, 0.055563338564704794, 0.041162333610640485, 0.029298127479707798, 0.02003585874555622, 0.01316449727103141, 0.008310531828522687, 0.005040592352516703, 0.002937396384358805, 0.001644643437557613);
void main() {
vec2 tex_offset = 1.0/textureSize(color, 0);
vec3 result = texture(color, texCoords).rgb * weights[0];
for(int i = 1; i < 16; i++) {
result += texture(color, texCoords + vec2(0, tex_offset.y * i)).rgb * weights[i];
result += texture(color, texCoords - vec2(0, tex_offset.y * i)).rgb * weights[i];
}
fragColor = vec4(result, 1);
}

View File

@ -0,0 +1,10 @@
#version 430
layout(location=0) in vec2 inTexCoords;
out vec2 texCoords;
void main() {
texCoords = inTexCoords;
gl_Position = vec4(inTexCoords*2 - vec2(1, 1), 0, 1);
}

View File

@ -25,8 +25,8 @@ vec4 calcFog(vec3 pos, vec4 color, Fog fog) {
float distance = length(pos); float distance = length(pos);
float fogFactor = 1.0/exp((distance*fog.density)*(distance*fog.density)); float fogFactor = 1.0/exp((distance*fog.density)*(distance*fog.density));
fogFactor = clamp(fogFactor, 0.0, 1.0); fogFactor = clamp(fogFactor, 0.0, 1.0);
vec3 resultColor = mix(fog.color, color.xyz, fogFactor); vec4 resultColor = mix(vec4(fog.color, 1), color, fogFactor);
return vec4(resultColor.xyz, color.w + 1 - fogFactor); return resultColor;
} }
void main() { void main() {

View File

@ -32,11 +32,11 @@ uniform int time;
const float[6] outNormalVariations = float[6]( const float[6] outNormalVariations = float[6](
1.0, //vec3(0, 1, 0), 1.0, //vec3(0, 1, 0),
0.8, //vec3(0, -1, 0), 0.88, //vec3(0, -1, 0),
0.9, //vec3(1, 0, 0), 0.92, //vec3(1, 0, 0),
0.9, //vec3(-1, 0, 0), 0.92, //vec3(-1, 0, 0),
0.95, //vec3(0, 0, 1), 0.96, //vec3(0, 0, 1),
0.8 //vec3(0, 0, -1) 0.88 //vec3(0, 0, -1)
); );
const vec3[6] normals = vec3[6]( const vec3[6] normals = vec3[6](
vec3(0, 1, 0), vec3(0, 1, 0),

View File

@ -425,6 +425,70 @@ pub const SSBO = struct {
} }
}; };
pub const FrameBuffer = struct {
frameBuffer: c_uint,
texture: c_uint,
hasDepthBuffer: bool,
renderBuffer: c_uint,
pub fn init(self: *FrameBuffer, hasDepthBuffer: bool) void {
self.* = FrameBuffer{
.frameBuffer = undefined,
.texture = undefined,
.renderBuffer = undefined,
.hasDepthBuffer = hasDepthBuffer,
};
c.glGenFramebuffers(1, &self.frameBuffer);
if(hasDepthBuffer) {
c.glGenRenderbuffers(1, &self.renderBuffer);
}
c.glGenTextures(1, &self.texture);
}
pub fn deinit(self: *FrameBuffer) void {
c.glDeleteFramebuffers(1, &self.frameBuffer);
if(self.hasDepthBuffer) {
c.glDeleteRenderbuffers(1, &self.renderBuffer);
}
c.glDeleteTextures(1, &self.texture);
}
pub fn updateSize(self: *FrameBuffer, width: u31, height: u31, textureFilter: c_int, textureWrap: c_int) void {
c.glBindFramebuffer(c.GL_FRAMEBUFFER, self.frameBuffer);
if(self.hasDepthBuffer) {
c.glBindRenderbuffer(c.GL_RENDERBUFFER, self.renderBuffer);
c.glRenderbufferStorage(c.GL_RENDERBUFFER, c.GL_DEPTH24_STENCIL8, width, height);
c.glFramebufferRenderbuffer(c.GL_FRAMEBUFFER, c.GL_DEPTH_STENCIL_ATTACHMENT, c.GL_RENDERBUFFER, self.renderBuffer);
}
c.glBindTexture(c.GL_TEXTURE_2D, self.texture);
c.glTexImage2D(c.GL_TEXTURE_2D, 0, c.GL_RGBA8, width, height, 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, null);
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, textureFilter);
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, textureFilter);
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_S, textureWrap);
c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_WRAP_T, textureWrap);
c.glFramebufferTexture2D(c.GL_FRAMEBUFFER, c.GL_COLOR_ATTACHMENT0, c.GL_TEXTURE_2D, self.texture, 0);
}
pub fn validate(self: *FrameBuffer) bool {
c.glBindFramebuffer(c.GL_FRAMEBUFFER, self.frameBuffer);
defer c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0);
if(c.glCheckFramebufferStatus(c.GL_FRAMEBUFFER) != c.GL_FRAMEBUFFER_COMPLETE) {
std.log.err("Frame Buffer Object error: {}", .{c.glCheckFramebufferStatus(c.GL_FRAMEBUFFER)});
return false;
}
return true;
}
pub fn bind(self: *FrameBuffer) void {
c.glBindFramebuffer(c.GL_FRAMEBUFFER, self.frameBuffer);
}
pub fn unbind() void {
c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0);
}
};
pub const TextureArray = struct { pub const TextureArray = struct {
textureID: c_uint, textureID: c_uint,

View File

@ -47,12 +47,14 @@ pub fn init() !void {
deferredRenderPassShader = try Shader.create("assets/cubyz/shaders/deferred_render_pass.vs", "assets/cubyz/shaders/deferred_render_pass.fs"); deferredRenderPassShader = try Shader.create("assets/cubyz/shaders/deferred_render_pass.vs", "assets/cubyz/shaders/deferred_render_pass.fs");
deferredUniforms = deferredRenderPassShader.bulkGetUniformLocation(@TypeOf(deferredUniforms)); deferredUniforms = deferredRenderPassShader.bulkGetUniformLocation(@TypeOf(deferredUniforms));
buffers.init(); buffers.init();
try Bloom.init();
} }
pub fn deinit() void { pub fn deinit() void {
fogShader.delete(); fogShader.delete();
deferredRenderPassShader.delete(); deferredRenderPassShader.delete();
buffers.deinit(); buffers.deinit();
Bloom.deinit();
} }
const buffers = struct { const buffers = struct {
@ -321,9 +323,9 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
// glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// } // }
// } // }
// if(ClientSettings.BLOOM) { if(settings.bloom) {
// BloomRenderer.render(buffers, Window.getWidth(), Window.getHeight()); // TODO: Use true width/height Bloom.render(main.Window.width, main.Window.height);
// } }
buffers.unbind(); buffers.unbind();
buffers.bindTextures(); buffers.bindTextures();
deferredRenderPassShader.bind(); deferredRenderPassShader.bind();
@ -385,6 +387,110 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
// } // }
//} //}
const Bloom = struct {
var buffer1: graphics.FrameBuffer = undefined;
var buffer2: graphics.FrameBuffer = undefined;
var extractedBuffer: graphics.FrameBuffer = undefined;
var width: u31 = std.math.maxInt(u31);
var height: u31 = std.math.maxInt(u31);
var firstPassShader: graphics.Shader = undefined;
var secondPassShader: graphics.Shader = undefined;
var colorExtractShader: graphics.Shader = undefined;
var scaleShader: graphics.Shader = undefined;
pub fn init() !void {
buffer1.init(false);
buffer2.init(false);
extractedBuffer.init(false);
firstPassShader = try graphics.Shader.create("assets/cubyz/shaders/bloom/first_pass.vs", "assets/cubyz/shaders/bloom/first_pass.fs");
secondPassShader = try graphics.Shader.create("assets/cubyz/shaders/bloom/second_pass.vs", "assets/cubyz/shaders/bloom/second_pass.fs");
colorExtractShader = try graphics.Shader.create("assets/cubyz/shaders/bloom/color_extractor.vs", "assets/cubyz/shaders/bloom/color_extractor.fs");
scaleShader = try graphics.Shader.create("assets/cubyz/shaders/bloom/scale.vs", "assets/cubyz/shaders/bloom/scale.fs");
}
pub fn deinit() void {
buffer1.deinit();
buffer2.deinit();
extractedBuffer.deinit();
firstPassShader.delete();
secondPassShader.delete();
colorExtractShader.delete();
scaleShader.delete();
}
fn extractImageData() void {
colorExtractShader.bind();
buffers.bindTextures();
extractedBuffer.bind();
c.glBindVertexArray(graphics.Draw.rectVAO);
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
}
fn downscale() void {
scaleShader.bind();
c.glActiveTexture(c.GL_TEXTURE3);
c.glBindTexture(c.GL_TEXTURE_2D, extractedBuffer.texture);
buffer1.bind();
c.glBindVertexArray(graphics.Draw.rectVAO);
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
}
fn firstPass() void {
firstPassShader.bind();
c.glActiveTexture(c.GL_TEXTURE3);
c.glBindTexture(c.GL_TEXTURE_2D, buffer1.texture);
buffer2.bind();
c.glBindVertexArray(graphics.Draw.rectVAO);
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
}
fn secondPass() void {
secondPassShader.bind();
c.glActiveTexture(c.GL_TEXTURE3);
c.glBindTexture(c.GL_TEXTURE_2D, buffer2.texture);
buffer1.bind();
c.glBindVertexArray(graphics.Draw.rectVAO);
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
}
fn upscale() void {
scaleShader.bind();
c.glActiveTexture(c.GL_TEXTURE3);
c.glBindTexture(c.GL_TEXTURE_2D, buffer1.texture);
buffers.bind();
c.glBindVertexArray(graphics.Draw.rectVAO);
c.glDrawArrays(c.GL_TRIANGLE_STRIP, 0, 4);
}
pub fn render(currentWidth: u31, currentHeight: u31) void {
if(width != currentWidth or height != currentHeight) {
width = currentWidth;
height = currentHeight;
buffer1.updateSize(width/2, height/2, c.GL_LINEAR, c.GL_CLAMP_TO_EDGE);
std.debug.assert(buffer1.validate());
buffer2.updateSize(width/2, height/2, c.GL_LINEAR, c.GL_CLAMP_TO_EDGE);
std.debug.assert(buffer2.validate());
extractedBuffer.updateSize(width, height, c.GL_LINEAR, c.GL_CLAMP_TO_EDGE);
std.debug.assert(extractedBuffer.validate());
}
c.glDisable(c.GL_DEPTH_TEST);
c.glDisable(c.GL_CULL_FACE);
extractImageData();
c.glViewport(0, 0, width/2, height/2);
downscale();
firstPass();
secondPass();
c.glViewport(0, 0, width, height);
c.glBlendFunc(c.GL_ONE, c.GL_ONE);
upscale();
c.glEnable(c.GL_DEPTH_TEST);
c.glEnable(c.GL_CULL_FACE);
c.glBlendFunc(c.GL_SRC_ALPHA, c.GL_ONE_MINUS_SRC_ALPHA);
}
};
pub const Frustum = struct { pub const Frustum = struct {
const Plane = struct { const Plane = struct {
pos: Vec3f, pos: Vec3f,

View File

@ -17,3 +17,5 @@ pub var mouseSensitivity: f32 = 1;
pub var renderDistance: i32 = 4; pub var renderDistance: i32 = 4;
pub var LODFactor: f32 = 2.0; pub var LODFactor: f32 = 2.0;
pub var bloom: bool = true;