mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 19:28:49 -04:00
Add bloom.
This commit is contained in:
parent
a04fc3369d
commit
7d70bca35c
13
assets/cubyz/shaders/bloom/color_extractor.fs
Normal file
13
assets/cubyz/shaders/bloom/color_extractor.fs
Normal 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);
|
||||
}
|
10
assets/cubyz/shaders/bloom/color_extractor.vs
Normal file
10
assets/cubyz/shaders/bloom/color_extractor.vs
Normal 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);
|
||||
}
|
19
assets/cubyz/shaders/bloom/first_pass.fs
Normal file
19
assets/cubyz/shaders/bloom/first_pass.fs
Normal 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);
|
||||
}
|
10
assets/cubyz/shaders/bloom/first_pass.vs
Normal file
10
assets/cubyz/shaders/bloom/first_pass.vs
Normal 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);
|
||||
}
|
11
assets/cubyz/shaders/bloom/scale.fs
Normal file
11
assets/cubyz/shaders/bloom/scale.fs
Normal 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);
|
||||
}
|
10
assets/cubyz/shaders/bloom/scale.vs
Normal file
10
assets/cubyz/shaders/bloom/scale.vs
Normal 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);
|
||||
}
|
19
assets/cubyz/shaders/bloom/second_pass.fs
Normal file
19
assets/cubyz/shaders/bloom/second_pass.fs
Normal 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);
|
||||
}
|
10
assets/cubyz/shaders/bloom/second_pass.vs
Normal file
10
assets/cubyz/shaders/bloom/second_pass.vs
Normal 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);
|
||||
}
|
@ -25,8 +25,8 @@ vec4 calcFog(vec3 pos, vec4 color, Fog fog) {
|
||||
float distance = length(pos);
|
||||
float fogFactor = 1.0/exp((distance*fog.density)*(distance*fog.density));
|
||||
fogFactor = clamp(fogFactor, 0.0, 1.0);
|
||||
vec3 resultColor = mix(fog.color, color.xyz, fogFactor);
|
||||
return vec4(resultColor.xyz, color.w + 1 - fogFactor);
|
||||
vec4 resultColor = mix(vec4(fog.color, 1), color, fogFactor);
|
||||
return resultColor;
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
@ -32,11 +32,11 @@ uniform int time;
|
||||
|
||||
const float[6] outNormalVariations = float[6](
|
||||
1.0, //vec3(0, 1, 0),
|
||||
0.8, //vec3(0, -1, 0),
|
||||
0.9, //vec3(1, 0, 0),
|
||||
0.9, //vec3(-1, 0, 0),
|
||||
0.95, //vec3(0, 0, 1),
|
||||
0.8 //vec3(0, 0, -1)
|
||||
0.88, //vec3(0, -1, 0),
|
||||
0.92, //vec3(1, 0, 0),
|
||||
0.92, //vec3(-1, 0, 0),
|
||||
0.96, //vec3(0, 0, 1),
|
||||
0.88 //vec3(0, 0, -1)
|
||||
);
|
||||
const vec3[6] normals = vec3[6](
|
||||
vec3(0, 1, 0),
|
||||
|
@ -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 {
|
||||
textureID: c_uint,
|
||||
|
||||
|
112
src/renderer.zig
112
src/renderer.zig
@ -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");
|
||||
deferredUniforms = deferredRenderPassShader.bulkGetUniformLocation(@TypeOf(deferredUniforms));
|
||||
buffers.init();
|
||||
try Bloom.init();
|
||||
}
|
||||
|
||||
pub fn deinit() void {
|
||||
fogShader.delete();
|
||||
deferredRenderPassShader.delete();
|
||||
buffers.deinit();
|
||||
Bloom.deinit();
|
||||
}
|
||||
|
||||
const buffers = struct {
|
||||
@ -321,9 +323,9 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
|
||||
// glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
// }
|
||||
// }
|
||||
// if(ClientSettings.BLOOM) {
|
||||
// BloomRenderer.render(buffers, Window.getWidth(), Window.getHeight()); // TODO: Use true width/height
|
||||
// }
|
||||
if(settings.bloom) {
|
||||
Bloom.render(main.Window.width, main.Window.height);
|
||||
}
|
||||
buffers.unbind();
|
||||
buffers.bindTextures();
|
||||
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 {
|
||||
const Plane = struct {
|
||||
pos: Vec3f,
|
||||
|
@ -16,4 +16,6 @@ pub var fov: f32 = 45;
|
||||
pub var mouseSensitivity: f32 = 1;
|
||||
|
||||
pub var renderDistance: i32 = 4;
|
||||
pub var LODFactor: f32 = 2.0;
|
||||
pub var LODFactor: f32 = 2.0;
|
||||
|
||||
pub var bloom: bool = true;
|
Loading…
x
Reference in New Issue
Block a user