Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increase FOV when moving fast (Issue#716) #812

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
49 changes: 39 additions & 10 deletions src/game.zig
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ 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 fovMod: f32 = 0;
IntegratedQuantum marked this conversation as resolved.
Show resolved Hide resolved
pub var id: u32 = 0;
pub var gamemode: Atomic(Gamemode) = .init(.creative);
pub var isFlying: Atomic(bool) = .init(false);
Expand Down Expand Up @@ -401,6 +402,12 @@ pub const Player = struct { // MARK: Player
return eyeCoyote;
}

pub fn getFovModifierBlocking() f32 {
mutex.lock();
defer mutex.unlock();
return fovMod;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just make fovMod atomic?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Why does it have to be atomic, when other, similar, variables (like eyeVel or eyePos) are not atomic either?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's only ever used by the update and render functions, then you are right, it doesn't need to be thread safe.

pub fn setGamemode(newGamemode: Gamemode) void {
gamemode.store(newGamemode, .monotonic);

Expand Down Expand Up @@ -703,6 +710,9 @@ pub fn update(deltaTime: f64) void { // MARK: update()
// At equillibrium we want to have dv/dt = a - λv = 0 → a = λ*v
const fricMul = speedMultiplier*baseFrictionCoefficient;

const MaxSpeedWalking: f64 = 4;
const MaxSpeedRunning: f64 = 8;

const forward = vec.rotateZ(Vec3d{0, 1, 0}, -camera.rotation[2]);
const right = Vec3d{-forward[1], forward[0], 0};
var movementDir: Vec3d = .{0, 0, 0};
Expand All @@ -717,25 +727,25 @@ pub fn update(deltaTime: f64) void { // MARK: update()
movementSpeed = @max(movementSpeed, 32)*KeyBoard.key("forward").value;
movementDir += forward*@as(Vec3d, @splat(32*KeyBoard.key("forward").value));
} else {
movementSpeed = @max(movementSpeed, 8)*KeyBoard.key("forward").value;
movementDir += forward*@as(Vec3d, @splat(8*KeyBoard.key("forward").value));
movementSpeed = @max(movementSpeed, MaxSpeedRunning)*KeyBoard.key("forward").value;
movementDir += forward*@as(Vec3d, @splat(MaxSpeedRunning*KeyBoard.key("forward").value));
}
} else {
movementSpeed = @max(movementSpeed, 4)*KeyBoard.key("forward").value;
movementDir += forward*@as(Vec3d, @splat(4*KeyBoard.key("forward").value));
movementSpeed = @max(movementSpeed, MaxSpeedWalking)*KeyBoard.key("forward").value;
movementDir += forward*@as(Vec3d, @splat(MaxSpeedWalking*KeyBoard.key("forward").value));
}
}
if(KeyBoard.key("backward").value > 0.0) {
movementSpeed = @max(movementSpeed, 4)*KeyBoard.key("backward").value;
movementDir += forward*@as(Vec3d, @splat(-4*KeyBoard.key("backward").value));
movementSpeed = @max(movementSpeed, MaxSpeedWalking)*KeyBoard.key("backward").value;
movementDir += forward*@as(Vec3d, @splat(-MaxSpeedWalking*KeyBoard.key("backward").value));
}
if(KeyBoard.key("left").value > 0.0) {
movementSpeed = @max(movementSpeed, 4*KeyBoard.key("left").value);
movementDir += right*@as(Vec3d, @splat(4*KeyBoard.key("left").value));
movementSpeed = @max(movementSpeed, MaxSpeedWalking*KeyBoard.key("left").value);
movementDir += right*@as(Vec3d, @splat(MaxSpeedWalking*KeyBoard.key("left").value));
}
if(KeyBoard.key("right").value > 0.0) {
movementSpeed = @max(movementSpeed, 4*KeyBoard.key("right").value);
movementDir += right*@as(Vec3d, @splat(-4*KeyBoard.key("right").value));
movementSpeed = @max(movementSpeed, MaxSpeedWalking*KeyBoard.key("right").value);
movementDir += right*@as(Vec3d, @splat(-MaxSpeedWalking*KeyBoard.key("right").value));
IntegratedQuantum marked this conversation as resolved.
Show resolved Hide resolved
}
if(KeyBoard.key("jump").pressed) {
if(Player.isFlying.load(.monotonic)) {
Expand Down Expand Up @@ -894,6 +904,25 @@ pub fn update(deltaTime: f64) void { // MARK: update()
Player.eyeVel[i] = firstTerm.mul(c_3.negate().subScalar(frictionCoefficient).mulScalar(0.5)).add(secondTerm.mul((c_3.subScalar(frictionCoefficient)).mulScalar(0.5))).val[0];
Player.eyePos[i] += firstTerm.add(secondTerm).addScalar(a/k).val[0];
}

// Calculate our FOV modifier based on our current speed.
{
const fovModStartSpeed: f32 = @as(f32, @floatCast(MaxSpeedWalking));
const fovModEndSpeed: f32 = @as(f32, @floatCast(MaxSpeedRunning));

// Clamped between 0-1. We'll let the renderer decide what the acual FOV values are
const fovModGoal : f32 = std.math.clamp((@as(f32, @floatCast(movementSpeed)) - fovModStartSpeed) / (fovModEndSpeed - fovModStartSpeed), 0, 1);
IntegratedQuantum marked this conversation as resolved.
Show resolved Hide resolved
const fovModDir: f32 = if(Player.fovMod < fovModGoal) 1 else -1;
const fovModNext: f32 = Player.fovMod + (fovModDir * @as(f32, @floatCast(deltaTime)) * 5.0);

if((Player.fovMod < fovModGoal and fovModNext < fovModGoal) or (Player.fovMod > fovModGoal and fovModNext > fovModGoal)) {
Player.fovMod = fovModNext;
} else {
Player.fovMod = fovModGoal;
}

main.renderer.updateFovModifier(Player.fovMod);
}
}

const time = std.time.milliTimestamp();
Expand Down
12 changes: 9 additions & 3 deletions src/renderer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,21 @@ var worldFrameBuffer: graphics.FrameBuffer = undefined;
var lastWidth: u31 = 0;
var lastHeight: u31 = 0;
var lastFov: f32 = 0;
var lastFovExtra: f32 = 0;
pub fn updateViewport(width: u31, height: u31, fov: f32) void {
IntegratedQuantum marked this conversation as resolved.
Show resolved Hide resolved
lastWidth = @intFromFloat(@as(f32, @floatFromInt(width))*main.settings.resolutionScale);
lastHeight = @intFromFloat(@as(f32, @floatFromInt(height))*main.settings.resolutionScale);
lastFov = fov;
game.projectionMatrix = Mat4f.perspective(std.math.degreesToRadians(fov), @as(f32, @floatFromInt(lastWidth))/@as(f32, @floatFromInt(lastHeight)), zNear, zFar);
game.projectionMatrix = Mat4f.perspective(std.math.degreesToRadians(fov+lastFovExtra), @as(f32, @floatFromInt(lastWidth))/@as(f32, @floatFromInt(lastHeight)), zNear, zFar);
worldFrameBuffer.updateSize(lastWidth, lastHeight, c.GL_RGB16F);
worldFrameBuffer.unbind();
}

pub fn updateFovModifier(fovMod: f32) void {
lastFovExtra = fovMod * 20;
game.projectionMatrix = Mat4f.perspective(std.math.degreesToRadians(lastFov+lastFovExtra), @as(f32, @floatFromInt(lastWidth))/@as(f32, @floatFromInt(lastHeight)), zNear, zFar);
}

pub fn render(playerPosition: Vec3d) void {
// TODO: player bobbing
if(game.world) |world| {
Expand Down Expand Up @@ -173,7 +179,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
game.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}, game.camera.viewMatrix, lastFov+lastFovExtra, lastWidth, lastHeight);
IntegratedQuantum marked this conversation as resolved.
Show resolved Hide resolved

const time: u32 = @intCast(std.time.milliTimestamp() & std.math.maxInt(u32));

Expand All @@ -198,7 +204,7 @@ pub fn renderWorld(world: *World, ambientLight: Vec3f, skyColor: Vec3f, playerPo
const meshes = mesh_storage.updateAndGetRenderChunks(world.conn, &frustum, playerPos, settings.renderDistance);

gpu_performance_measuring.startQuery(.chunk_rendering_preparation);
const direction = crosshairDirection(game.camera.viewMatrix, lastFov, lastWidth, lastHeight);
const direction = crosshairDirection(game.camera.viewMatrix, lastFov+lastFovExtra, lastWidth, lastHeight);
IntegratedQuantum marked this conversation as resolved.
Show resolved Hide resolved
MeshSelection.select(playerPos, direction, game.Player.inventory.getItem(game.Player.selectedSlot));
MeshSelection.render(game.projectionMatrix, game.camera.viewMatrix, playerPos);

Expand Down
Loading