diff --git a/assets/shaders/cube_shadow.glsl b/assets/shaders/cube_shadow.glsl new file mode 100644 index 0000000..a182082 --- /dev/null +++ b/assets/shaders/cube_shadow.glsl @@ -0,0 +1,38 @@ +// UBOs +layout(std140, binding = 0) uniform Matrices { + mat4 projection; + mat4 view; +}; + +// Uniforms +layout(location = 1) uniform mat4 model; +layout(location = 18) uniform vec2 near_far; + +// Input, output blocks +VERTEX_EXPORT VertexData { + vec3 vPos; +} VertexOut; + +#if VERTEX_SHADER + +layout(location = 0) in vec3 aPos; + +void main() { + vec4 vPos = view * model * vec4(aPos.xyz, 1.0); + gl_Position = projection * vPos; + VertexOut.vPos = vPos.xyz; +} +#endif // VERTEX_SHADER + +#if FRAGMENT_SHADER + +float map(float value, float min1, float max1, float min2, float max2) { + return min2 + (value - min1) * (max2 - min2) / (max1 - min1); +} + +void main() { + gl_FragDepth = map(length(VertexOut.vPos), near_far.x, near_far.y, 0, 1); +} + + +#endif // FRAGMNET_SHADER diff --git a/assets/shaders/cube_shadow.prog b/assets/shaders/cube_shadow.prog new file mode 100644 index 0000000..41fe9cf --- /dev/null +++ b/assets/shaders/cube_shadow.prog @@ -0,0 +1,6 @@ + +{ + "shader": "cube_shadow.glsl", + "vertex": true, + "fragment": true +} diff --git a/assets/shaders/mesh.glsl b/assets/shaders/mesh.glsl index 1ade198..f2426f0 100644 --- a/assets/shaders/mesh.glsl +++ b/assets/shaders/mesh.glsl @@ -7,6 +7,8 @@ struct Light { vec4 vPos; vec4 color; + mat4 shadow_vp; // for spot and dir lights + vec2 near_far; // for point lights }; // UBOs @@ -44,7 +46,7 @@ layout(location = 14, bindless_sampler) uniform sampler2D emission_map; layout(location = 15) uniform vec2 emission_map_uv_scale = vec2(1); layout(location = 16, bindless_sampler) uniform sampler2DArrayShadow shadow_maps; -layout(location = 17) uniform mat4 shadow_map_vp; +layout(location = 17, bindless_sampler) uniform samplerCubeArrayShadow cube_shadow_maps; // Input, output blocks @@ -54,6 +56,7 @@ VERTEX_EXPORT VertexData { vec2 uv; mat3 vTBN; vec3 wPos; + vec3 wNormal; } VertexOut; float random(vec4 seed4) { @@ -81,6 +84,7 @@ void main() { VertexOut.vTBN = mat3(T, B, N); vec4 wPos = model * vec4(aPos.xyz, 1.0); VertexOut.wPos = wPos.xyz / wPos.w; + VertexOut.wNormal = normalize(model * vec4(aNormal, 0.0)).xyz; } #endif // VERTEX_SHADER @@ -145,7 +149,11 @@ vec2 poissonDisk[4] = vec2[]( vec2( 0.34495938, 0.29387760 ) ); -vec3 microfacetModel(Material mat, Light light, vec3 P, vec3 N) { +float map(float value, float min1, float max1, float min2, float max2) { + return min2 + (value - min1) * (max2 - min2) / (max1 - min1); +} + +vec3 microfacetModel(Material mat, int light_idx, Light light, vec3 P, vec3 N) { vec3 diffuseBrdf = vec3(0); // metallic if (!mat.metallic) { diffuseBrdf = mat.albedo; @@ -177,37 +185,60 @@ vec3 microfacetModel(Material mat, Light light, vec3 P, vec3 N) { float NDotL = max(dot(N, L), 0); float NDotV = dot(N, V); + float normal_offset_scale = clamp(1 - NDotL, 0, 1); + normal_offset_scale *= 10; // constant + + float constant_bias = 0.001; float shadow_mult = 1; - //// TODO: Shadows for directional light only for now - if (point == 0) { - vec4 shadow_pos = shadow_map_vp * vec4(VertexOut.wPos, 1.0); + vec4 shadow_offset = vec4(VertexOut.wNormal * normal_offset_scale, 0); + if (point == 1) { + vec2 shadow_map_texel_size = 1.0 / vec2(textureSize(cube_shadow_maps, 0)); + shadow_offset *= shadow_map_texel_size.x; + vec3 shadow_dir = (light.shadow_vp * vec4(VertexOut.wPos, 1.0)).xyz; + float world_depth = length(shadow_dir.xyz); + shadow_dir = normalize((light.shadow_vp * (vec4(VertexOut.wPos, 1.0) + shadow_offset)).xyz); + float mapped_depth = map(world_depth, light.near_far.x, light.near_far.y, 0, 1); + + vec4 texcoord; + texcoord.xyz = shadow_dir; + texcoord.w = float(light_idx); + + float sum = 0; + for (float z = -1; z <= 1; z += 1) { + for (float y = -1; y <= 1; y += 1) { + for (float x = -1; x <= 1; x += 1) { + sum += texture(cube_shadow_maps, vec4(normalize(texcoord.xyz + vec3(x, y, z) * shadow_map_texel_size.x), texcoord.w), mapped_depth - constant_bias); + } + } + } + + shadow_mult = sum / 27; + } else { + vec2 shadow_map_texel_size = 1.0 / vec2(textureSize(shadow_maps, 0)); + shadow_offset *= shadow_map_texel_size.x; + // Directional shadow + vec4 shadow_pos = light.shadow_vp * vec4(VertexOut.wPos, 1.0); + shadow_pos.xy = (light.shadow_vp * (vec4(VertexOut.wPos, 1.0) + shadow_offset)).xy; shadow_pos /= shadow_pos.w; shadow_pos.xyz = shadow_pos.xyz * 0.5 + 0.5; // [-1, 1] to [0, 1] - float bias = 0.005 * tan(acos(NDotL)); - shadow_pos.z -= bias; + shadow_pos.z -= constant_bias; + vec4 texcoord; texcoord.xyw = shadow_pos.xyz; // sampler2DArrayShadow strange texcoord mapping texcoord.z = 0; // First shadow map float sum = 0; - vec2 tex_scale = 1.0 / vec2(textureSize(shadow_maps, 0)); for (float y = -1.5; y <= 1.5; y += 1) { for (float x = -1.5; x <= 1.5; x += 1) { - sum += texture(shadow_maps, vec4(texcoord.xy + vec2(x, y) * tex_scale, texcoord.zw)); + sum += texture(shadow_maps, vec4(texcoord.xy + vec2(x, y) * shadow_map_texel_size, texcoord.zw)); } } shadow_mult = sum / 16.0; - - // for (int i=0; i<4; i++){ - // int index = int(16.0 * random(vec4(VertexOut.wPos.xyz * 1000.0, i))) % 4; - // float depth_test = texture(shadow_maps, vec4(texcoord.xy + poissonDisk[index]/700.0, texcoord.zw)); - // shadow_mult -= 0.25 * (1 - depth_test); - // } - //shadow_mult = texture(shadow_maps, texcoord); } + shadow_mult = clamp(shadow_mult, 0, 1); vec3 specBrdf = 0.25 * ggxDistribution(mat, NDotH) * schlickFresnel(mat, LDotH) * geomSmith(mat, NDotL) * geomSmith(mat, NDotV); @@ -226,7 +257,7 @@ void main() { vec3 finalColor = vec3(0); for (int i = 0; i < lights_count; i++) { - finalColor += microfacetModel(material, lights[i], VertexOut.vPos, N); + finalColor += microfacetModel(material, i, lights[i], VertexOut.vPos, N); } FragColor = vec4(finalColor, 1.0f); diff --git a/assets/shaders/shadow.glsl b/assets/shaders/shadow.glsl index e8c7ea8..96cbb21 100644 --- a/assets/shaders/shadow.glsl +++ b/assets/shaders/shadow.glsl @@ -20,8 +20,9 @@ void main() { #if FRAGMENT_SHADER + void main() { - gl_FragDepth = gl_FragCoord.z / gl_FragCoord.w; + //gl_FragDepth = gl_FragCoord.z / gl_FragCoord.w; } diff --git a/src/Render.zig b/src/Render.zig index 52d5962..18d56ab 100644 --- a/src/Render.zig +++ b/src/Render.zig @@ -36,11 +36,14 @@ command_buffer: [MAX_DRAW_COMMANDS]DrawCommand = undefined, command_count: usize = 0, ubo_align: usize = 0, shadow_vao: gl.GLuint = 0, -shadow_texture_arrray: gl.GLuint = 0, +shadow_texture_array: gl.GLuint = 0, shadow_texture_handle: gl.GLuint64 = 0, shadow_framebuffer: gl.GLuint = 0, shadow_matrices_buffer: gl.GLuint = 0, shadow_matrices: CameraMatrices = .{}, +cube_shadow_texture_array: gl.GLuint = 0, +cube_shadow_texture_handle: gl.GLuint64 = 0, +cube_shadow_framebuffer: gl.GLuint = 0, pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetman: *AssetManager) Render { var render = Render{ @@ -136,34 +139,68 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetm } { - // Shadow texture array - gl.createTextures(gl.TEXTURE_2D_ARRAY, 1, &render.shadow_texture_arrray); - checkGLError(); - std.debug.assert(render.shadow_texture_arrray != 0); + // 2D Shadow texture array + { + gl.createTextures(gl.TEXTURE_2D_ARRAY, 1, &render.shadow_texture_array); + checkGLError(); + std.debug.assert(render.shadow_texture_array != 0); - gl.textureStorage3D(render.shadow_texture_arrray, 1, gl.DEPTH_COMPONENT16, 2048, 2048, 1); - checkGLError(); + gl.textureStorage3D(render.shadow_texture_array, 1, gl.DEPTH_COMPONENT16, 2048, 2048, 1); + checkGLError(); - gl.textureParameteri(render.shadow_texture_arrray, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE); - gl.textureParameteri(render.shadow_texture_arrray, gl.TEXTURE_COMPARE_FUNC, gl.LESS); - gl.textureParameteri(render.shadow_texture_arrray, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER); - gl.textureParameteri(render.shadow_texture_arrray, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER); - gl.textureParameteri(render.shadow_texture_arrray, gl.TEXTURE_MIN_FILTER, gl.LINEAR); - gl.textureParameteri(render.shadow_texture_arrray, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.textureParameterfv(render.shadow_texture_arrray, gl.TEXTURE_BORDER_COLOR, @ptrCast(&Vec4.one().data)); + gl.textureParameteri(render.shadow_texture_array, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE); + gl.textureParameteri(render.shadow_texture_array, gl.TEXTURE_COMPARE_FUNC, gl.LESS); + gl.textureParameteri(render.shadow_texture_array, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER); + gl.textureParameteri(render.shadow_texture_array, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER); + gl.textureParameteri(render.shadow_texture_array, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.textureParameteri(render.shadow_texture_array, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.textureParameterfv(render.shadow_texture_array, gl.TEXTURE_BORDER_COLOR, @ptrCast(&Vec4.one().data)); + } // First shadow texture handle - render.shadow_texture_handle = gl.GL_ARB_bindless_texture.getTextureHandleARB(render.shadow_texture_arrray); - checkGLError(); - gl.GL_ARB_bindless_texture.makeTextureHandleResidentARB(render.shadow_texture_handle); - checkGLError(); + { + render.shadow_texture_handle = gl.GL_ARB_bindless_texture.getTextureHandleARB(render.shadow_texture_array); + checkGLError(); + std.debug.assert(render.shadow_texture_handle != 0); + gl.GL_ARB_bindless_texture.makeTextureHandleResidentARB(render.shadow_texture_handle); + checkGLError(); + } + + // Cube Shadow texture array + { + gl.createTextures(gl.TEXTURE_CUBE_MAP_ARRAY, 1, &render.cube_shadow_texture_array); + checkGLError(); + std.debug.assert(render.cube_shadow_texture_array != 0); + + gl.textureStorage3D(render.cube_shadow_texture_array, 1, gl.DEPTH_COMPONENT16, 512, 512, MAX_POINT_LIGHTS * 6); + checkGLError(); + + gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE); + gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_COMPARE_FUNC, gl.LESS); + gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.textureParameteri(render.cube_shadow_texture_array, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE); + } + + // Cube Shadow array handle + { + render.cube_shadow_texture_handle = gl.GL_ARB_bindless_texture.getTextureHandleARB(render.cube_shadow_texture_array); + checkGLError(); + std.debug.assert(render.cube_shadow_texture_handle != 0); + gl.GL_ARB_bindless_texture.makeTextureHandleResidentARB(render.cube_shadow_texture_handle); + checkGLError(); + } // Shadow FBO - gl.createFramebuffers(1, &render.shadow_framebuffer); - checkGLError(); - std.debug.assert(render.shadow_framebuffer != 0); + { + gl.createFramebuffers(1, &render.shadow_framebuffer); + checkGLError(); + std.debug.assert(render.shadow_framebuffer != 0); + } - gl.namedFramebufferTextureLayer(render.shadow_framebuffer, gl.DEPTH_ATTACHMENT, render.shadow_texture_arrray, 0, 0); + gl.namedFramebufferTextureLayer(render.shadow_framebuffer, gl.DEPTH_ATTACHMENT, render.shadow_texture_array, 0, 0); const check_fbo_status = gl.checkNamedFramebufferStatus(render.shadow_framebuffer, gl.DRAW_FRAMEBUFFER); if (check_fbo_status != gl.FRAMEBUFFER_COMPLETE) { std.log.debug("Shadow Framebuffer Incomplete: {}\n", .{check_fbo_status}); @@ -251,61 +288,88 @@ pub fn draw(self: *Render, cmd: DrawCommand) void { pub fn finish(self: *Render) void { const ginit = globals.g_init; - var dir_light: ?PointLight = null; - var dir_light_vp: ?Mat4 = null; + const lights = self.getPointLights(); - // Find directional light + // Light shadow maps { - const lights = self.getPointLights(); + gl.bindVertexArray(self.shadow_vao); - for (lights.lights[0..lights.count]) |*light| { + gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, self.shadow_framebuffer); + + for (lights.lights[0..lights.count], 0..) |*light, i| { + gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.shadow).program); + // Directional light if (std.math.approxEqAbs(f32, light.pos.w(), 0, std.math.floatEps(f32))) { - dir_light = light.*; - } + gl.namedFramebufferTextureLayer(self.shadow_framebuffer, gl.DEPTH_ATTACHMENT, self.shadow_texture_array, 0, 0); + const check_fbo_status = gl.checkNamedFramebufferStatus(self.shadow_framebuffer, gl.DRAW_FRAMEBUFFER); + if (check_fbo_status != gl.FRAMEBUFFER_COMPLETE) { + std.log.debug("Shadow Framebuffer Incomplete: {}\n", .{check_fbo_status}); + } - // Transform view to camera view space - light.pos = self.camera.view_mat.mulByVec4(light.pos); + gl.viewport(0, 0, 2048, 2048); + + const camera_matrix = &self.shadow_matrices; + camera_matrix.* = .{ + .projection = Mat4.orthographic(-2, 2, -2, 2, -5, 5), + .view = Mat4.lookAt( + Vec3.new(light.pos.x(), light.pos.y(), light.pos.z()).scale(-1), + Vec3.zero(), + Vec3.up(), + ), + }; + light.shadow_vp = camera_matrix.projection.mul(camera_matrix.view); + + gl.namedBufferSubData(self.shadow_matrices_buffer, 0, @sizeOf(CameraMatrices), std.mem.asBytes(&self.shadow_matrices)); + checkGLError(); + + gl.clear(gl.DEPTH_BUFFER_BIT); + gl.bindBufferBase(gl.UNIFORM_BUFFER, UBO.CameraMatrices.value(), self.shadow_matrices_buffer); + + self.renderShadow(); + } else { + // Point Light + gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.cube_shadow).program); + + const pos = Vec3.new(light.pos.x(), light.pos.y(), light.pos.z()); + light.shadow_vp = Mat4.fromTranslate(pos.negate()); + // For each cube face + for (cube_camera_dirs, 0..) |cam_dir, face| { + gl.namedFramebufferTextureLayer(self.shadow_framebuffer, gl.DEPTH_ATTACHMENT, self.cube_shadow_texture_array, 0, @intCast(i * 6 + face)); + const check_fbo_status = gl.checkNamedFramebufferStatus(self.shadow_framebuffer, gl.DRAW_FRAMEBUFFER); + if (check_fbo_status != gl.FRAMEBUFFER_COMPLETE) { + std.log.debug("Shadow Framebuffer Incomplete: {}\n", .{check_fbo_status}); + } + + gl.viewport(0, 0, 512, 512); + + const near_far = Vec2.new(0.1, 10); + const camera_matrix = &self.shadow_matrices; + camera_matrix.* = .{ + .projection = Mat4.perspective(90, 1, near_far.x(), near_far.y()), + .view = Mat4.lookAt( + pos, + pos.add(cam_dir.target), + cam_dir.up, + ), + }; + light.near_far = near_far; + gl.uniform2f(Uniform.NearFarPlanes.value(), near_far.x(), near_far.y()); + + gl.namedBufferSubData(self.shadow_matrices_buffer, 0, @sizeOf(CameraMatrices), std.mem.asBytes(&self.shadow_matrices)); + checkGLError(); + + gl.clear(gl.DEPTH_BUFFER_BIT); + gl.bindBufferBase(gl.UNIFORM_BUFFER, UBO.CameraMatrices.value(), self.shadow_matrices_buffer); + + self.renderShadow(); + } + } } } - // Directional Light shadow map - if (dir_light) |light| { - gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, self.shadow_framebuffer); - gl.viewport(0, 0, 2048, 2048); - gl.clear(gl.DEPTH_BUFFER_BIT); - - gl.useProgram(self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.shadow).program); - gl.bindVertexArray(self.shadow_vao); - - const camera_matrix = &self.shadow_matrices; - camera_matrix.* = .{ - .projection = Mat4.orthographic(-2, 2, -2, 2, -5, 5), - .view = Mat4.lookAt( - Vec3.new(light.pos.x(), light.pos.y(), light.pos.z()).scale(-1), - Vec3.zero(), - Vec3.up(), - ), - }; - dir_light_vp = camera_matrix.projection.mul(camera_matrix.view); - // TODO: use multiple buffers for this in the future - gl.namedBufferSubData(self.shadow_matrices_buffer, 0, @sizeOf(CameraMatrices), std.mem.asBytes(camera_matrix)); - checkGLError(); - gl.bindBufferBase(gl.UNIFORM_BUFFER, UBO.CameraMatrices.value(), self.shadow_matrices_buffer); - - for (self.command_buffer[0..self.command_count]) |*cmd| { - const mesh = self.assetman.resolveMesh(cmd.mesh); - - gl.uniformMatrix4fv(Uniform.ModelMatrix.value(), 1, gl.FALSE, @ptrCast(&cmd.transform.data)); - mesh.positions.bind(Render.Attrib.Position.value()); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mesh.indices.buffer); - - gl.drawElements( - gl.TRIANGLES, - mesh.indices.count, - mesh.indices.type, - @ptrFromInt(mesh.indices.offset), - ); - } + // Light world space to view space + for (lights.lights[0..lights.count]) |*light| { + light.pos = self.camera.view_mat.mulByVec4(light.pos); } var width: c_int = 0; @@ -393,10 +457,8 @@ pub fn finish(self: *Render) void { ); gl.uniform2fv(Uniform.EmissionMapUVScale.value(), 1, @ptrCast(&emission_map.uv_scale.data)); } - if (dir_light != null) { - gl.GL_ARB_bindless_texture.uniformHandleui64ARB(Uniform.ShadowMap.value(), self.shadow_texture_handle); - gl.uniformMatrix4fv(Uniform.ShadowMapVP.value(), 1, gl.FALSE, @ptrCast(&dir_light_vp.?.data)); - } + gl.GL_ARB_bindless_texture.uniformHandleui64ARB(Uniform.ShadowMap2D.value(), self.shadow_texture_handle); + gl.GL_ARB_bindless_texture.uniformHandleui64ARB(Uniform.ShadowMapCube.value(), self.cube_shadow_texture_handle); mesh.positions.bind(Render.Attrib.Position.value()); mesh.normals.bind(Render.Attrib.Normal.value()); @@ -416,6 +478,62 @@ pub fn finish(self: *Render) void { c.SDL_Delay(1); } +const CubeCameraDir = struct { + face: gl.GLenum, + target: Vec3, + up: Vec3, +}; + +const cube_camera_dirs = [6]CubeCameraDir{ + .{ + .face = gl.TEXTURE_CUBE_MAP_POSITIVE_X, + .target = Vec3.right(), + .up = Vec3.down(), + }, + .{ + .face = gl.TEXTURE_CUBE_MAP_NEGATIVE_X, + .target = Vec3.left(), + .up = Vec3.down(), + }, + .{ + .face = gl.TEXTURE_CUBE_MAP_POSITIVE_Y, + .target = Vec3.up(), + .up = Vec3.forward(), + }, + .{ + .face = gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, + .target = Vec3.down(), + .up = Vec3.back(), + }, + .{ + .face = gl.TEXTURE_CUBE_MAP_POSITIVE_Z, + .target = Vec3.forward(), + .up = Vec3.down(), + }, + .{ + .face = gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, + .target = Vec3.back(), + .up = Vec3.down(), + }, +}; + +fn renderShadow(self: *Render) void { + for (self.command_buffer[0..self.command_count]) |*cmd| { + const mesh = self.assetman.resolveMesh(cmd.mesh); + + gl.uniformMatrix4fv(Uniform.ModelMatrix.value(), 1, gl.FALSE, @ptrCast(&cmd.transform.data)); + mesh.positions.bind(Render.Attrib.Position.value()); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mesh.indices.buffer); + + gl.drawElements( + gl.TRIANGLES, + mesh.indices.count, + mesh.indices.type, + @ptrFromInt(mesh.indices.offset), + ); + } +} + pub fn checkGLError() void { var err = gl.getError(); if (err == gl.NO_ERROR) return; @@ -483,8 +601,10 @@ pub const Uniform = enum(gl.GLint) { EmissionMap = 14, EmissionMapUVScale = 15, - ShadowMap = 16, - ShadowMapVP = 17, + ShadowMap2D = 16, + ShadowMapCube = 17, + + NearFarPlanes = 18, // vec2 stores near and far planes for perspective projection pub inline fn value(self: Uniform) gl.GLint { return @intFromEnum(self); @@ -513,6 +633,8 @@ const CameraMatrices = extern struct { pub const PointLight = extern struct { pos: Vec4, // x, y, z, w - vPos color_radius: Vec4, // x, y, z - color, w - radius + shadow_vp: Mat4 = Mat4.identity(), + near_far: Vec2 = Vec2.zero(), }; // TODO: rename diff --git a/src/game.zig b/src/game.zig index cc51abc..19b9de0 100644 --- a/src/game.zig +++ b/src/game.zig @@ -114,6 +114,7 @@ fn loadGL() void { }; gl.debugMessageCallback(glDebugCallback, null); // gl.enable(gl.DEBUG_OUTPUT); + gl.enable(gl.DEBUG_OUTPUT_SYNCHRONOUS); } fn glDebugCallback(source: gl.GLenum, _type: gl.GLenum, id: gl.GLuint, severity: gl.GLenum, length: gl.GLsizei, message: [*:0]const u8, userParam: ?*anyopaque) callconv(.C) void { @@ -188,7 +189,7 @@ export fn game_init(global_allocator: *std.mem.Allocator) void { _ = globals.g_mem.world.addEntity(.{ .flags = .{ .dir_light = true, .rotate = true }, .transform = .{ .rot = Quat.fromEulerAngles(Vec3.new(60, 15, 0)) }, - .light = .{ .color_intensity = Vec4.new(1, 1, 0.83, 1) }, + .light = .{ .color_intensity = Vec4.new(1, 1, 0.83, 0.7) }, }); const light_root = globals.g_mem.world.addEntity(.{