From e3be287fe102c3083fbeaa1993e06345a14fbe29 Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sun, 14 Jan 2024 20:01:32 +0200 Subject: [PATCH] test out better bloom in test-scene --- build.zig | 3 +- libs/raylib/raylib.zig | 16 ++--- src/main.zig | 9 +++ src/shaders/bloom_fs.glsl | 26 ++++---- src/shaders/bloom_vs.glsl | 12 ++++ src/shaders/default_vs.glsl | 24 -------- src/shaders/main_fs.glsl | 7 +++ src/test-scene.zig | 115 ++++++++++++++++++++++++++++++++---- 8 files changed, 151 insertions(+), 61 deletions(-) create mode 100644 src/shaders/bloom_vs.glsl delete mode 100644 src/shaders/default_vs.glsl diff --git a/build.zig b/build.zig index 841ec48..b39c737 100644 --- a/build.zig +++ b/build.zig @@ -7,6 +7,7 @@ pub fn build(b: *std.Build) !void { // TODO: Figure out how to build project for WASM. Tried to do it but standard memory allocators // didn't work. + // Might help: https://github.com/ryupold/raylib.zig/issues/28 const exe = b.addExecutable(.{ .name = "chip8-zig", @@ -41,7 +42,7 @@ pub fn build(b: *std.Build) !void { exe.addOptions("options", options); } - raylib.addTo(b, exe, target, optimize); + raylib.addTo(b, exe, target, optimize, .{}); { var build_models_step = b.step("models", "Export .blend files"); diff --git a/libs/raylib/raylib.zig b/libs/raylib/raylib.zig index 5623096..804e3f7 100644 --- a/libs/raylib/raylib.zig +++ b/libs/raylib/raylib.zig @@ -8395,17 +8395,17 @@ pub fn rlDrawVertexArrayElementsInstanced( /// Load texture data pub fn rlLoadTexture( - data: *const anyopaque, + data: ?*const anyopaque, width: i32, height: i32, - format: i32, + format: PixelFormat, mipmapCount: i32, ) u32 { return raylib.mrlLoadTexture( data, width, height, - format, + @intFromEnum(format), mipmapCount, ); } @@ -8557,15 +8557,15 @@ pub fn rlLoadFramebuffer( pub fn rlFramebufferAttach( fboId: u32, texId: u32, - attachType: i32, - texType: i32, + attachType: rlFramebufferAttachType, + texType: rlFramebufferAttachTextureType, mipLevel: i32, ) void { raylib.mrlFramebufferAttach( fboId, texId, - attachType, - texType, + @intFromEnum(attachType), + @intFromEnum(texType), mipLevel, ); } @@ -10444,7 +10444,7 @@ pub const Texture2D = extern struct { /// Mipmap levels, 1 by default mipmaps: i32, /// Data format (PixelFormat type) - format: i32, + format: PixelFormat, }; /// RenderTexture, fbo for texture rendering diff --git a/src/main.zig b/src/main.zig index e34d8f3..2a3bfee 100755 --- a/src/main.zig +++ b/src/main.zig @@ -1,5 +1,6 @@ const rl = @import("raylib"); const std = @import("std"); +const gl = @import("opengl"); const print = std.debug.print; const Allocator = std.mem.Allocator; @@ -14,6 +15,10 @@ fn megabytes(amount: usize) usize { return amount * 1024 * 1024; } +fn load_opengl_function(opengl_lib: *std.DynLib, func_name: [:0]const u8) ?gl.FunctionPointer { + return opengl_lib.lookup(gl.FunctionPointer, func_name); +} + pub fn main() anyerror!void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); @@ -30,6 +35,10 @@ pub fn main() anyerror!void { rl.SetTargetFPS(60); + var opengl_lib = try std.DynLib.open("libGL.so"); // TODO: Make this cross platform, .dll on windows + defer opengl_lib.close(); + try gl.load(&opengl_lib, load_opengl_function); + var scene = try TestScene.init(allocator); defer scene.deinit(); diff --git a/src/shaders/bloom_fs.glsl b/src/shaders/bloom_fs.glsl index 1c645ac..e776f96 100644 --- a/src/shaders/bloom_fs.glsl +++ b/src/shaders/bloom_fs.glsl @@ -1,20 +1,14 @@ #version 330 -// Input vertex attributes (from vertex shader) -in vec2 fragTexCoord; -in vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -// Output fragment color -out vec4 finalColor; +out vec4 fragColor; +in vec2 texCoords; +uniform sampler2D screenTexture; +uniform sampler2D bloomTexture; uniform vec2 renderSize; -// const vec2 size = vec2(800, 450); // Framebuffer size -const float samples = 7.0; // Pixels per axis; higher = bigger glow, worse performance -const float quality = 5.0; // Defines size factor: Lower = smaller glow, better quality + +const float samples = 9.0; +const float quality = 5.0; void main() { @@ -22,7 +16,7 @@ void main() vec2 sizeFactor = vec2(1)/renderSize*quality; // Texel color fetching from texture sampler - vec4 source = texture(texture0, fragTexCoord); + vec4 source = texture(screenTexture, texCoords); const int range = (int(samples) - 1)/2; // should be = (samples - 1)/2; @@ -30,10 +24,10 @@ void main() { for (int y = -range; y <= range; y++) { - sum += texture(texture0, fragTexCoord + vec2(x, y)*sizeFactor); + sum += texture(bloomTexture, texCoords + vec2(x, y)*sizeFactor); } } // Calculate final fragment color - finalColor = ((sum/(samples*samples)) + source)*colDiffuse; + fragColor = ((sum/(samples*samples)) + source); } diff --git a/src/shaders/bloom_vs.glsl b/src/shaders/bloom_vs.glsl new file mode 100644 index 0000000..8b138d3 --- /dev/null +++ b/src/shaders/bloom_vs.glsl @@ -0,0 +1,12 @@ +#version 330 + +layout (location = 0) in vec2 inPos; +layout (location = 1) in vec2 inTexCoords; + +out vec2 texCoords; + +void main() +{ + gl_Position = vec4(inPos.x, inPos.y, 0.0, 1.0); + texCoords = vec2(inTexCoords.x, 1-inTexCoords.y); +} diff --git a/src/shaders/default_vs.glsl b/src/shaders/default_vs.glsl deleted file mode 100644 index d786749..0000000 --- a/src/shaders/default_vs.glsl +++ /dev/null @@ -1,24 +0,0 @@ -#version 330 - -// Input vertex attributes -in vec3 vertexPosition; -in vec2 vertexTexCoord; -in vec3 vertexNormal; -in vec4 vertexColor; - -// Input uniform values -uniform mat4 mvp; - -// Output vertex attributes (to fragment shader) -out vec2 fragTexCoord; -out vec4 fragColor; - -void main() -{ - // Send vertex attributes to fragment shader - fragTexCoord = vertexTexCoord; - fragColor = vertexColor; - - // Calculate final vertex position - gl_Position = mvp*vec4(vertexPosition, 1.0); -} diff --git a/src/shaders/main_fs.glsl b/src/shaders/main_fs.glsl index 22069f3..59da44e 100644 --- a/src/shaders/main_fs.glsl +++ b/src/shaders/main_fs.glsl @@ -74,5 +74,12 @@ void main() { // Gamma correction finalColor = pow(finalColor, vec4(1.0/1.9)); + + float brigthness = dot(finalColor.rgb, vec3(0.2126f, 0.7152f, 0.0722f)); + if (brigthness > 0.53f) { + bloomColor = vec4(finalColor.rgb, 1); + } else { + bloomColor = vec4(0, 0, 0, 0); + } } diff --git a/src/test-scene.zig b/src/test-scene.zig index 6241b8a..a9b3695 100644 --- a/src/test-scene.zig +++ b/src/test-scene.zig @@ -6,6 +6,7 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const ShaderCode = @import("./shader-code.zig"); const Light = @import("./light.zig"); +const assert = std.debug.assert; const max_lights = 1; @@ -14,11 +15,62 @@ const SHADER_LOC_VECTOR_VIEW = @intFromEnum(rl.ShaderLocationIndex.SHADER_LOC_VE shader: rl.Shader, bloom_shader: rl.Shader, frame_buffer: rl.RenderTexture2D, +bloom_texture: rl.Texture2D, camera: rl.Camera3D, lights: [max_lights]Light, +rect: OpenglRect, cube: rl.Model, + +const OpenglRect = struct { + vbo: u32, + vao: u32, + + fn init() OpenglRect { + var rect: OpenglRect = undefined; + + const vertices = [_]f32{ + // Coords // texCoords + 1.0, -1.0, 1.0, 0.0, + -1.0, 1.0, 0.0, 1.0, + -1.0, -1.0, 0.0, 0.0, + + 1.0, 1.0, 1.0, 1.0, + -1.0, 1.0, 0.0, 1.0, + 1.0, -1.0, 1.0, 0.0, + }; + + gl.genVertexArrays(1, &rect.vao); + gl.genBuffers(1, &rect.vbo); + gl.bindVertexArray(rect.vao); + gl.bindBuffer(gl.ARRAY_BUFFER, rect.vbo); + gl.bufferData(gl.ARRAY_BUFFER, vertices.len * @sizeOf(f32), @ptrCast(&vertices), gl.STATIC_DRAW); + gl.enableVertexAttribArray(0); + gl.vertexAttribPointer(0, 2, gl.FLOAT, gl.FALSE, 4 * @sizeOf(f32), @ptrFromInt(0)); + gl.enableVertexAttribArray(1); + gl.vertexAttribPointer(1, 2, gl.FLOAT, gl.FALSE, 4 * @sizeOf(f32), @ptrFromInt(2 * @sizeOf(f32))); + + return rect; + } + + fn draw(self: OpenglRect) void { + gl.bindVertexArray(self.vao); + gl.disable(gl.DEPTH_TEST); + gl.drawArrays(gl.TRIANGLES, 0, 6); + } +}; + +fn loadEmptyTexture(width: i32, height: i32, format: rl.PixelFormat) rl.Texture2D { + var target: rl.Texture2D = undefined; + target.id = rl.rlLoadTexture(null, width, height, format, 1); + target.width = width; + target.height = height; + target.format = format; + target.mipmaps = 1; + return target; +} + pub fn init(allocator: Allocator) !Self { const main_shader_code = try ShaderCode.init(allocator, max_lights); defer main_shader_code.deinit(); @@ -29,20 +81,27 @@ pub fn init(allocator: Allocator) !Self { return error.CompileShader; } - const bloom_shader = rl.LoadShaderFromMemory(@embedFile("shaders/default_vs.glsl"), @embedFile("shaders/bloom_fs.glsl")); + const bloom_shader = rl.LoadShaderFromMemory(@embedFile("shaders/bloom_vs.glsl"), @embedFile("shaders/bloom_fs.glsl")); errdefer rl.UnloadShader(bloom_shader); if (bloom_shader.id == rl.rlGetShaderIdDefault()) { return error.CompileShader; } - const frame_buffer = rl.LoadRenderTexture(rl.GetScreenWidth(), rl.GetScreenHeight()); + const screen_width = rl.GetScreenWidth(); + const screen_height = rl.GetScreenHeight(); + const frame_buffer = rl.LoadRenderTexture(screen_width, screen_height); errdefer rl.UnloadRenderTexture(frame_buffer); + var bloom_texture = loadEmptyTexture(screen_width, screen_height, .PIXELFORMAT_UNCOMPRESSED_R8G8B8); + rl.rlFramebufferAttach(frame_buffer.id, bloom_texture.id, .RL_ATTACHMENT_COLOR_CHANNEL1, .RL_ATTACHMENT_TEXTURE2D, 0); + if (rl.rlFramebufferComplete(frame_buffer.id)) std.debug.print("INFO: Successfully attached bloom texture", .{}); + + rl.rlActiveDrawBuffers(2); + var lights: [max_lights]Light = undefined; for (0..max_lights) |i| { lights[i] = Light.init(shader, i); } - Light.init(shader, 0).set_point(rl.RED, rl.Vector3{ .x = 1, .y = 1, .z = 0.5 }, 2.0); shader.locs.?[SHADER_LOC_VECTOR_VIEW] = rl.GetShaderLocation(shader, "viewPos"); @@ -50,10 +109,14 @@ pub fn init(allocator: Allocator) !Self { const ambientLoc = rl.GetShaderLocation(shader, "ambient"); rl.SetShaderValue(shader, ambientLoc, &[4]f32{ 0.6, 0.6, 1, 1.0 }, .SHADER_UNIFORM_VEC4); + const rect = OpenglRect.init(); + return Self{ .shader = shader, .bloom_shader = bloom_shader, + .rect = rect, .frame_buffer = frame_buffer, + .bloom_texture = bloom_texture, .camera = rl.Camera3D{ .position = rl.Vector3.new(0, 0, -10), .target = rl.Vector3.new(0.0, 0.0, 0.0), @@ -76,7 +139,12 @@ pub fn update(self: *Self, dt: f32) void { const screen_height = rl.GetScreenHeight(); if (self.frame_buffer.texture.width != screen_width or self.frame_buffer.texture.height != screen_height) { rl.UnloadRenderTexture(self.frame_buffer); + rl.UnloadTexture(self.bloom_texture); self.frame_buffer = rl.LoadRenderTexture(screen_width, screen_height); + + self.bloom_texture = loadEmptyTexture(screen_width, screen_height, .PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); + rl.rlFramebufferAttach(self.frame_buffer.id, self.bloom_texture.id, .RL_ATTACHMENT_COLOR_CHANNEL1, .RL_ATTACHMENT_TEXTURE2D, 0); + if (rl.rlFramebufferComplete(self.frame_buffer.id)) std.debug.print("INFO: Successfully attached bloom texture", .{}); } rl.UpdateCamera(&self.camera, .CAMERA_THIRD_PERSON); @@ -87,15 +155,23 @@ pub fn update(self: *Self, dt: f32) void { } pub fn draw(self: *Self) void { + rl.BeginTextureMode(self.frame_buffer); { - rl.ClearBackground(.{ .r = 33, .g = 33, .b = 33, .a = 255 }); + rl.rlActiveDrawBuffers(2); + + const bg_color = [_]f32{ 33.0 / 255.0, 33.0 / 255.0, 33.0 / 255.0, 1.0 }; + gl.clearBufferfv(gl.COLOR, 0, &bg_color); + + const transparent_color = [_]f32{ 0.0, 0.0, 0.0, 0.0 }; + gl.clearBufferfv(gl.COLOR, 1, &transparent_color); + gl.clear(gl.DEPTH_BUFFER_BIT); rl.BeginMode3D(self.camera); rl.BeginShaderMode(self.shader); - self.cube.materials.?[0].shader = self.shader; - rl.DrawModel(self.cube, rl.Vector3Zero(), 1.0, rl.WHITE); + self.cube.materials.?[0].shader = self.shader; + rl.DrawModel(self.cube, rl.Vector3Zero(), 1.0, rl.WHITE); rl.EndShaderMode(); rl.EndMode3D(); @@ -104,13 +180,28 @@ pub fn draw(self: *Self) void { const screen_width = rl.GetScreenWidth(); const screen_height = rl.GetScreenHeight(); - const screen_rect = rl.Rectangle{ .x = 0, .y = 0, .width = @floatFromInt(screen_width), .height = @floatFromInt(screen_height) }; + // const screen_rect = rl.Rectangle{ .x = 0, .y = 0, .width = @floatFromInt(screen_width), .height = @floatFromInt(screen_height) }; - const loc = rl.GetShaderLocation(self.bloom_shader, "renderSize"); - rl.SetShaderValue(self.bloom_shader, loc, &[2]f32{ @floatFromInt(screen_width), @floatFromInt(screen_height) }, .SHADER_UNIFORM_VEC2); rl.BeginDrawing(); - rl.BeginShaderMode(self.bloom_shader); - rl.DrawTextureRec(self.frame_buffer.texture, screen_rect, rl.Vector2.zero(), rl.WHITE); - rl.EndShaderMode(); + + gl.useProgram(self.bloom_shader.id); + + rl.rlDisableDepthTest(); + + const renderSize = [_]f32{ @floatFromInt(screen_width), @floatFromInt(screen_height) }; + rl.rlSetUniform(rl.rlGetLocationUniform(self.bloom_shader.id, "renderSize"), &renderSize, @intFromEnum(rl.ShaderUniformDataType.SHADER_UNIFORM_VEC2), 1); + rl.rlSetUniformSampler(rl.rlGetLocationUniform(self.bloom_shader.id, "screenTexture"), self.frame_buffer.texture.id); + rl.rlSetUniformSampler(rl.rlGetLocationUniform(self.bloom_shader.id, "bloomTexture"), self.bloom_texture.id); + + gl.bindVertexArray(self.rect.vao); + + rl.rlActiveTextureSlot(1); + rl.rlEnableTexture(self.frame_buffer.texture.id); + + rl.rlActiveTextureSlot(2); + rl.rlEnableTexture(self.bloom_texture.id); + + gl.drawArrays(gl.TRIANGLES, 0, 6); + rl.EndDrawing(); }