From 86960eb89aec7062a15c8b6a806242060f2a20c4 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Tue, 3 Sep 2024 13:58:01 +0100 Subject: [PATCH 01/21] Added View Bobbing to Camera --- src/game.zig | 21 ++++++++++++++++++++- src/gui/windows/graphics.zig | 10 ++++++++++ src/settings.zig | 2 ++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/game.zig b/src/game.zig index ceffbc9af..2414a82a2 100644 --- a/src/game.zig +++ b/src/game.zig @@ -295,6 +295,9 @@ pub const Player = struct { // MARK: Player pub var eyePos: Vec3d = .{0, 0, 0}; pub var eyeVel: Vec3d = .{0, 0, 0}; pub var eyeStep: @Vector(3, bool) = .{false, false, false}; + pub var bobTime: f64 = 0; + pub var bobVel: f64 = 0; + pub var bobVec: Vec3d = .{0, 0, 0}; pub var id: u32 = 0; pub var isFlying: Atomic(bool) = Atomic(bool).init(false); pub var isGhost: Atomic(bool) = Atomic(bool).init(false); @@ -342,7 +345,7 @@ pub const Player = struct { // MARK: Player pub fn getEyePosBlocking() Vec3d { mutex.lock(); defer mutex.unlock(); - return eyePos + super.pos + desiredEyePos; + return eyePos + super.pos + desiredEyePos + bobVec; } pub fn getVelBlocking() Vec3d { @@ -665,6 +668,22 @@ pub fn update(deltaTime: f64) void { // MARK: update() Player.selectedSlot = @intCast(@mod(newSlot, 12)); main.Window.scrollOffset = 0; } + + // View Bobbing + if (Player.onGround) { // No view bobbing in the air + // Smooth lerping of bobTime with framerate independent damping + const fac: f64 = 1 - std.math.exp(-10 * deltaTime); + var targetBobVel: f64 = 0; + if (movementSpeed > 0) { + targetBobVel = vec.dot(movementDir * @as(Vec3d, @splat(std.math.log2(movementSpeed / 4 + 1))), forward); + } + Player.bobVel = Player.bobVel * (1 - fac) + targetBobVel * fac; + Player.bobTime += std.math.pow(f64, Player.bobVel, 0.7) * 8 * deltaTime; + } + const bobStrength: f64 = Player.bobVel * 0.04 * settings.viewBobStrength; + const xBob = std.math.cos(Player.bobTime); // Horizontal Component + const zBob = std.math.pow(f64, std.math.sin(Player.bobTime), 2) * 1.5; // Vertical Component + Player.bobVec = vec.rotateZ(Vec3d{ xBob * bobStrength, 0, zBob * bobStrength }, -camera.rotation[2]); // This our model for movement on a single frame: // dv/dt = a - λ·v diff --git a/src/gui/windows/graphics.zig b/src/gui/windows/graphics.zig index 224993883..77863b96f 100644 --- a/src/gui/windows/graphics.zig +++ b/src/gui/windows/graphics.zig @@ -98,6 +98,15 @@ fn resolutionScaleCallback(newValue: u16) void { main.Window.GLFWCallbacks.framebufferSize(null, main.Window.width, main.Window.height); } +fn viewBobbingCallback(newValue: f32) void { + settings.viewBobStrength = newValue; + settings.save(); +} + +fn viewBobbingFormatter(allocator: main.utils.NeverFailingAllocator, value: f32) []const u8 { + return std.fmt.allocPrint(allocator.allocator, "#ffffffView Bobbing Strength: {d:.2}", .{value}) catch unreachable; +} + pub fn onOpen() void { const list = VerticalList.init(.{padding, 16 + padding}, 300, 16); list.add(ContinuousSlider.init(.{0, 0}, 128, 10.0, 154.0, @floatFromInt(settings.fpsCap orelse 144), &fpsCapCallback, &fpsCapFormatter)); @@ -108,6 +117,7 @@ pub fn onOpen() void { list.add(CheckBox.init(.{0, 0}, 128, "Vertical Synchronization", settings.vsync, &vsyncCallback)); list.add(DiscreteSlider.init(.{0, 0}, 128, "#ffffffAnisotropic Filtering: ", "{}x", &anisotropy, switch(settings.anisotropicFiltering) {1 => 0, 2 => 1, 4 => 2, 8 => 3, 16 => 4, else => 2}, &anisotropicFilteringCallback)); list.add(DiscreteSlider.init(.{0, 0}, 128, "#ffffffResolution Scale: ", "{}%", &resolutions, @as(u16, @intFromFloat(@log2(settings.resolutionScale) + 2.0)), &resolutionScaleCallback)); + list.add(ContinuousSlider.init(.{0, 0}, 128, 0.0, 1.0, settings.viewBobStrength, &viewBobbingCallback, &viewBobbingFormatter)); list.finish(.center); window.rootComponent = list.toComponent(); window.contentSize = window.rootComponent.?.pos() + window.rootComponent.?.size() + @as(Vec2f, @splat(padding)); diff --git a/src/settings.zig b/src/settings.zig index d95bea448..253e50c56 100644 --- a/src/settings.zig +++ b/src/settings.zig @@ -44,6 +44,8 @@ pub var musicVolume: f32 = 1; pub var leavesQuality: u16 = 2; +pub var viewBobStrength: f32 = 0.5; + pub var storageTime: i64 = 5000; From 2ced0786b90940ea03849e179241976f14e20125 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Tue, 3 Sep 2024 21:44:05 +0100 Subject: [PATCH 02/21] Fixed crash/UB on walking backwards --- src/game.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game.zig b/src/game.zig index 2414a82a2..a880752b4 100644 --- a/src/game.zig +++ b/src/game.zig @@ -678,7 +678,7 @@ pub fn update(deltaTime: f64) void { // MARK: update() targetBobVel = vec.dot(movementDir * @as(Vec3d, @splat(std.math.log2(movementSpeed / 4 + 1))), forward); } Player.bobVel = Player.bobVel * (1 - fac) + targetBobVel * fac; - Player.bobTime += std.math.pow(f64, Player.bobVel, 0.7) * 8 * deltaTime; + Player.bobTime += std.math.pow(f64, @abs(Player.bobVel), 0.7) * std.math.sign(Player.bobVel) * 8 * deltaTime; } const bobStrength: f64 = Player.bobVel * 0.04 * settings.viewBobStrength; const xBob = std.math.cos(Player.bobTime); // Horizontal Component From 81b8e6c8f8c9a8db0491ee3512899d64c8b60cc5 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Tue, 3 Sep 2024 23:07:35 +0100 Subject: [PATCH 03/21] Reworked view bobbing to add rotation and more natural feel. --- src/game.zig | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/game.zig b/src/game.zig index a880752b4..f38f3aefa 100644 --- a/src/game.zig +++ b/src/game.zig @@ -41,8 +41,12 @@ pub const camera = struct { // MARK: camera } pub fn updateViewMatrix() void { - direction = vec.rotateZ(vec.rotateX(Vec3f{0, 1, 0}, -rotation[0]), -rotation[2]); - viewMatrix = Mat4f.identity().mul(Mat4f.rotationX(rotation[0])).mul(Mat4f.rotationZ(rotation[2])); + const bobStrength = @min(@abs(Player.bobVel) / 4, 1); + const xRot: f32 = @floatCast(rotation[0] + @cos(Player.bobTime + 0.20) * -0.005 * bobStrength); + const yRot: f32 = @floatCast(@sin(Player.bobTime) * 0.003 * bobStrength); + const zRot: f32 = rotation[2]; + direction = vec.rotateZ(vec.rotateY(vec.rotateX(Vec3f{0, 1, 0}, -xRot), -yRot), -zRot); + viewMatrix = Mat4f.identity().mul(Mat4f.rotationX(xRot)).mul(Mat4f.rotationY(yRot)).mul(Mat4f.rotationZ(zRot)); } }; @@ -680,9 +684,9 @@ pub fn update(deltaTime: f64) void { // MARK: update() Player.bobVel = Player.bobVel * (1 - fac) + targetBobVel * fac; Player.bobTime += std.math.pow(f64, @abs(Player.bobVel), 0.7) * std.math.sign(Player.bobVel) * 8 * deltaTime; } - const bobStrength: f64 = Player.bobVel * 0.04 * settings.viewBobStrength; - const xBob = std.math.cos(Player.bobTime); // Horizontal Component - const zBob = std.math.pow(f64, std.math.sin(Player.bobTime), 2) * 1.5; // Vertical Component + const bobStrength: f64 = @min(@abs(Player.bobVel) / 4, 1) * 0.3 * settings.viewBobStrength; + const xBob = @sin(Player.bobTime) * 0.5; // Horizontal Component + const zBob = -@abs(@cos(Player.bobTime)); // Vertical Component Player.bobVec = vec.rotateZ(Vec3d{ xBob * bobStrength, 0, zBob * bobStrength }, -camera.rotation[2]); // This our model for movement on a single frame: From 8a3efbd2dde7ac265292b35e91094d34ca10bd45 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Tue, 3 Sep 2024 23:23:42 +0100 Subject: [PATCH 04/21] Fixed tabs/spaces formatting --- src/game.zig | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/game.zig b/src/game.zig index f38f3aefa..24ec5aeae 100644 --- a/src/game.zig +++ b/src/game.zig @@ -299,9 +299,9 @@ pub const Player = struct { // MARK: Player pub var eyePos: Vec3d = .{0, 0, 0}; pub var eyeVel: Vec3d = .{0, 0, 0}; pub var eyeStep: @Vector(3, bool) = .{false, false, false}; - pub var bobTime: f64 = 0; - pub var bobVel: f64 = 0; - pub var bobVec: Vec3d = .{0, 0, 0}; + pub var bobTime: f64 = 0; + pub var bobVel: f64 = 0; + pub var bobVec: Vec3d = .{0, 0, 0}; pub var id: u32 = 0; pub var isFlying: Atomic(bool) = Atomic(bool).init(false); pub var isGhost: Atomic(bool) = Atomic(bool).init(false); @@ -672,22 +672,22 @@ pub fn update(deltaTime: f64) void { // MARK: update() Player.selectedSlot = @intCast(@mod(newSlot, 12)); main.Window.scrollOffset = 0; } - - // View Bobbing - if (Player.onGround) { // No view bobbing in the air - // Smooth lerping of bobTime with framerate independent damping - const fac: f64 = 1 - std.math.exp(-10 * deltaTime); - var targetBobVel: f64 = 0; - if (movementSpeed > 0) { - targetBobVel = vec.dot(movementDir * @as(Vec3d, @splat(std.math.log2(movementSpeed / 4 + 1))), forward); - } - Player.bobVel = Player.bobVel * (1 - fac) + targetBobVel * fac; - Player.bobTime += std.math.pow(f64, @abs(Player.bobVel), 0.7) * std.math.sign(Player.bobVel) * 8 * deltaTime; - } - const bobStrength: f64 = @min(@abs(Player.bobVel) / 4, 1) * 0.3 * settings.viewBobStrength; - const xBob = @sin(Player.bobTime) * 0.5; // Horizontal Component - const zBob = -@abs(@cos(Player.bobTime)); // Vertical Component - Player.bobVec = vec.rotateZ(Vec3d{ xBob * bobStrength, 0, zBob * bobStrength }, -camera.rotation[2]); + + // View Bobbing + if (Player.onGround) { // No view bobbing in the air + // Smooth lerping of bobTime with framerate independent damping + const fac: f64 = 1 - std.math.exp(-10 * deltaTime); + var targetBobVel: f64 = 0; + if (movementSpeed > 0) { + targetBobVel = vec.dot(movementDir * @as(Vec3d, @splat(std.math.log2(movementSpeed / 4 + 1))), forward); + } + Player.bobVel = Player.bobVel * (1 - fac) + targetBobVel * fac; + Player.bobTime += std.math.pow(f64, @abs(Player.bobVel), 0.7) * std.math.sign(Player.bobVel) * 8 * deltaTime; + } + const bobStrength: f64 = @min(@abs(Player.bobVel) / 4, 1) * 0.3 * settings.viewBobStrength; + const xBob = @sin(Player.bobTime) * 0.5; // Horizontal Component + const zBob = -@abs(@cos(Player.bobTime)); // Vertical Component + Player.bobVec = vec.rotateZ(Vec3d{ xBob * bobStrength, 0, zBob * bobStrength }, -camera.rotation[2]); // This our model for movement on a single frame: // dv/dt = a - λ·v From f1b407a101228a6826c94bd899f59ce5d627e133 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Wed, 4 Sep 2024 02:25:38 +0100 Subject: [PATCH 05/21] Rotation of viewbob now affected by strength setting --- src/game.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/game.zig b/src/game.zig index 24ec5aeae..755a7e812 100644 --- a/src/game.zig +++ b/src/game.zig @@ -41,9 +41,9 @@ pub const camera = struct { // MARK: camera } pub fn updateViewMatrix() void { - const bobStrength = @min(@abs(Player.bobVel) / 4, 1); - const xRot: f32 = @floatCast(rotation[0] + @cos(Player.bobTime + 0.20) * -0.005 * bobStrength); - const yRot: f32 = @floatCast(@sin(Player.bobTime) * 0.003 * bobStrength); + const bobStrength = @min(@abs(Player.bobVel) / 4, 1) * settings.viewBobStrength; + const xRot: f32 = @floatCast(rotation[0] + @cos(Player.bobTime + 0.20) * -0.008 * bobStrength); + const yRot: f32 = @floatCast(@sin(Player.bobTime) * 0.005 * bobStrength); const zRot: f32 = rotation[2]; direction = vec.rotateZ(vec.rotateY(vec.rotateX(Vec3f{0, 1, 0}, -xRot), -yRot), -zRot); viewMatrix = Mat4f.identity().mul(Mat4f.rotationX(xRot)).mul(Mat4f.rotationY(yRot)).mul(Mat4f.rotationZ(zRot)); From 955b0ed88db9bb567ca0b3d1f1479222591c84b6 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Thu, 5 Sep 2024 17:15:46 +0100 Subject: [PATCH 06/21] Reworked view bobbing to not affect selected block. --- src/game.zig | 50 +++++++++++++++++++++++++++++------------------- src/main.zig | 2 +- src/renderer.zig | 43 ++++++++++++++++++++++++++--------------- 3 files changed, 59 insertions(+), 36 deletions(-) diff --git a/src/game.zig b/src/game.zig index 755a7e812..a20823818 100644 --- a/src/game.zig +++ b/src/game.zig @@ -41,12 +41,8 @@ pub const camera = struct { // MARK: camera } pub fn updateViewMatrix() void { - const bobStrength = @min(@abs(Player.bobVel) / 4, 1) * settings.viewBobStrength; - const xRot: f32 = @floatCast(rotation[0] + @cos(Player.bobTime + 0.20) * -0.008 * bobStrength); - const yRot: f32 = @floatCast(@sin(Player.bobTime) * 0.005 * bobStrength); - const zRot: f32 = rotation[2]; - direction = vec.rotateZ(vec.rotateY(vec.rotateX(Vec3f{0, 1, 0}, -xRot), -yRot), -zRot); - viewMatrix = Mat4f.identity().mul(Mat4f.rotationX(xRot)).mul(Mat4f.rotationY(yRot)).mul(Mat4f.rotationZ(zRot)); + direction = vec.rotateZ(vec.rotateY(vec.rotateX(Vec3f{0, 1, 0}, -rotation[0]), -rotation[1]), -rotation[2]); + viewMatrix = Mat4f.identity().mul(Mat4f.rotationX(rotation[0])).mul(Mat4f.rotationY(rotation[1])).mul(Mat4f.rotationZ(rotation[2])); } }; @@ -301,7 +297,7 @@ pub const Player = struct { // MARK: Player pub var eyeStep: @Vector(3, bool) = .{false, false, false}; pub var bobTime: f64 = 0; pub var bobVel: f64 = 0; - pub var bobVec: Vec3d = .{0, 0, 0}; + pub var bobMag: f64 = 0; pub var id: u32 = 0; pub var isFlying: Atomic(bool) = Atomic(bool).init(false); pub var isGhost: Atomic(bool) = Atomic(bool).init(false); @@ -349,7 +345,24 @@ pub const Player = struct { // MARK: Player pub fn getEyePosBlocking() Vec3d { mutex.lock(); defer mutex.unlock(); - return eyePos + super.pos + desiredEyePos + bobVec; + return eyePos + super.pos + desiredEyePos; + } + + pub fn applyViewBobbingPosBlocking(pos: Vec3d) Vec3d { + mutex.lock(); + defer mutex.unlock(); + const xBob = @sin(bobTime) * 0.5 * 0.05; // Horizontal Component + const zBob = -@abs(@cos(bobTime)) * 0.05; // Vertical Component + const bobVec = vec.rotateZ(Vec3d{ xBob * bobMag, 0, zBob * bobMag }, -camera.rotation[2]); + return pos + bobVec; + } + + pub fn applyViewBobbingRotBlocking(rot: Vec3f) Vec3f { + mutex.lock(); + defer mutex.unlock(); + const xRot: f32 = @as(f32, @floatCast(@cos(bobTime + 0.20) * -0.005 * bobMag)); + const yRot: f32 = @as(f32, @floatCast(@sin(bobTime) * 0.003 * bobMag)); + return rot + Vec3f{ xRot, yRot, 0 }; } pub fn getVelBlocking() Vec3d { @@ -674,20 +687,17 @@ pub fn update(deltaTime: f64) void { // MARK: update() } // View Bobbing + // Smooth lerping of bobTime with framerate independent damping + const fac: f64 = 1 - std.math.exp(-10 * deltaTime); + var targetBobVel: f64 = 0; + if (movementSpeed > 0) { + targetBobVel = vec.length(vec.xy(Player.getVelBlocking()) * @as(vec.Vec2d, @splat(std.math.pow(f64, movementSpeed / 4, 0.7)))) / movementSpeed; + } + Player.bobVel = Player.bobVel * (1 - fac) + targetBobVel * fac; if (Player.onGround) { // No view bobbing in the air - // Smooth lerping of bobTime with framerate independent damping - const fac: f64 = 1 - std.math.exp(-10 * deltaTime); - var targetBobVel: f64 = 0; - if (movementSpeed > 0) { - targetBobVel = vec.dot(movementDir * @as(Vec3d, @splat(std.math.log2(movementSpeed / 4 + 1))), forward); - } - Player.bobVel = Player.bobVel * (1 - fac) + targetBobVel * fac; - Player.bobTime += std.math.pow(f64, @abs(Player.bobVel), 0.7) * std.math.sign(Player.bobVel) * 8 * deltaTime; + Player.bobTime += std.math.pow(f64, Player.bobVel, 0.7) * 8 * deltaTime; } - const bobStrength: f64 = @min(@abs(Player.bobVel) / 4, 1) * 0.3 * settings.viewBobStrength; - const xBob = @sin(Player.bobTime) * 0.5; // Horizontal Component - const zBob = -@abs(@cos(Player.bobTime)); // Vertical Component - Player.bobVec = vec.rotateZ(Vec3d{ xBob * bobStrength, 0, zBob * bobStrength }, -camera.rotation[2]); + Player.bobMag = @min(@sqrt(Player.bobVel), 2) * settings.viewBobStrength; // This our model for movement on a single frame: // dv/dt = a - λ·v diff --git a/src/main.zig b/src/main.zig index 9f6207c27..e05983db1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -512,7 +512,7 @@ pub fn main() void { // MARK: main() if(!isHidden) { c.glEnable(c.GL_CULL_FACE); c.glEnable(c.GL_DEPTH_TEST); - renderer.render(game.Player.getEyePosBlocking()); + renderer.render(); // Render the GUI gui.windowlist.gpu_performance_measuring.startQuery(.gui); c.glDisable(c.GL_CULL_FACE); diff --git a/src/renderer.zig b/src/renderer.zig index faa7e572f..5aef1b138 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -121,8 +121,7 @@ pub fn updateViewport(width: u31, height: u31, fov: f32) void { worldFrameBuffer.unbind(); } -pub fn render(playerPosition: Vec3d) void { - // TODO: player bobbing +pub fn render() void { if(game.world) |world| { // TODO: Handle colors and sun position in the world. var ambient: Vec3f = undefined; @@ -132,7 +131,7 @@ pub fn render(playerPosition: Vec3d) void { const skyColor = vec.xyz(world.clearColor); game.fog.skyColor = skyColor; - renderWorld(world, ambient, skyColor, playerPosition); + renderWorld(world, ambient, skyColor); const startTime = std.time.milliTimestamp(); mesh_storage.updateMeshes(startTime + maximumMeshTime); } else { @@ -164,12 +163,27 @@ pub fn crosshairDirection(rotationMatrix: Mat4f, fovY: f32, width: u31, height: return adjusted; } -pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPos: Vec3d) void { // MARK: renderWorld() +pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f) void { // MARK: renderWorld() worldFrameBuffer.bind(); c.glViewport(0, 0, lastWidth, lastHeight); gpu_performance_measuring.startQuery(.clear); worldFrameBuffer.clear(Vec4f{skyColor[0], skyColor[1], skyColor[2], 1}); gpu_performance_measuring.stopQuery(); + + const playerPos = game.Player.getEyePosBlocking(); + const playerRot = game.camera.rotation; + const cameraPos = game.Player.applyViewBobbingPosBlocking(playerPos); + const cameraRot = game.Player.applyViewBobbingRotBlocking(playerRot); + + // Get view matrix before view bobbing is applied + game.camera.updateViewMatrix(); + const baseViewMatrix = game.camera.viewMatrix; + + const oldCameraRot = game.camera.rotation; + defer game.camera.rotation = oldCameraRot; + game.camera.rotation = cameraRot; + + // View matrix after view bobbing is applied game.camera.updateViewMatrix(); // Uses FrustumCulling on the chunks. @@ -181,10 +195,9 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo gpu_performance_measuring.startQuery(.animation); blocks.meshes.preProcessAnimationData(time); gpu_performance_measuring.stopQuery(); - // Update the uniforms. The uniforms are needed to render the replacement meshes. - chunk_meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight, playerPos); + chunk_meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight, cameraPos); c.glActiveTexture(c.GL_TEXTURE0); blocks.meshes.blockTextureArray.bind(); @@ -199,9 +212,9 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo const meshes = mesh_storage.updateAndGetRenderChunks(world.conn, playerPos, settings.renderDistance); gpu_performance_measuring.startQuery(.chunk_rendering_preparation); - const direction = crosshairDirection(game.camera.viewMatrix, lastFov, lastWidth, lastHeight); + const direction = crosshairDirection(baseViewMatrix, lastFov, lastWidth, lastHeight); MeshSelection.select(playerPos, direction, game.Player.inventory__SEND_CHANGES_TO_SERVER.items[game.Player.selectedSlot]); - MeshSelection.render(game.projectionMatrix, game.camera.viewMatrix, playerPos); + MeshSelection.render(game.projectionMatrix, game.camera.viewMatrix, cameraPos); chunk_meshing.beginRender(); @@ -212,13 +225,13 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo } gpu_performance_measuring.stopQuery(); if(chunkList.items.len != 0) { - chunk_meshing.drawChunksIndirect(chunkList.items, game.projectionMatrix, ambientLight, playerPos, false); + chunk_meshing.drawChunksIndirect(chunkList.items, game.projectionMatrix, ambientLight, cameraPos, false); } gpu_performance_measuring.startQuery(.entity_rendering); - entity.ClientEntityManager.render(game.projectionMatrix, ambientLight, .{1, 0.5, 0.25}, playerPos); + entity.ClientEntityManager.render(game.projectionMatrix, ambientLight, .{1, 0.5, 0.25}, cameraPos); - itemdrop.ItemDropRenderer.renderItemDrops(game.projectionMatrix, ambientLight, playerPos, time); + itemdrop.ItemDropRenderer.renderItemDrops(game.projectionMatrix, ambientLight, cameraPos, time); gpu_performance_measuring.stopQuery(); // Render transparent chunk meshes: @@ -237,11 +250,11 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo while(true) { if(i == 0) break; i -= 1; - meshes[i].prepareTransparentRendering(playerPos, &chunkList); + meshes[i].prepareTransparentRendering(cameraPos, &chunkList); } gpu_performance_measuring.stopQuery(); if(chunkList.items.len != 0) { - chunk_meshing.drawChunksIndirect(chunkList.items, game.projectionMatrix, ambientLight, playerPos, true); + chunk_meshing.drawChunksIndirect(chunkList.items, game.projectionMatrix, ambientLight, cameraPos, true); } } c.glDepthMask(c.GL_TRUE); @@ -287,7 +300,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0); - entity.ClientEntityManager.renderNames(game.projectionMatrix, playerPos); + entity.ClientEntityManager.renderNames(game.projectionMatrix, cameraPos); gpu_performance_measuring.stopQuery(); } @@ -556,7 +569,7 @@ pub const MenuBackGround = struct { // Draw to frame buffer. buffer.bind(); c.glClear(c.GL_DEPTH_BUFFER_BIT | c.GL_STENCIL_BUFFER_BIT | c.GL_COLOR_BUFFER_BIT); - main.renderer.render(game.Player.getEyePosBlocking()); + main.renderer.render(); // Copy the pixels directly from OpenGL buffer.bind(); c.glReadPixels(0, 0, size, size, c.GL_RGBA, c.GL_UNSIGNED_BYTE, pixels.ptr); From 40802d39b6b1e55bc4857820937d2b2d4e34f751 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Tue, 10 Sep 2024 00:42:39 +0100 Subject: [PATCH 07/21] Updated view bobbing to feel less like limping --- src/game.zig | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/game.zig b/src/game.zig index a20823818..c74749a2b 100644 --- a/src/game.zig +++ b/src/game.zig @@ -351,8 +351,8 @@ pub const Player = struct { // MARK: Player pub fn applyViewBobbingPosBlocking(pos: Vec3d) Vec3d { mutex.lock(); defer mutex.unlock(); - const xBob = @sin(bobTime) * 0.5 * 0.05; // Horizontal Component - const zBob = -@abs(@cos(bobTime)) * 0.05; // Vertical Component + const xBob = @sin(bobTime) * 0.5 * 0.07; // Horizontal Component + const zBob = -@abs(@cos(bobTime)) * 0.07; // Vertical Component const bobVec = vec.rotateZ(Vec3d{ xBob * bobMag, 0, zBob * bobMag }, -camera.rotation[2]); return pos + bobVec; } @@ -360,9 +360,10 @@ pub const Player = struct { // MARK: Player pub fn applyViewBobbingRotBlocking(rot: Vec3f) Vec3f { mutex.lock(); defer mutex.unlock(); - const xRot: f32 = @as(f32, @floatCast(@cos(bobTime + 0.20) * -0.005 * bobMag)); - const yRot: f32 = @as(f32, @floatCast(@sin(bobTime) * 0.003 * bobMag)); - return rot + Vec3f{ xRot, yRot, 0 }; + const xRot: f32 = @as(f32, @floatCast(@cos(bobTime * 1.5 + 0.20) * -0.002 * bobMag)); + const yRot: f32 = @as(f32, @floatCast(@sin(bobTime * 1.5) * 0.002 * bobMag)); + const zRot: f32 = @as(f32, @floatCast(@sin(bobTime * 0.75 + 0.5) * 0.001 * bobMag)); + return rot + Vec3f{ xRot, yRot, zRot }; } pub fn getVelBlocking() Vec3d { From 505bb4c87c9a0fdffbcafd0038395af3662e59a4 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Tue, 10 Sep 2024 00:54:18 +0100 Subject: [PATCH 08/21] Fixed minor bug where player was still on ground when in ghost mode --- src/game.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/game.zig b/src/game.zig index c74749a2b..28405334e 100644 --- a/src/game.zig +++ b/src/game.zig @@ -930,6 +930,7 @@ pub fn update(deltaTime: f64) void { // MARK: update() } } else { Player.super.pos += move; + Player.onGround = false; } // Clamp the eyePosition: From 9d1ac239e6106f239adf95e44236de935d0fb69f Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Tue, 10 Sep 2024 17:33:15 +0100 Subject: [PATCH 09/21] Limited maximum bobbing strength and removed roll --- src/game.zig | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/game.zig b/src/game.zig index 28405334e..3a499ead2 100644 --- a/src/game.zig +++ b/src/game.zig @@ -352,7 +352,7 @@ pub const Player = struct { // MARK: Player mutex.lock(); defer mutex.unlock(); const xBob = @sin(bobTime) * 0.5 * 0.07; // Horizontal Component - const zBob = -@abs(@cos(bobTime)) * 0.07; // Vertical Component + const zBob = (-0.5 + @abs(@cos(bobTime))) * 0.07; // Vertical Component const bobVec = vec.rotateZ(Vec3d{ xBob * bobMag, 0, zBob * bobMag }, -camera.rotation[2]); return pos + bobVec; } @@ -361,9 +361,8 @@ pub const Player = struct { // MARK: Player mutex.lock(); defer mutex.unlock(); const xRot: f32 = @as(f32, @floatCast(@cos(bobTime * 1.5 + 0.20) * -0.002 * bobMag)); - const yRot: f32 = @as(f32, @floatCast(@sin(bobTime * 1.5) * 0.002 * bobMag)); const zRot: f32 = @as(f32, @floatCast(@sin(bobTime * 0.75 + 0.5) * 0.001 * bobMag)); - return rot + Vec3f{ xRot, yRot, zRot }; + return rot + Vec3f{ xRot, 0, zRot }; } pub fn getVelBlocking() Vec3d { @@ -692,13 +691,13 @@ pub fn update(deltaTime: f64) void { // MARK: update() const fac: f64 = 1 - std.math.exp(-10 * deltaTime); var targetBobVel: f64 = 0; if (movementSpeed > 0) { - targetBobVel = vec.length(vec.xy(Player.getVelBlocking()) * @as(vec.Vec2d, @splat(std.math.pow(f64, movementSpeed / 4, 0.7)))) / movementSpeed; + targetBobVel = vec.length(vec.xy(Player.getVelBlocking()) * @as(vec.Vec2d, @splat(std.math.pow(f64, movementSpeed / 4, 0.5)))) / movementSpeed; } Player.bobVel = Player.bobVel * (1 - fac) + targetBobVel * fac; if (Player.onGround) { // No view bobbing in the air - Player.bobTime += std.math.pow(f64, Player.bobVel, 0.7) * 8 * deltaTime; + Player.bobTime += std.math.pow(f64, Player.bobVel, 0.9) * 8 * deltaTime; } - Player.bobMag = @min(@sqrt(Player.bobVel), 2) * settings.viewBobStrength; + Player.bobMag = @min(@sqrt(Player.bobVel), 1.2) * settings.viewBobStrength; // This our model for movement on a single frame: // dv/dt = a - λ·v From 9111b2b0a9ba4e15c71fefc53e39ec2e39524356 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Tue, 10 Sep 2024 20:53:54 +0100 Subject: [PATCH 10/21] Reverted from 'n' shape to 'u' shape motion view bobbing --- src/game.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game.zig b/src/game.zig index 3a499ead2..98f5e6afa 100644 --- a/src/game.zig +++ b/src/game.zig @@ -352,7 +352,7 @@ pub const Player = struct { // MARK: Player mutex.lock(); defer mutex.unlock(); const xBob = @sin(bobTime) * 0.5 * 0.07; // Horizontal Component - const zBob = (-0.5 + @abs(@cos(bobTime))) * 0.07; // Vertical Component + const zBob = (0.5 - @abs(@cos(bobTime))) * 0.07; // Vertical Component const bobVec = vec.rotateZ(Vec3d{ xBob * bobMag, 0, zBob * bobMag }, -camera.rotation[2]); return pos + bobVec; } From 3e63eb5822fdb8e788a2b783bbd5e7347f510b00 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Tue, 10 Sep 2024 23:18:05 +0100 Subject: [PATCH 11/21] View bobbing based on https://www.desmos.com/calculator/y7sbbltnmf --- src/game.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game.zig b/src/game.zig index 98f5e6afa..7f5ca115b 100644 --- a/src/game.zig +++ b/src/game.zig @@ -351,8 +351,8 @@ pub const Player = struct { // MARK: Player pub fn applyViewBobbingPosBlocking(pos: Vec3d) Vec3d { mutex.lock(); defer mutex.unlock(); - const xBob = @sin(bobTime) * 0.5 * 0.07; // Horizontal Component - const zBob = (0.5 - @abs(@cos(bobTime))) * 0.07; // Vertical Component + const xBob = (std.math.atan(0.25 * @sin(bobTime)) / std.math.atan(@as(f64, 0.25))) * 0.07; // Horizontal Component + const zBob = (std.math.atan(0.5 * @cos(2 * bobTime + std.math.pi * 0.5)) / std.math.atan(@as(f64, 0.5)) + 0.5 * std.math.pow(f64, @cos(bobTime + std.math.pi * 0.5), 2)) * 0.6 * 0.07; // Vertical Component const bobVec = vec.rotateZ(Vec3d{ xBob * bobMag, 0, zBob * bobMag }, -camera.rotation[2]); return pos + bobVec; } From c9b0c24a529719bb79eb891295ea96951f55a924 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Wed, 11 Sep 2024 13:29:09 +0100 Subject: [PATCH 12/21] View bobbing now based on actual velocity only, and adjusted bobbing motion. --- src/game.zig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/game.zig b/src/game.zig index 7f5ca115b..5e6fcabfc 100644 --- a/src/game.zig +++ b/src/game.zig @@ -352,7 +352,7 @@ pub const Player = struct { // MARK: Player mutex.lock(); defer mutex.unlock(); const xBob = (std.math.atan(0.25 * @sin(bobTime)) / std.math.atan(@as(f64, 0.25))) * 0.07; // Horizontal Component - const zBob = (std.math.atan(0.5 * @cos(2 * bobTime + std.math.pi * 0.5)) / std.math.atan(@as(f64, 0.5)) + 0.5 * std.math.pow(f64, @cos(bobTime + std.math.pi * 0.5), 2)) * 0.6 * 0.07; // Vertical Component + const zBob = (std.math.atan(0.5 * @cos(2 * bobTime + std.math.pi * 0.5)) / std.math.atan(@as(f64, 0.5)) + 0.5 * std.math.pow(f64, @cos(bobTime + std.math.pi * 0.5), 2)) * 0.8 * 0.07; // Vertical Component const bobVec = vec.rotateZ(Vec3d{ xBob * bobMag, 0, zBob * bobMag }, -camera.rotation[2]); return pos + bobVec; } @@ -360,8 +360,8 @@ pub const Player = struct { // MARK: Player pub fn applyViewBobbingRotBlocking(rot: Vec3f) Vec3f { mutex.lock(); defer mutex.unlock(); - const xRot: f32 = @as(f32, @floatCast(@cos(bobTime * 1.5 + 0.20) * -0.002 * bobMag)); - const zRot: f32 = @as(f32, @floatCast(@sin(bobTime * 0.75 + 0.5) * 0.001 * bobMag)); + const xRot: f32 = @as(f32, @floatCast(@cos(bobTime * 2 + 0.20) * -0.002 * bobMag)); + const zRot: f32 = @as(f32, @floatCast(@sin(bobTime + 0.5) * 0.001 * bobMag)); return rot + Vec3f{ xRot, 0, zRot }; } @@ -688,10 +688,10 @@ pub fn update(deltaTime: f64) void { // MARK: update() // View Bobbing // Smooth lerping of bobTime with framerate independent damping - const fac: f64 = 1 - std.math.exp(-10 * deltaTime); + const fac: f64 = 1 - std.math.exp(-15 * deltaTime); var targetBobVel: f64 = 0; if (movementSpeed > 0) { - targetBobVel = vec.length(vec.xy(Player.getVelBlocking()) * @as(vec.Vec2d, @splat(std.math.pow(f64, movementSpeed / 4, 0.5)))) / movementSpeed; + targetBobVel = std.math.pow(f64, vec.length(vec.xy(Player.getVelBlocking())) / 4, 0.5); } Player.bobVel = Player.bobVel * (1 - fac) + targetBobVel * fac; if (Player.onGround) { // No view bobbing in the air From bf826a6e37a474debb722fbafef8c7a6d83ddb26 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Wed, 11 Sep 2024 13:37:41 +0100 Subject: [PATCH 13/21] Adjusted bobbing slightly --- src/game.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/game.zig b/src/game.zig index 5e6fcabfc..30bf5a471 100644 --- a/src/game.zig +++ b/src/game.zig @@ -351,8 +351,8 @@ pub const Player = struct { // MARK: Player pub fn applyViewBobbingPosBlocking(pos: Vec3d) Vec3d { mutex.lock(); defer mutex.unlock(); - const xBob = (std.math.atan(0.25 * @sin(bobTime)) / std.math.atan(@as(f64, 0.25))) * 0.07; // Horizontal Component - const zBob = (std.math.atan(0.5 * @cos(2 * bobTime + std.math.pi * 0.5)) / std.math.atan(@as(f64, 0.5)) + 0.5 * std.math.pow(f64, @cos(bobTime + std.math.pi * 0.5), 2)) * 0.8 * 0.07; // Vertical Component + const xBob = (std.math.atan(0.25 * @sin(bobTime)) / std.math.atan(@as(f64, 0.25))) * 0.05; // Horizontal Component + const zBob = (std.math.atan(0.5 * @cos(2 * bobTime + std.math.pi * 0.5)) / std.math.atan(@as(f64, 0.5)) + 0.5 * std.math.pow(f64, @cos(bobTime + std.math.pi * 0.5), 2)) * 0.8 * 0.05; // Vertical Component const bobVec = vec.rotateZ(Vec3d{ xBob * bobMag, 0, zBob * bobMag }, -camera.rotation[2]); return pos + bobVec; } @@ -360,7 +360,7 @@ pub const Player = struct { // MARK: Player pub fn applyViewBobbingRotBlocking(rot: Vec3f) Vec3f { mutex.lock(); defer mutex.unlock(); - const xRot: f32 = @as(f32, @floatCast(@cos(bobTime * 2 + 0.20) * -0.002 * bobMag)); + const xRot: f32 = @as(f32, @floatCast(@cos(bobTime * 2 + 0.20) * -0.0015 * bobMag)); const zRot: f32 = @as(f32, @floatCast(@sin(bobTime + 0.5) * 0.001 * bobMag)); return rot + Vec3f{ xRot, 0, zRot }; } From 27b7930e87a69829905143f9c35b5c7c5556cec6 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Wed, 11 Sep 2024 16:17:14 +0100 Subject: [PATCH 14/21] Fixed minor issue with bobbing not centering when in air and stopping when still moving. --- src/game.zig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/game.zig b/src/game.zig index 30bf5a471..41404db56 100644 --- a/src/game.zig +++ b/src/game.zig @@ -690,8 +690,9 @@ pub fn update(deltaTime: f64) void { // MARK: update() // Smooth lerping of bobTime with framerate independent damping const fac: f64 = 1 - std.math.exp(-15 * deltaTime); var targetBobVel: f64 = 0; - if (movementSpeed > 0) { - targetBobVel = std.math.pow(f64, vec.length(vec.xy(Player.getVelBlocking())) / 4, 0.5); + const horizontalMovementSpeed = vec.length(vec.xy(Player.getVelBlocking())); + if (horizontalMovementSpeed > 0.01 and Player.onGround) { + targetBobVel = std.math.pow(f64, horizontalMovementSpeed / 4, 0.5); } Player.bobVel = Player.bobVel * (1 - fac) + targetBobVel * fac; if (Player.onGround) { // No view bobbing in the air From 9041c69d57b42ca37d405e35e5340aa7a7f8dca0 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Thu, 12 Sep 2024 01:02:42 +0100 Subject: [PATCH 15/21] Addressed Review Feedback (Trig identities + comments) --- src/game.zig | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/game.zig b/src/game.zig index 41404db56..509179a2f 100644 --- a/src/game.zig +++ b/src/game.zig @@ -351,9 +351,13 @@ pub const Player = struct { // MARK: Player pub fn applyViewBobbingPosBlocking(pos: Vec3d) Vec3d { mutex.lock(); defer mutex.unlock(); - const xBob = (std.math.atan(0.25 * @sin(bobTime)) / std.math.atan(@as(f64, 0.25))) * 0.05; // Horizontal Component - const zBob = (std.math.atan(0.5 * @cos(2 * bobTime + std.math.pi * 0.5)) / std.math.atan(@as(f64, 0.5)) + 0.5 * std.math.pow(f64, @cos(bobTime + std.math.pi * 0.5), 2)) * 0.8 * 0.05; // Vertical Component - const bobVec = vec.rotateZ(Vec3d{ xBob * bobMag, 0, zBob * bobMag }, -camera.rotation[2]); + // Horizontal Component - atan(0.25 * sin(bobTime)) / atan(0.25) + const xBob = 1.0204970377 * @sin(bobTime); + // Vertical Component (*0.8) - atan(0.5 * -sin(2 * bobTime)) / atan(0.5) + 0.5 * (-@sin(bobTime))^2 + const a = 0.5 * -@sin(2 * bobTime); + const b = -@sin(bobTime); + const zBob = ((a - a * a * a / 3) / 0.4636476090 + 0.5 * b * b) * 0.8; + const bobVec = vec.rotateZ(Vec3d{ xBob * bobMag * 0.05, 0, zBob * bobMag * 0.05 }, -camera.rotation[2]); return pos + bobVec; } @@ -685,20 +689,24 @@ pub fn update(deltaTime: f64) void { // MARK: update() Player.selectedSlot = @intCast(@mod(newSlot, 12)); main.Window.scrollOffset = 0; } - - // View Bobbing - // Smooth lerping of bobTime with framerate independent damping - const fac: f64 = 1 - std.math.exp(-15 * deltaTime); - var targetBobVel: f64 = 0; - const horizontalMovementSpeed = vec.length(vec.xy(Player.getVelBlocking())); - if (horizontalMovementSpeed > 0.01 and Player.onGround) { - targetBobVel = std.math.pow(f64, horizontalMovementSpeed / 4, 0.5); - } - Player.bobVel = Player.bobVel * (1 - fac) + targetBobVel * fac; - if (Player.onGround) { // No view bobbing in the air - Player.bobTime += std.math.pow(f64, Player.bobVel, 0.9) * 8 * deltaTime; + + { // View Bobbing + Player.mutex.lock(); + defer Player.mutex.unlock(); + var targetBobVel: f64 = 0; + const horizontalMovementSpeed = vec.length(vec.xy(Player.super.vel)); + if (horizontalMovementSpeed > 0.01 and Player.onGround) { + targetBobVel = @sqrt(horizontalMovementSpeed / 4); + } + // Smooth lerping of bobVel with framerate independent damping + const fac: f64 = 1 - std.math.exp(-15 * deltaTime); + Player.bobVel = Player.bobVel * (1 - fac) + targetBobVel * fac; + if (Player.onGround) { // No view bobbing in the air + Player.bobTime += Player.bobVel * 8 * deltaTime; + } + // Maximum magnitude when sprinting (2x walking speed) + Player.bobMag = @sqrt(@min(Player.bobVel, 2)) * settings.viewBobStrength; } - Player.bobMag = @min(@sqrt(Player.bobVel), 1.2) * settings.viewBobStrength; // This our model for movement on a single frame: // dv/dt = a - λ·v From eaee832b7113729cf62da54bf67cd2d1bb56b933 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Thu, 12 Sep 2024 01:17:11 +0100 Subject: [PATCH 16/21] View bobbing scales with player hitbox height --- src/game.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game.zig b/src/game.zig index 358763fb1..db0ee65c4 100644 --- a/src/game.zig +++ b/src/game.zig @@ -781,8 +781,8 @@ pub fn update(deltaTime: f64) void { // MARK: update() if (Player.onGround) { // No view bobbing in the air Player.bobTime += Player.bobVel * 8 * deltaTime; } - // Maximum magnitude when sprinting (2x walking speed) - Player.bobMag = @sqrt(@min(Player.bobVel, 2)) * settings.viewBobStrength; + // Maximum magnitude when sprinting (2x walking speed). Magnitude is scaled by player bounding box height + Player.bobMag = @sqrt(@min(Player.bobVel, 2)) * settings.viewBobStrength * Player.outerBoundingBoxExtent[2]; } // This our model for movement on a single frame: From a9e8cf3426924e750bb69fbbf5534c5837d30ae4 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Fri, 20 Sep 2024 23:16:27 +0100 Subject: [PATCH 17/21] Decoupled Camera from Player --- src/camera.zig | 85 ++++++++++++++++++++++++++++++++++ src/entity.zig | 4 +- src/game.zig | 67 ++------------------------- src/graphics.zig | 6 +-- src/graphics/Window.zig | 2 +- src/gui/gui.zig | 6 +-- src/gui/windows/workbench.zig | 2 +- src/itemdrop.zig | 2 +- src/main.zig | 1 + src/network.zig | 6 +-- src/renderer.zig | 56 +++++++++++----------- src/renderer/chunk_meshing.zig | 4 +- src/renderer/mesh_storage.zig | 2 +- 13 files changed, 134 insertions(+), 109 deletions(-) create mode 100644 src/camera.zig diff --git a/src/camera.zig b/src/camera.zig new file mode 100644 index 000000000..0e7c6e100 --- /dev/null +++ b/src/camera.zig @@ -0,0 +1,85 @@ +const std = @import("std"); + +const vec = @import("vec.zig"); +const Vec3f = vec.Vec3f; +const Vec4f = vec.Vec4f; +const Vec3d = vec.Vec3d; +const Mat4f = vec.Mat4f; +const game = @import("game.zig"); +const settings = @import("settings.zig"); + +// MARK: camera +// A zig file is implicitly a struct, so when importing we can have camera.position, camera.rotation, etc. +// instead of camera.camera.position, camera.camera.rotation, etc. +pub var position: Vec3d = Vec3d{0, 0, 0}; +pub var rotation: Vec3f = Vec3f{0, 0, 0}; +pub var direction: Vec3f = Vec3f{0, 0, 0}; +pub var viewMatrix: Mat4f = Mat4f.identity(); +pub fn moveRotation(mouseX: f32, mouseY: f32) void { + // Mouse movement along the y-axis rotates the image along the x-axis. + rotation[0] += mouseY; + if (rotation[0] > std.math.pi / 2.0) { + rotation[0] = std.math.pi / 2.0; + } else if (rotation[0] < -std.math.pi / 2.0) { + rotation[0] = -std.math.pi / 2.0; + } + // Mouse movement along the x-axis rotates the image along the z-axis. + rotation[2] += mouseX; +} + +pub fn updateViewMatrix() void { + direction = vec.rotateZ(vec.rotateY(vec.rotateX(Vec3f{0, 1, 0}, -rotation[0]), -rotation[1]), -rotation[2]); + viewMatrix = Mat4f.identity().mul(Mat4f.rotationX(rotation[0])).mul(Mat4f.rotationY(rotation[1])).mul(Mat4f.rotationZ(rotation[2])); +} + +pub const ViewBobbing = struct { // MARK: ViewBobber + var time: f64 = 0; + var velocity: f64 = 0; + var magnitude: f64 = 0; + + pub fn update(deltaTime: f64) void { + game.Player.mutex.lock(); + defer game.Player.mutex.unlock(); + var targetVelocity: f64 = 0; + const horizontalMovementSpeed = vec.length(vec.xy(game.Player.super.vel)); + if (horizontalMovementSpeed > 0.01 and game.Player.onGround) { + targetVelocity = @sqrt(horizontalMovementSpeed / 4); + } + // Smooth lerping of bobVel with framerate independent damping + const fac: f64 = 1 - std.math.exp(-15 * deltaTime); + velocity = velocity * (1 - fac) + targetVelocity * fac; + if (game.Player.onGround) { // No view bobbing in the air + time += velocity * 8 * deltaTime; + } + // Maximum magnitude when sprinting (2x walking speed). Magnitude is scaled by player bounding box height + magnitude = @sqrt(@min(velocity, 2)) * settings.viewBobStrength * game.Player.outerBoundingBoxExtent[2]; + } + + inline fn getPositionBobbing() Vec3d { + game.Player.mutex.lock(); + defer game.Player.mutex.unlock(); + const xBob = @sin(time); + const a = 0.5 * -@sin(2 * time); + const zBob = ((a - a * a * a / 3) * 2 + 0.25 - 0.25 * @cos(2 * time)) * 0.8; + const bobVec = vec.rotateZ(Vec3d{xBob * magnitude * 0.05, 0, zBob * magnitude * 0.05}, -rotation[2]); + return bobVec; + } + + inline fn getRotationBobbing() Vec3f { + game.Player.mutex.lock(); + defer game.Player.mutex.unlock(); + const xRot: f32 = @as(f32, @floatCast(@cos(time * 2 + 0.20) * -0.0015 * magnitude)); + const zRot: f32 = @as(f32, @floatCast(@sin(time + 0.5) * 0.001 * magnitude)); + return Vec3f{xRot, 0, zRot}; + } + + pub fn apply() void { + position += getPositionBobbing(); + rotation += getRotationBobbing(); + } + + pub fn remove() void { + position -= getPositionBobbing(); + rotation -= getRotationBobbing(); + } +}; diff --git a/src/entity.zig b/src/entity.zig index 2b196e652..eb4ada769 100644 --- a/src/entity.zig +++ b/src/entity.zig @@ -130,7 +130,7 @@ pub const ClientEntityManager = struct { 1, }; - const rotatedPos = game.camera.viewMatrix.mulVec(pos4f); + const rotatedPos = main.camera.viewMatrix.mulVec(pos4f); const projectedPos = projMatrix.mulVec(rotatedPos); if(projectedPos[2] < 0) continue; const xCenter = (1 + projectedPos[0]/projectedPos[3])*@as(f32, @floatFromInt(main.Window.width/2)); @@ -171,7 +171,7 @@ pub const ClientEntityManager = struct { @floatCast(pos[2]), })) ); - const modelViewMatrix = modelMatrix.mul(game.camera.viewMatrix); + const modelViewMatrix = modelMatrix.mul(main.camera.viewMatrix); c.glUniformMatrix4fv(uniforms.viewMatrix, 1, c.GL_TRUE, @ptrCast(&modelViewMatrix)); // TODO: c.glDrawElements(...); } diff --git a/src/game.zig b/src/game.zig index db0ee65c4..660256c4b 100644 --- a/src/game.zig +++ b/src/game.zig @@ -23,28 +23,7 @@ const models = main.models; const Fog = graphics.Fog; const renderer = @import("renderer.zig"); const settings = @import("settings.zig"); - -pub const camera = struct { // MARK: camera - pub var rotation: Vec3f = Vec3f{0, 0, 0}; - pub var direction: Vec3f = Vec3f{0, 0, 0}; - pub var viewMatrix: Mat4f = Mat4f.identity(); - pub fn moveRotation(mouseX: f32, mouseY: f32) void { - // Mouse movement along the y-axis rotates the image along the x-axis. - rotation[0] += mouseY; - if(rotation[0] > std.math.pi/2.0) { - rotation[0] = std.math.pi/2.0; - } else if(rotation[0] < -std.math.pi/2.0) { - rotation[0] = -std.math.pi/2.0; - } - // Mouse movement along the x-axis rotates the image along the z-axis. - rotation[2] += mouseX; - } - - pub fn updateViewMatrix() void { - direction = vec.rotateZ(vec.rotateY(vec.rotateX(Vec3f{0, 1, 0}, -rotation[0]), -rotation[1]), -rotation[2]); - viewMatrix = Mat4f.identity().mul(Mat4f.rotationX(rotation[0])).mul(Mat4f.rotationY(rotation[1])).mul(Mat4f.rotationZ(rotation[2])); - } -}; +const camera = @import("camera.zig"); pub const collision = struct { pub fn triangleAABB(triangle: [3]Vec3d, box_center: Vec3d, box_extents: Vec3d) bool { @@ -329,9 +308,6 @@ pub const Player = struct { // MARK: Player pub var eyeVel: Vec3d = .{0, 0, 0}; pub var eyeCoyote: f64 = 0; pub var eyeStep: @Vector(3, bool) = .{false, false, false}; - pub var bobTime: f64 = 0; - pub var bobVel: f64 = 0; - pub var bobMag: f64 = 0; pub var id: u32 = 0; pub var isFlying: Atomic(bool) = Atomic(bool).init(false); pub var isGhost: Atomic(bool) = Atomic(bool).init(false); @@ -388,27 +364,6 @@ pub const Player = struct { // MARK: Player return eyePos + super.pos + desiredEyePos; } - pub fn applyViewBobbingPosBlocking(pos: Vec3d) Vec3d { - mutex.lock(); - defer mutex.unlock(); - // Horizontal Component - atan(0.25 * sin(bobTime)) / atan(0.25) - const xBob = 1.0204970377 * @sin(bobTime); - // Vertical Component (*0.8) - atan(0.5 * -sin(2 * bobTime)) / atan(0.5) + 0.5 * (-@sin(bobTime))^2 - const a = 0.5 * -@sin(2 * bobTime); - const b = -@sin(bobTime); - const zBob = ((a - a * a * a / 3) / 0.4636476090 + 0.5 * b * b) * 0.8; - const bobVec = vec.rotateZ(Vec3d{ xBob * bobMag * 0.05, 0, zBob * bobMag * 0.05 }, -camera.rotation[2]); - return pos + bobVec; - } - - pub fn applyViewBobbingRotBlocking(rot: Vec3f) Vec3f { - mutex.lock(); - defer mutex.unlock(); - const xRot: f32 = @as(f32, @floatCast(@cos(bobTime * 2 + 0.20) * -0.0015 * bobMag)); - const zRot: f32 = @as(f32, @floatCast(@sin(bobTime + 0.5) * 0.001 * bobMag)); - return rot + Vec3f{ xRot, 0, zRot }; - } - pub fn getEyeVelBlocking() Vec3d { mutex.lock(); defer mutex.unlock(); @@ -767,23 +722,7 @@ pub fn update(deltaTime: f64) void { // MARK: update() main.Window.scrollOffset = 0; } - { // View Bobbing - Player.mutex.lock(); - defer Player.mutex.unlock(); - var targetBobVel: f64 = 0; - const horizontalMovementSpeed = vec.length(vec.xy(Player.super.vel)); - if (horizontalMovementSpeed > 0.01 and Player.onGround) { - targetBobVel = @sqrt(horizontalMovementSpeed / 4); - } - // Smooth lerping of bobVel with framerate independent damping - const fac: f64 = 1 - std.math.exp(-15 * deltaTime); - Player.bobVel = Player.bobVel * (1 - fac) + targetBobVel * fac; - if (Player.onGround) { // No view bobbing in the air - Player.bobTime += Player.bobVel * 8 * deltaTime; - } - // Maximum magnitude when sprinting (2x walking speed). Magnitude is scaled by player bounding box height - Player.bobMag = @sqrt(@min(Player.bobVel, 2)) * settings.viewBobStrength * Player.outerBoundingBoxExtent[2]; - } + camera.ViewBobbing.update(deltaTime); // This our model for movement on a single frame: // dv/dt = a - λ·v @@ -986,6 +925,8 @@ pub fn update(deltaTime: f64) void { // MARK: update() Player.eyePos = @max(Player.eyeBox.min, @min(Player.eyePos, Player.eyeBox.max)); Player.eyeCoyote -= deltaTime; + camera.position = Player.getEyePosBlocking(); + const biome = world.?.playerBiome.load(.monotonic); const t = 1 - @as(f32, @floatCast(@exp(-2 * deltaTime))); diff --git a/src/graphics.zig b/src/graphics.zig index 6a5bb586b..aed000d2d 100644 --- a/src/graphics.zig +++ b/src/graphics.zig @@ -1984,9 +1984,9 @@ pub fn generateBlockTexture(blockType: u16) Texture { } const projMatrix = Mat4f.perspective(0.013, 1, 64, 256); - const oldViewMatrix = main.game.camera.viewMatrix; - main.game.camera.viewMatrix = Mat4f.identity().mul(Mat4f.rotationX(std.math.pi/4.0)).mul(Mat4f.rotationZ(-5.0*std.math.pi/4.0)); - defer main.game.camera.viewMatrix = oldViewMatrix; + const oldViewMatrix = main.camera.viewMatrix; + main.camera.viewMatrix = Mat4f.identity().mul(Mat4f.rotationX(std.math.pi/4.0)).mul(Mat4f.rotationZ(-5.0*std.math.pi/4.0)); + defer main.camera.viewMatrix = oldViewMatrix; const uniforms = if(block.transparent()) &main.renderer.chunk_meshing.transparentUniforms else &main.renderer.chunk_meshing.uniforms; var faceData: main.ListUnmanaged(main.renderer.chunk_meshing.FaceData) = .{}; diff --git a/src/graphics/Window.zig b/src/graphics/Window.zig index 8cd73b508..7d18c6451 100644 --- a/src/graphics/Window.zig +++ b/src/graphics/Window.zig @@ -189,7 +189,7 @@ pub const GLFWCallbacks = struct { // MARK: GLFWCallbacks averagedDelta += delta; } averagedDelta /= @splat(deltasLen); - main.game.camera.moveRotation(averagedDelta[0]*0.0089, averagedDelta[1]*0.0089); + main.camera.moveRotation(averagedDelta[0]*0.0089, averagedDelta[1]*0.0089); deltaBufferPosition = (deltaBufferPosition + 1)%deltasLen; deltas[deltaBufferPosition] = Vec2f{0, 0}; } diff --git a/src/gui/gui.zig b/src/gui/gui.zig index 001d3fc4b..5c54833e8 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -568,7 +568,7 @@ pub fn toggleGameMenu() void { inventory.carriedItemStack.amount = main.game.Player.inventory__SEND_CHANGES_TO_SERVER.addItem(item, inventory.carriedItemStack.amount); main.network.Protocols.genericUpdate.sendInventory_full(main.game.world.?.conn, main.game.Player.inventory__SEND_CHANGES_TO_SERVER); // TODO(post-java): Add better options to the protocol. if(inventory.carriedItemStack.amount != 0) { - main.network.Protocols.genericUpdate.itemStackDrop(main.game.world.?.conn, inventory.carriedItemStack, @floatCast(main.game.Player.getPosBlocking()), main.game.camera.direction, 20); + main.network.Protocols.genericUpdate.itemStackDrop(main.game.world.?.conn, inventory.carriedItemStack, @floatCast(main.game.Player.getPosBlocking()), main.camera.direction, 20); } inventory.carriedItemStack.clear(); } @@ -678,10 +678,10 @@ pub const inventory = struct { // MARK: inventory } } else if(!hoveredAWindow) { if(leftClick or carriedItemStack.amount == 1) { - main.network.Protocols.genericUpdate.itemStackDrop(main.game.world.?.conn, carriedItemStack, @floatCast(main.game.Player.getPosBlocking()), main.game.camera.direction, 20); + main.network.Protocols.genericUpdate.itemStackDrop(main.game.world.?.conn, carriedItemStack, @floatCast(main.game.Player.getPosBlocking()), main.camera.direction, 20); carriedItemStack.clear(); } else if(carriedItemStack.amount != 0) { - main.network.Protocols.genericUpdate.itemStackDrop(main.game.world.?.conn, .{.item = carriedItemStack.item, .amount = 1}, @floatCast(main.game.Player.getPosBlocking()), main.game.camera.direction, 20); + main.network.Protocols.genericUpdate.itemStackDrop(main.game.world.?.conn, .{.item = carriedItemStack.item, .amount = 1}, @floatCast(main.game.Player.getPosBlocking()), main.camera.direction, 20); _ = carriedItemStack.add(carriedItemStack.item.?, @as(i32, -1)); } } diff --git a/src/gui/windows/workbench.zig b/src/gui/windows/workbench.zig index 55086b660..128f06831 100644 --- a/src/gui/windows/workbench.zig +++ b/src/gui/windows/workbench.zig @@ -164,7 +164,7 @@ pub fn onClose() void { if(!itemStack.empty()) { itemStack.amount = main.game.Player.inventory__SEND_CHANGES_TO_SERVER.addItem(itemStack.item.?, itemStack.amount); if(!itemStack.empty()) { - main.network.Protocols.genericUpdate.itemStackDrop(main.game.world.?.conn, itemStack.*, .{0, 0, 0}, main.game.camera.direction, 20); + main.network.Protocols.genericUpdate.itemStackDrop(main.game.world.?.conn, itemStack.*, .{0, 0, 0}, main.camera.direction, 20); itemStack.clear(); } } diff --git a/src/itemdrop.zig b/src/itemdrop.zig index be76f6404..7df1adc25 100644 --- a/src/itemdrop.zig +++ b/src/itemdrop.zig @@ -627,7 +627,7 @@ pub const ItemDropRenderer = struct { // MARK: ItemDropRenderer c.glUniform1i(itemUniforms.time, @as(u31, @truncate(time))); c.glUniformMatrix4fv(itemUniforms.projectionMatrix, 1, c.GL_TRUE, @ptrCast(&projMatrix)); c.glUniform3fv(itemUniforms.ambientLight, 1, @ptrCast(&ambientLight)); - c.glUniformMatrix4fv(itemUniforms.viewMatrix, 1, c.GL_TRUE, @ptrCast(&game.camera.viewMatrix)); + c.glUniformMatrix4fv(itemUniforms.viewMatrix, 1, c.GL_TRUE, @ptrCast(&main.camera.viewMatrix)); c.glUniform1f(itemUniforms.contrast, 0.12); const itemDrops = &game.world.?.itemDrops.super; itemDrops.mutex.lock(); diff --git a/src/main.zig b/src/main.zig index 6e99b0a0d..a10a674e1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -20,6 +20,7 @@ pub const random = @import("random.zig"); pub const renderer = @import("renderer.zig"); pub const rotation = @import("rotation.zig"); pub const settings = @import("settings.zig"); +pub const camera = @import("camera.zig"); pub const utils = @import("utils.zig"); pub const vec = @import("vec.zig"); diff --git a/src/network.zig b/src/network.zig index 1fde8e6ce..acdc42b31 100644 --- a/src/network.zig +++ b/src/network.zig @@ -863,9 +863,9 @@ pub const Protocols = struct { std.mem.writeInt(u64, data[24..32], @as(u64, @bitCast(playerVel[0])), .big); std.mem.writeInt(u64, data[32..40], @as(u64, @bitCast(playerVel[1])), .big); std.mem.writeInt(u64, data[40..48], @as(u64, @bitCast(playerVel[2])), .big); - std.mem.writeInt(u32, data[48..52], @as(u32, @bitCast(game.camera.rotation[0])), .big); - std.mem.writeInt(u32, data[52..56], @as(u32, @bitCast(game.camera.rotation[1])), .big); - std.mem.writeInt(u32, data[56..60], @as(u32, @bitCast(game.camera.rotation[2])), .big); + std.mem.writeInt(u32, data[48..52], @as(u32, @bitCast(main.camera.rotation[0])), .big); + std.mem.writeInt(u32, data[52..56], @as(u32, @bitCast(main.camera.rotation[1])), .big); + std.mem.writeInt(u32, data[56..60], @as(u32, @bitCast(main.camera.rotation[2])), .big); std.mem.writeInt(u16, data[60..62], time, .big); conn.sendUnimportant(id, &data); } diff --git a/src/renderer.zig b/src/renderer.zig index 5aef1b138..e4f3314a6 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -15,6 +15,7 @@ const Window = main.Window; const models = @import("models.zig"); const network = @import("network.zig"); const settings = @import("settings.zig"); +const camera = @import("camera.zig"); const vec = @import("vec.zig"); const gpu_performance_measuring = main.gui.windowlist.gpu_performance_measuring; const crosshair = main.gui.windowlist.crosshair; @@ -169,25 +170,22 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f) void { / gpu_performance_measuring.startQuery(.clear); worldFrameBuffer.clear(Vec4f{skyColor[0], skyColor[1], skyColor[2], 1}); gpu_performance_measuring.stopQuery(); - - const playerPos = game.Player.getEyePosBlocking(); - const playerRot = game.camera.rotation; - const cameraPos = game.Player.applyViewBobbingPosBlocking(playerPos); - const cameraRot = game.Player.applyViewBobbingRotBlocking(playerRot); - - // Get view matrix before view bobbing is applied - game.camera.updateViewMatrix(); - const baseViewMatrix = game.camera.viewMatrix; - const oldCameraRot = game.camera.rotation; - defer game.camera.rotation = oldCameraRot; - game.camera.rotation = cameraRot; + // Get camera data before view bobbing is applied + camera.updateViewMatrix(); + const lookMatrix = camera.viewMatrix; + const cameraPos = camera.position; + + camera.ViewBobbing.apply(); + defer camera.ViewBobbing.remove(); + + const viewPos = camera.position; // View matrix after view bobbing is applied - game.camera.updateViewMatrix(); + camera.updateViewMatrix(); // Uses FrustumCulling on the chunks. - const frustum = Frustum.init(Vec3f{0, 0, 0}, game.camera.viewMatrix, lastFov, lastWidth, lastHeight); + const frustum = Frustum.init(Vec3f{0, 0, 0}, camera.viewMatrix, lastFov, lastWidth, lastHeight); _ = frustum; const time: u32 = @intCast(std.time.milliTimestamp() & std.math.maxInt(u32)); @@ -197,7 +195,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f) void { / gpu_performance_measuring.stopQuery(); // Update the uniforms. The uniforms are needed to render the replacement meshes. - chunk_meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight, cameraPos); + chunk_meshing.bindShaderAndUniforms(game.projectionMatrix, ambientLight, viewPos); c.glActiveTexture(c.GL_TEXTURE0); blocks.meshes.blockTextureArray.bind(); @@ -209,12 +207,12 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f) void { / chunk_meshing.quadsDrawn = 0; chunk_meshing.transparentQuadsDrawn = 0; - const meshes = mesh_storage.updateAndGetRenderChunks(world.conn, playerPos, settings.renderDistance); + const meshes = mesh_storage.updateAndGetRenderChunks(world.conn, cameraPos, settings.renderDistance); gpu_performance_measuring.startQuery(.chunk_rendering_preparation); - const direction = crosshairDirection(baseViewMatrix, lastFov, lastWidth, lastHeight); - MeshSelection.select(playerPos, direction, game.Player.inventory__SEND_CHANGES_TO_SERVER.items[game.Player.selectedSlot]); - MeshSelection.render(game.projectionMatrix, game.camera.viewMatrix, cameraPos); + const direction = crosshairDirection(lookMatrix, lastFov, lastWidth, lastHeight); + MeshSelection.select(cameraPos, direction, game.Player.inventory__SEND_CHANGES_TO_SERVER.items[game.Player.selectedSlot]); + MeshSelection.render(game.projectionMatrix, camera.viewMatrix, viewPos); chunk_meshing.beginRender(); @@ -225,13 +223,13 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f) void { / } gpu_performance_measuring.stopQuery(); if(chunkList.items.len != 0) { - chunk_meshing.drawChunksIndirect(chunkList.items, game.projectionMatrix, ambientLight, cameraPos, false); + chunk_meshing.drawChunksIndirect(chunkList.items, game.projectionMatrix, ambientLight, viewPos, false); } gpu_performance_measuring.startQuery(.entity_rendering); - entity.ClientEntityManager.render(game.projectionMatrix, ambientLight, .{1, 0.5, 0.25}, cameraPos); + entity.ClientEntityManager.render(game.projectionMatrix, ambientLight, .{1, 0.5, 0.25}, viewPos); - itemdrop.ItemDropRenderer.renderItemDrops(game.projectionMatrix, ambientLight, cameraPos, time); + itemdrop.ItemDropRenderer.renderItemDrops(game.projectionMatrix, ambientLight, viewPos, time); gpu_performance_measuring.stopQuery(); // Render transparent chunk meshes: @@ -250,11 +248,11 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f) void { / while(true) { if(i == 0) break; i -= 1; - meshes[i].prepareTransparentRendering(cameraPos, &chunkList); + meshes[i].prepareTransparentRendering(viewPos, &chunkList); } gpu_performance_measuring.stopQuery(); if(chunkList.items.len != 0) { - chunk_meshing.drawChunksIndirect(chunkList.items, game.projectionMatrix, ambientLight, cameraPos, true); + chunk_meshing.drawChunksIndirect(chunkList.items, game.projectionMatrix, ambientLight, viewPos, true); } } c.glDepthMask(c.GL_TRUE); @@ -264,7 +262,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f) void { / worldFrameBuffer.bindTexture(c.GL_TEXTURE3); - const playerBlock = mesh_storage.getBlockFromAnyLod(@intFromFloat(@floor(playerPos[0])), @intFromFloat(@floor(playerPos[1])), @intFromFloat(@floor(playerPos[2]))); + const playerBlock = mesh_storage.getBlockFromAnyLod(@intFromFloat(@floor(cameraPos[0])), @intFromFloat(@floor(cameraPos[1])), @intFromFloat(@floor(cameraPos[2]))); if(settings.bloom) { Bloom.render(lastWidth, lastHeight, playerBlock); @@ -300,7 +298,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f) void { / c.glBindFramebuffer(c.GL_FRAMEBUFFER, 0); - entity.ClientEntityManager.renderNames(game.projectionMatrix, cameraPos); + entity.ClientEntityManager.renderNames(game.projectionMatrix, viewPos); gpu_performance_measuring.stopQuery(); } @@ -553,8 +551,8 @@ pub const MenuBackGround = struct { activeFrameBuffer = buffer.frameBuffer; defer activeFrameBuffer = 0; - const oldRotation = game.camera.rotation; - defer game.camera.rotation = oldRotation; + const oldRotation = camera.rotation; + defer camera.rotation = oldRotation; const angles = [_]f32 {std.math.pi/2.0, std.math.pi, std.math.pi*3/2.0, std.math.pi*2}; @@ -565,7 +563,7 @@ pub const MenuBackGround = struct { for(0..4) |i| { c.glEnable(c.GL_CULL_FACE); c.glEnable(c.GL_DEPTH_TEST); - game.camera.rotation = .{0, 0, angles[i]}; + camera.rotation = .{0, 0, angles[i]}; // Draw to frame buffer. buffer.bind(); c.glClear(c.GL_DEPTH_BUFFER_BIT | c.GL_STENCIL_BUFFER_BIT | c.GL_COLOR_BUFFER_BIT); diff --git a/src/renderer/chunk_meshing.zig b/src/renderer/chunk_meshing.zig index 73c33367c..e0f01331d 100644 --- a/src/renderer/chunk_meshing.zig +++ b/src/renderer/chunk_meshing.zig @@ -140,7 +140,7 @@ fn bindCommonUniforms(locations: *UniformStruct, projMatrix: Mat4f, ambient: Vec c.glUniform1f(locations.contrast, 0.12); - c.glUniformMatrix4fv(locations.viewMatrix, 1, c.GL_TRUE, @ptrCast(&game.camera.viewMatrix)); + c.glUniformMatrix4fv(locations.viewMatrix, 1, c.GL_TRUE, @ptrCast(&main.camera.viewMatrix)); c.glUniform3f(locations.ambientLight, ambient[0], ambient[1], ambient[2]); @@ -205,7 +205,7 @@ pub fn drawChunksIndirect(chunkIDs: []const u32, projMatrix: Mat4f, ambient: Vec c.glUniform3i(occlusionTestUniforms.playerPositionInteger, @intFromFloat(@floor(playerPos[0])), @intFromFloat(@floor(playerPos[1])), @intFromFloat(@floor(playerPos[2]))); c.glUniform3f(occlusionTestUniforms.playerPositionFraction, @floatCast(@mod(playerPos[0], 1)), @floatCast(@mod(playerPos[1], 1)), @floatCast(@mod(playerPos[2], 1))); c.glUniformMatrix4fv(occlusionTestUniforms.projectionMatrix, 1, c.GL_TRUE, @ptrCast(&projMatrix)); - c.glUniformMatrix4fv(occlusionTestUniforms.viewMatrix, 1, c.GL_TRUE, @ptrCast(&game.camera.viewMatrix)); + c.glUniformMatrix4fv(occlusionTestUniforms.viewMatrix, 1, c.GL_TRUE, @ptrCast(&main.camera.viewMatrix)); c.glDepthMask(c.GL_FALSE); c.glColorMask(c.GL_FALSE, c.GL_FALSE, c.GL_FALSE, c.GL_FALSE); c.glBindVertexArray(vao); diff --git a/src/renderer/mesh_storage.zig b/src/renderer/mesh_storage.zig index 2dbd7b390..d6aafa9cc 100644 --- a/src/renderer/mesh_storage.zig +++ b/src/renderer/mesh_storage.zig @@ -615,7 +615,7 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, playerPos: V } var nodeList = main.List(*ChunkMeshNode).init(main.stackAllocator); defer nodeList.deinit(); - const projRotMat = game.projectionMatrix.mul(game.camera.viewMatrix); + const projRotMat = game.projectionMatrix.mul(main.camera.viewMatrix); while(searchList.removeOrNull()) |data| { nodeList.append(data.node); data.node.active = false; From 67be3101910231de9e3c4dd38d19796fb5d61bf9 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Fri, 20 Sep 2024 23:36:41 +0100 Subject: [PATCH 18/21] Removed unnecessary comment --- src/camera.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/camera.zig b/src/camera.zig index 0e7c6e100..9df2b7023 100644 --- a/src/camera.zig +++ b/src/camera.zig @@ -9,8 +9,6 @@ const game = @import("game.zig"); const settings = @import("settings.zig"); // MARK: camera -// A zig file is implicitly a struct, so when importing we can have camera.position, camera.rotation, etc. -// instead of camera.camera.position, camera.camera.rotation, etc. pub var position: Vec3d = Vec3d{0, 0, 0}; pub var rotation: Vec3f = Vec3f{0, 0, 0}; pub var direction: Vec3f = Vec3f{0, 0, 0}; From ffd36e7c85a0460d0c1502e1fd05056a70127f67 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Sat, 21 Sep 2024 17:47:43 +0100 Subject: [PATCH 19/21] Fixed issue with background screenshot seams --- src/camera.zig | 3 +++ src/renderer.zig | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/camera.zig b/src/camera.zig index 9df2b7023..bd055a62b 100644 --- a/src/camera.zig +++ b/src/camera.zig @@ -31,6 +31,7 @@ pub fn updateViewMatrix() void { } pub const ViewBobbing = struct { // MARK: ViewBobber + pub var enabled: bool = true; var time: f64 = 0; var velocity: f64 = 0; var magnitude: f64 = 0; @@ -72,11 +73,13 @@ pub const ViewBobbing = struct { // MARK: ViewBobber } pub fn apply() void { + if (!enabled) return; position += getPositionBobbing(); rotation += getRotationBobbing(); } pub fn remove() void { + if (!enabled) return; position -= getPositionBobbing(); rotation -= getRotationBobbing(); } diff --git a/src/renderer.zig b/src/renderer.zig index 0d6bedc82..432fead5f 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -553,6 +553,10 @@ pub const MenuBackGround = struct { const oldRotation = camera.rotation; defer camera.rotation = oldRotation; + const oldViewBobEnabled = camera.ViewBobbing.enabled; + defer camera.ViewBobbing.enabled = oldViewBobEnabled; + camera.ViewBobbing.enabled = false; + const angles = [_]f32 {std.math.pi/2.0, std.math.pi, std.math.pi*3/2.0, std.math.pi*2}; // All 4 sides are stored in a single image. From cc29de72ca8e453d7d1bd836d270ea6f158d3b01 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Thu, 26 Sep 2024 15:40:50 +0100 Subject: [PATCH 20/21] View bobbing cannot escape eyeBox anymore View bobbing will scale down as it gets closer to eyeBox edges, and will hard clamp if needed. --- src/camera.zig | 7 ++++++- src/game.zig | 5 ++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/camera.zig b/src/camera.zig index bd055a62b..f415bae28 100644 --- a/src/camera.zig +++ b/src/camera.zig @@ -60,7 +60,12 @@ pub const ViewBobbing = struct { // MARK: ViewBobber const xBob = @sin(time); const a = 0.5 * -@sin(2 * time); const zBob = ((a - a * a * a / 3) * 2 + 0.25 - 0.25 * @cos(2 * time)) * 0.8; - const bobVec = vec.rotateZ(Vec3d{xBob * magnitude * 0.05, 0, zBob * magnitude * 0.05}, -rotation[2]); + var bobVec = vec.rotateZ(Vec3d{xBob * magnitude * 1.05, 0, zBob * magnitude * 1.05}, -rotation[2]); + const eyeMin = game.Player.eyePos - game.Player.desiredEyePos + game.Player.eyeBox.min; + const eyeMax = game.Player.eyePos - game.Player.desiredEyePos + game.Player.eyeBox.max; + const eyeBoxSize = game.Player.eyeBox.max - game.Player.eyeBox.min; + const scaling = @as(Vec3d, @splat(1)) - @as(Vec3d, @splat(2)) * @abs(game.Player.eyePos) / eyeBoxSize; + bobVec = @max(eyeMin, @min(bobVec * scaling, eyeMax)); return bobVec; } diff --git a/src/game.zig b/src/game.zig index 9be1bfb9f..426b16d98 100644 --- a/src/game.zig +++ b/src/game.zig @@ -328,7 +328,7 @@ pub const Player = struct { // MARK: Player .min = -outerBoundingBoxExtent, .max = outerBoundingBoxExtent, }; - const eyeBox: collision.Box = .{ + pub const eyeBox: collision.Box = .{ .min = -Vec3d{outerBoundingBoxExtent[0]*0.2, outerBoundingBoxExtent[1]*0.2, 0.6}, .max = Vec3d{outerBoundingBoxExtent[0]*0.2, outerBoundingBoxExtent[1]*0.2, 0.9 - 0.05}, }; @@ -722,8 +722,6 @@ pub fn update(deltaTime: f64) void { // MARK: update() main.Window.scrollOffset = 0; } - camera.ViewBobbing.update(deltaTime); - // This our model for movement on a single frame: // dv/dt = a - λ·v // dx/dt = v @@ -925,6 +923,7 @@ pub fn update(deltaTime: f64) void { // MARK: update() Player.eyePos = @max(Player.eyeBox.min, @min(Player.eyePos, Player.eyeBox.max)); Player.eyeCoyote -= deltaTime; + camera.ViewBobbing.update(deltaTime); camera.position = Player.getEyePosBlocking(); const biome = world.?.playerBiome.load(.monotonic); From 862c98210f37fde767cd2de1cfbca722bc1752d8 Mon Sep 17 00:00:00 2001 From: Alex Davies Date: Thu, 26 Sep 2024 22:24:08 +0100 Subject: [PATCH 21/21] Fixed issue with bob scaling --- src/camera.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/camera.zig b/src/camera.zig index f415bae28..df58cd880 100644 --- a/src/camera.zig +++ b/src/camera.zig @@ -60,7 +60,7 @@ pub const ViewBobbing = struct { // MARK: ViewBobber const xBob = @sin(time); const a = 0.5 * -@sin(2 * time); const zBob = ((a - a * a * a / 3) * 2 + 0.25 - 0.25 * @cos(2 * time)) * 0.8; - var bobVec = vec.rotateZ(Vec3d{xBob * magnitude * 1.05, 0, zBob * magnitude * 1.05}, -rotation[2]); + var bobVec = vec.rotateZ(Vec3d{xBob * magnitude * 0.05, 0, zBob * magnitude * 0.05}, -rotation[2]); const eyeMin = game.Player.eyePos - game.Player.desiredEyePos + game.Player.eyeBox.min; const eyeMax = game.Player.eyePos - game.Player.desiredEyePos + game.Player.eyeBox.max; const eyeBoxSize = game.Player.eyeBox.max - game.Player.eyeBox.min;