Skip to content

Commit

Permalink
New framerate-independent damping algorithm.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mirsario committed Dec 26, 2022
1 parent 7218982 commit 3572102
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 29 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

# 1.4.0
- Added compatibility with Minecraft `1.19.3`+.
- Replaced all use of linear interpolation with a framerate-independent damping algorithm. Effects will no longer reduce in intensity on higher framerates, and will react to lagspikes slightly better.
- New default settings are a bit more balanced and friendlier to the average player.
- Mouselook roll's rotation target decay is now a separate setting.
- Improved logging clarity.

# 1.3.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ public class ConfigData extends BaseConfigData
// Pitch factors
public float verticalVelocityPitchFactor = 1.0f;
public float forwardVelocityPitchFactor = 1.0f;
// Interpolation speeds
public float horizontalVelocityInterpolationSpeed = 0.25f;
public float verticalVelocityInterpolationSpeed = 0.75f;
public float yawDeltaInterpolationSpeed = 1.0f;
// Smoothing factors
public float horizontalVelocitySmoothingFactor = 0.8f;
public float verticalVelocitySmoothingFactor = 0.8f;
public float yawDeltaSmoothingFactor = 0.8f;
public float yawDeltaDecayFactor = 0.5f;
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ public void OnCameraUpdate(Entity focusedEntity, Camera camera, Transform camera
Vec2f relativeXZVelocity = Vec2fUtils.Rotate(new Vec2f((float)velocity.x, (float)velocity.z), 360f - (float)cameraTransform.eulerRot.y);

// X
VerticalVelocityPitchOffset(cameraTransform, offsetTransform, velocity, relativeXZVelocity, deltaTime, config.verticalVelocityPitchFactor, config.verticalVelocityInterpolationSpeed);
ForwardVelocityPitchOffset(cameraTransform, offsetTransform, velocity, relativeXZVelocity, deltaTime, config.forwardVelocityPitchFactor, config.horizontalVelocityInterpolationSpeed);
VerticalVelocityPitchOffset(cameraTransform, offsetTransform, velocity, relativeXZVelocity, deltaTime, config.verticalVelocityPitchFactor, config.verticalVelocitySmoothingFactor);
ForwardVelocityPitchOffset(cameraTransform, offsetTransform, velocity, relativeXZVelocity, deltaTime, config.forwardVelocityPitchFactor, config.horizontalVelocitySmoothingFactor);
// Z
YawDeltaRollOffset(cameraTransform, offsetTransform, velocity, relativeXZVelocity, deltaTime, config.yawDeltaRollFactor, config.yawDeltaInterpolationSpeed);
StrafingRollOffset(cameraTransform, offsetTransform, velocity, relativeXZVelocity, deltaTime, strafingRollFactorToUse, config.horizontalVelocityInterpolationSpeed);
YawDeltaRollOffset(cameraTransform, offsetTransform, velocity, relativeXZVelocity, deltaTime, config.yawDeltaRollFactor * 1.25f, config.yawDeltaSmoothingFactor, config.yawDeltaDecayFactor);
StrafingRollOffset(cameraTransform, offsetTransform, velocity, relativeXZVelocity, deltaTime, strafingRollFactorToUse, config.horizontalVelocitySmoothingFactor);

prevCameraYaw = cameraTransform.eulerRot.y;
}
Expand All @@ -83,29 +83,29 @@ public Transform ModifyCameraTransform(Camera camera, Transform transform)
);
}

private void VerticalVelocityPitchOffset(Transform inputTransform, Transform outputTransform, Vec3d velocity, Vec2f relativeXZVelocity, double deltaTime, float intensity, float lerpSpeed)
private void VerticalVelocityPitchOffset(Transform inputTransform, Transform outputTransform, Vec3d velocity, Vec2f relativeXZVelocity, double deltaTime, float intensity, float smoothing)
{
double verticalVelocityPitchOffset = velocity.y * 2.75d;

if(velocity.y < 0f) {
verticalVelocityPitchOffset *= 2.25d;
}

prevVerticalVelocityPitchOffset = verticalVelocityPitchOffset = MathUtils.Lerp(prevVerticalVelocityPitchOffset, verticalVelocityPitchOffset, deltaTime * lerpSpeed);
prevVerticalVelocityPitchOffset = verticalVelocityPitchOffset = MathUtils.Damp(prevVerticalVelocityPitchOffset, verticalVelocityPitchOffset, smoothing, deltaTime);

outputTransform.eulerRot = outputTransform.eulerRot.add(verticalVelocityPitchOffset * intensity, 0d, 0d);
}

private void ForwardVelocityPitchOffset(Transform inputTransform, Transform outputTransform, Vec3d velocity, Vec2f relativeXZVelocity, double deltaTime, float intensity, float lerpSpeed)
private void ForwardVelocityPitchOffset(Transform inputTransform, Transform outputTransform, Vec3d velocity, Vec2f relativeXZVelocity, double deltaTime, float intensity, float smoothing)
{
double forwardVelocityPitchOffset = relativeXZVelocity.y * 5d;

prevForwardVelocityPitchOffset = forwardVelocityPitchOffset = MathUtils.Lerp(prevForwardVelocityPitchOffset, forwardVelocityPitchOffset, deltaTime * lerpSpeed);
prevForwardVelocityPitchOffset = forwardVelocityPitchOffset = MathUtils.Damp(prevForwardVelocityPitchOffset, forwardVelocityPitchOffset, smoothing, deltaTime);

outputTransform.eulerRot = outputTransform.eulerRot.add(forwardVelocityPitchOffset * intensity, 0d, 0d);
}

private void YawDeltaRollOffset(Transform inputTransform, Transform outputTransform, Vec3d velocity, Vec2f relativeXZVelocity, double deltaTime, float intensity, float lerpSpeed)
private void YawDeltaRollOffset(Transform inputTransform, Transform outputTransform, Vec3d velocity, Vec2f relativeXZVelocity, double deltaTime, float intensity, float offsetSmoothing, float decaySmoothing)
{
double yawDelta = prevCameraYaw - inputTransform.eulerRot.y;

Expand All @@ -116,18 +116,18 @@ private void YawDeltaRollOffset(Transform inputTransform, Transform outputTransf
}

yawDeltaRollTargetOffset += yawDelta * 0.07d;
yawDeltaRollOffset = MathUtils.Lerp(yawDeltaRollOffset, yawDeltaRollTargetOffset, (double)deltaTime * lerpSpeed * 10d);
yawDeltaRollOffset = MathUtils.Damp(yawDeltaRollOffset, yawDeltaRollTargetOffset, offsetSmoothing, deltaTime);

outputTransform.eulerRot = outputTransform.eulerRot.add(0d, 0d, yawDeltaRollOffset * intensity);

yawDeltaRollTargetOffset = MathUtils.Lerp(yawDeltaRollTargetOffset, 0d, deltaTime * 0.35d);
yawDeltaRollTargetOffset = MathUtils.Damp(yawDeltaRollTargetOffset, 0d, decaySmoothing, deltaTime);
}

private void StrafingRollOffset(Transform inputTransform, Transform outputTransform, Vec3d velocity, Vec2f relativeXZVelocity, double deltaTime, float intensity, float lerpSpeed)
private void StrafingRollOffset(Transform inputTransform, Transform outputTransform, Vec3d velocity, Vec2f relativeXZVelocity, double deltaTime, float intensity, float smoothing)
{
double strafingRollOffset = -relativeXZVelocity.x * 15d;

prevStrafingRollOffset = strafingRollOffset = MathUtils.Lerp(prevStrafingRollOffset, strafingRollOffset, (double)deltaTime * lerpSpeed);
prevStrafingRollOffset = strafingRollOffset = MathUtils.Damp(prevStrafingRollOffset, strafingRollOffset, smoothing, deltaTime);

outputTransform.eulerRot = outputTransform.eulerRot.add(0d, 0d, strafingRollOffset * intensity);
}
Expand Down
31 changes: 29 additions & 2 deletions src/main/java/mirsario/cameraoverhaul/core/utils/MathUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

public class MathUtils
{
// Clamp

public static float Clamp(float value, float min, float max)
{
return value < min ? min : (value > max ? max : value);
}

public static double Clamp(double value, double min, double max)
{
return value < min ? min : (value > max ? max : value);
}

public static float Clamp01(float value)
{
return value < 0f ? 0f : (value > 1f ? 1f : value);
Expand All @@ -12,13 +24,28 @@ public static double Clamp01(double value)
return value < 0d ? 0d : (value > 1d ? 1d : value);
}

public static float Lerp(float a,float b,float time)
// Lerp

public static float Lerp(float a, float b, float time)
{
return a + (b - a) * Clamp01(time);
}

public static double Lerp(double a,double b,double time)
public static double Lerp(double a, double b, double time)
{
return a + (b - a) * Clamp01(time);
}

// Framerate-agnostic smoothing.
// https://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp

public static float Damp(float source, float destination, float smoothing, float dt)
{
return Lerp(source, destination, 1f - (float)Math.pow(smoothing, dt));
}

public static double Damp(double source, double destination, double smoothing, double dt)
{
return Lerp(source, destination, 1d - Math.pow(smoothing, dt));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import mirsario.cameraoverhaul.common.*;
import mirsario.cameraoverhaul.common.configuration.*;
import mirsario.cameraoverhaul.core.configuration.*;
import mirsario.cameraoverhaul.core.utils.MathUtils;
import mirsario.cameraoverhaul.fabric.abstractions.*;
import net.minecraft.client.*;

Expand Down Expand Up @@ -45,14 +46,20 @@ public static ConfigBuilder GetConfigBuilder()
general.addEntry(CreateFloatFactorEntry(entryBuilder, "verticalVelocityPitchFactor", 1.0f, config.verticalVelocityPitchFactor, value -> config.verticalVelocityPitchFactor = value));
general.addEntry(CreateFloatFactorEntry(entryBuilder, "forwardVelocityPitchFactor", 1.0f, config.forwardVelocityPitchFactor, value -> config.forwardVelocityPitchFactor = value));

// Interpolation factors
general.addEntry(CreateFloatFactorEntry(entryBuilder, "horizontalVelocityInterpolationSpeed", 0.25f, config.horizontalVelocityInterpolationSpeed, value -> config.horizontalVelocityInterpolationSpeed = value));
general.addEntry(CreateFloatFactorEntry(entryBuilder, "verticalVelocityInterpolationSpeed", 0.75f, config.verticalVelocityInterpolationSpeed, value -> config.verticalVelocityInterpolationSpeed = value));
general.addEntry(CreateFloatFactorEntry(entryBuilder, "yawDeltaInterpolationSpeed", 1.0f, config.yawDeltaInterpolationSpeed, value -> config.yawDeltaInterpolationSpeed = value));
// Smoothing factors
general.addEntry(CreateFloatFactorEntry(entryBuilder, "horizontalVelocitySmoothingFactor", 0.8f, ClampSmoothness(config.horizontalVelocitySmoothingFactor), value -> config.horizontalVelocitySmoothingFactor = ClampSmoothness(value)));
general.addEntry(CreateFloatFactorEntry(entryBuilder, "verticalVelocitySmoothingFactor", 0.8f, ClampSmoothness(config.verticalVelocitySmoothingFactor), value -> config.verticalVelocitySmoothingFactor = ClampSmoothness(value)));
general.addEntry(CreateFloatFactorEntry(entryBuilder, "yawDeltaSmoothingFactor", 0.8f, ClampSmoothness(config.yawDeltaSmoothingFactor), value -> config.yawDeltaSmoothingFactor = ClampSmoothness(value)));
general.addEntry(CreateFloatFactorEntry(entryBuilder, "yawDeltaDecayFactor", 0.5f, ClampSmoothness(config.yawDeltaDecayFactor), value -> config.yawDeltaDecayFactor = ClampSmoothness(value)));

return builder;
}

private static float ClampSmoothness(float value)
{
return MathUtils.Clamp(value, 0f, 0.999f);
}

// Entry Helpers

public static BooleanListEntry CreateBooleanEntry(ConfigEntryBuilder entryBuilder, String entryName, Boolean defaultValue, Boolean value, Function<Boolean, Boolean> setter)
Expand Down
14 changes: 8 additions & 6 deletions src/main/resources/assets/cameraoverhaul/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
"cameraoverhaul.config.forwardvelocitypitchfactor.name": "Forward Velocity Pitch Factor",
"cameraoverhaul.config.forwardvelocitypitchfactor.tooltip": "Controls the strength of the camera pitch rotation offset caused by moving forward or backwards.",

"cameraoverhaul.config.horizontalvelocityinterpolationspeed.name": "Horizontal Velocity Interpolation Speed",
"cameraoverhaul.config.horizontalvelocityinterpolationspeed.tooltip": "Controls the smoothness of camera pitch & roll rotations caused by moving horizontally.",
"cameraoverhaul.config.verticalvelocityinterpolationspeed.name": "Vertical Velocity Interpolation Speed",
"cameraoverhaul.config.verticalvelocityinterpolationspeed.tooltip": "Controls the smoothness of camera pitch rotations caused by moving vertically.",
"cameraoverhaul.config.yawdeltainterpolationspeed.name": "Mouselook Roll Interpolation Speed",
"cameraoverhaul.config.yawdeltainterpolationspeed.tooltip": "Controls the smoothness of camera roll rotations caused by turning around horizontally."
"cameraoverhaul.config.horizontalvelocitysmoothingfactor.name": "Horizontal Velocity Smoothing Factor",
"cameraoverhaul.config.horizontalvelocitysmoothingfactor.tooltip": "Controls the smoothness of camera pitch & roll rotations caused by moving horizontally.",
"cameraoverhaul.config.verticalvelocitysmoothingfactor.name": "Vertical Velocity Smoothing Factor",
"cameraoverhaul.config.verticalvelocitysmoothingfactor.tooltip": "Controls the smoothness of camera pitch rotations caused by moving vertically.",
"cameraoverhaul.config.yawdeltasmoothingfactor.name": "Mouselook Roll Smoothing Factor",
"cameraoverhaul.config.yawdeltasmoothingfactor.tooltip": "Controls the smoothness of camera roll rotations caused by turning around horizontally.",
"cameraoverhaul.config.yawdeltadecayfactor.name": "Mouselook Roll Decay Factor",
"cameraoverhaul.config.yawdeltadecayfactor.tooltip": "Controls the smoothness of the decay of camera roll rotations caused by turning around horizontally."
}

0 comments on commit 3572102

Please sign in to comment.