From e32387ca72db26757d7ace797e814af4a51528de Mon Sep 17 00:00:00 2001 From: sergeypdev Date: Wed, 21 Feb 2024 05:25:33 +0400 Subject: [PATCH] PBR!!! --- assets/shaders/mesh.glsl | 104 ++++++++++++++++++++++++++++++++------- src/game.zig | 42 +++++++++++++--- 2 files changed, 123 insertions(+), 23 deletions(-) diff --git a/assets/shaders/mesh.glsl b/assets/shaders/mesh.glsl index 39b92c6..0f16855 100644 --- a/assets/shaders/mesh.glsl +++ b/assets/shaders/mesh.glsl @@ -1,6 +1,7 @@ #extension GL_ARB_bindless_texture : enable // Keep in sync with cpu #define MAX_POINT_LIGHTS 8 +#define PI 3.1415926535897932384626433832795 // Types struct Light { @@ -33,7 +34,7 @@ layout(location = 6, bindless_sampler) uniform sampler2D metallic_map; layout(location = 7) uniform float roughness; layout(location = 8, bindless_sampler) uniform sampler2D roughness_map; -layout(location = 9) uniform float emission; +layout(location = 9) uniform vec3 emission; layout(location = 10, bindless_sampler) uniform sampler2D emission_map; @@ -70,9 +71,88 @@ void main() { out vec4 FragColor; -void main() { - vec3 albedoColor = textureSize(albedo_map, 0) == ivec2(0) ? color : texture(albedo_map, VertexOut.uv).rgb; +struct Material { + vec3 albedo; + bool metallic; + float roughness; + vec3 emission; +}; +Material evalMaterial() { + Material result; + result.albedo = textureSize(albedo_map, 0) == ivec2(0) ? pow(color, vec3(2.2)) : texture(albedo_map, VertexOut.uv).rgb; + float fMetallic = textureSize(metallic_map, 0) == ivec2(0) ? metallic : texture(metallic_map, VertexOut.uv).r; + result.metallic = fMetallic > 0.5; + result.roughness = max(0.01, textureSize(roughness_map, 0) == ivec2(0) ? roughness : texture(roughness_map, VertexOut.uv).r); + result.emission = textureSize(emission_map, 0) == ivec2(0) ? emission : texture(emission_map, VertexOut.uv).rgb; + + return result; +} + +vec3 schlickFresnel(Material mat, float LDotH) { + vec3 f0 = vec3(0.04); // dielectric + if (mat.metallic) { + f0 = mat.albedo; + } + + return f0 + (1 - f0) * pow(1.0 - LDotH, 5); +} + +float geomSmith(Material mat, float DotVal) { + float k = (mat.roughness + 1.0) * (mat.roughness + 1.0) / 8.0; + float denom = DotVal * (1 - k) + k; + return 1.0 / denom; +} + +float ggxDistribution(Material mat, float NDotH) { + float alpha2 = mat.roughness * mat.roughness * mat.roughness * mat.roughness; + float d = (NDotH * NDotH) * (alpha2 - 1) + 1; + return alpha2 / (PI * d * d); +} + +float lightAttenuation(float dist, float radius) { + float d = max(dist - radius, 0); + + float denom = d/radius + 1; + float att = 1 / (denom * denom); + // TODO: cutoff + att = max(att, 0); + + return att; +} + + +vec3 microfacetModel(Material mat, Light light, vec3 P, vec3 N) { + vec3 diffuseBrdf = vec3(0); // metallic + if (!mat.metallic) { + diffuseBrdf = mat.albedo; + } + + vec3 lightI = light.color.rgb * light.color.a; + float lightRadius = light.vPos.w; + vec3 L = light.vPos.xyz - P; + float dist = length(L); + L /= dist; + + float att = lightAttenuation(dist, lightRadius); + lightI *= att; + + vec3 V = normalize(-P); + vec3 H = normalize(V + L); + + float NDotH = dot(N, H); + float LDotH = dot(L, H); + float NDotL = max(dot(N, L), 0); + float NDotV = dot(N, V); + + vec3 specBrdf = 0.25 * ggxDistribution(mat, NDotH) * schlickFresnel(mat, LDotH) * geomSmith(mat, NDotL) * geomSmith(mat, NDotV); + + return (diffuseBrdf + PI * specBrdf) * lightI * NDotL; +} + +void main() { + Material material = evalMaterial(); + vec3 N = textureSize(normal_map, 0) == ivec2(0) ? vec3(0.5) : vec3(texture(normal_map, VertexOut.uv).xy, 0); N = N * 2.0 - 1.0; N.z = sqrt(clamp(1 - N.x * N.x - N.y * N.y, 0, 1)); @@ -82,26 +162,16 @@ void main() { vec3 finalColor = vec3(0); for (int i = 0; i < lights_count; i++) { - float radius = lights[i].vPos.w; - vec3 L = lights[i].vPos.xyz - VertexOut.vPos; - float dist = length(L); - float d = max(dist - radius, 0); - L /= dist; - - float denom = d/radius + 1; - float att = 1 / (denom * denom); - // TODO: cutoff - att = max(att, 0); - - float ndotl = max(dot(L, N), 0); - - finalColor += ndotl * lights[i].color.w * lights[i].color.xyz * att * albedoColor; + finalColor += microfacetModel(material, lights[i], VertexOut.vPos, N); } + // finalColor += microfacetModel(material, Light(vec4(VertexOut.vPos + N, 0.01), vec4(1, 1, 1, 10)), VertexOut.vPos, N); + FragColor = vec4(finalColor, 1.0f); float gamma = 2.2; FragColor.rgb = pow(FragColor.rgb, vec3(1.0/gamma)); } + #endif // FRAGMNET_SHADER diff --git a/src/game.zig b/src/game.zig index 2a421e9..3fce972 100644 --- a/src/game.zig +++ b/src/game.zig @@ -143,14 +143,14 @@ export fn game_init(global_allocator: *std.mem.Allocator) void { gl.viewport(0, 0, globals.g_init.width, globals.g_init.height); _ = globals.g_mem.world.addEntity(.{ - .transform = .{ .pos = Vec3.new(1, 1, 0) }, + .transform = .{ .pos = Vec3.new(1.8, 1, 0) }, .flags = .{ .point_light = true, .rotate = true }, .point_light = .{ .color_intensity = Vec4.new(1.0, 0.3, 0.1, 100.0), .radius = 0.1 }, .rotate = .{ .axis = Vec3.up(), .rate = 60 }, }); _ = globals.g_mem.world.addEntity(.{ - .transform = .{ .pos = Vec3.new(-1, 1, 0) }, + .transform = .{ .pos = Vec3.new(-2, 1, 0) }, .flags = .{ .point_light = true, .rotate = true }, .point_light = .{ .color_intensity = Vec4.new(0.2, 0.5, 1.0, 100.0), @@ -159,10 +159,19 @@ export fn game_init(global_allocator: *std.mem.Allocator) void { .rotate = .{ .axis = Vec3.up(), .rate = -20 }, }); + _ = globals.g_mem.world.addEntity(.{ + .transform = .{ .pos = Vec3.new(1, 0.5, 4) }, + .flags = .{ .point_light = true }, + .point_light = .{ + .color_intensity = Vec4.new(0.2, 0.5, 1.0, 10.0), + .radius = 1, + }, + }); + // Plane _ = globals.g_mem.world.addEntity(.{ .flags = .{ .mesh = true }, - .transform = .{ .scale = Vec3.one().scale(1) }, + .transform = .{ .scale = Vec3.one().scale(2) }, .mesh = .{ .handle = a.Meshes.plane, .material = .{ @@ -171,18 +180,39 @@ export fn game_init(global_allocator: *std.mem.Allocator) void { }, }); - // 10 bunnies + // 10 dielectric bunnies { for (0..10) |i| { _ = globals.g_mem.world.addEntity(.{ - .transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(i)) * 0.3, 0, 0) }, + .transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(i)) * 0.3 - 0.3 * 4.5, 0, 0) }, .flags = .{ .mesh = true }, .mesh = .{ .handle = a.Meshes.bunny, .material = .{ .albedo_map = a.Textures.bunny_tex1, - .normal_map = a.Textures.@"tile.norm", + // .normal_map = a.Textures.@"tile.norm", + .roughness = @as(f32, @floatFromInt(i)) / 10.0, + }, + }, + }); + } + } + // 10 metallic bunnies + { + for (0..10) |i| { + _ = globals.g_mem.world.addEntity(.{ + .transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(i)) * 0.3 - 0.3 * 4.5, 0.3, 0) }, + + .flags = .{ .mesh = true }, + .mesh = .{ + .handle = a.Meshes.bunny, + .material = .{ + .albedo = Vec3.new(1.000, 0.766, 0.336), + // .albedo_map = a.Textures.bunny_tex1, + // .normal_map = a.Textures.@"tile.norm", + .roughness = @as(f32, @floatFromInt(i + 1)) / 10.0, + .metallic = 1.0, }, }, });