Implement damped yaw rotation for smooth third-person camera target assist
This commit is contained in:
@@ -37,6 +37,7 @@ const MIN_PITCH_RADIANS = -0.2;
|
|||||||
const MAX_PITCH_RADIANS = Math.PI * 0.45;
|
const MAX_PITCH_RADIANS = Math.PI * 0.45;
|
||||||
export const THIRD_PERSON_CAMERA_COLLISION_RADIUS = 0.2;
|
export const THIRD_PERSON_CAMERA_COLLISION_RADIUS = 0.2;
|
||||||
const CAMERA_PIVOT_EYE_HEIGHT_FACTOR = 0.85;
|
const CAMERA_PIVOT_EYE_HEIGHT_FACTOR = 0.85;
|
||||||
|
const TARGET_ASSIST_YAW_SPEED = 2.2;
|
||||||
const TARGET_ASSIST_VERTICAL_LOOK_SPEED = 3.4;
|
const TARGET_ASSIST_VERTICAL_LOOK_SPEED = 3.4;
|
||||||
const TARGET_ASSIST_VERTICAL_LOOK_LIMIT = 1.25;
|
const TARGET_ASSIST_VERTICAL_LOOK_LIMIT = 1.25;
|
||||||
const TARGET_ASSIST_VERTICAL_COLLISION_FADE_START_RATIO = 0.28;
|
const TARGET_ASSIST_VERTICAL_COLLISION_FADE_START_RATIO = 0.28;
|
||||||
@@ -62,6 +63,24 @@ function clampCameraDistance(distance: number): number {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeAngleRadians(angle: number): number {
|
||||||
|
return Math.atan2(Math.sin(angle), Math.cos(angle));
|
||||||
|
}
|
||||||
|
|
||||||
|
function dampAngleRadians(
|
||||||
|
current: number,
|
||||||
|
target: number,
|
||||||
|
strength: number,
|
||||||
|
dt: number
|
||||||
|
): number {
|
||||||
|
if (dt <= 0 || strength <= 0) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
const alpha = 1 - Math.exp(-strength * dt);
|
||||||
|
return current + normalizeAngleRadians(target - current) * alpha;
|
||||||
|
}
|
||||||
|
|
||||||
function dampScalar(
|
function dampScalar(
|
||||||
current: number,
|
current: number,
|
||||||
target: number,
|
target: number,
|
||||||
@@ -400,7 +419,12 @@ export class ThirdPersonNavigationController implements NavigationController {
|
|||||||
targetAssist.targetPosition.x - this.feetPosition.x,
|
targetAssist.targetPosition.x - this.feetPosition.x,
|
||||||
targetAssist.targetPosition.z - this.feetPosition.z
|
targetAssist.targetPosition.z - this.feetPosition.z
|
||||||
);
|
);
|
||||||
this.cameraYawRadians = targetYaw;
|
this.cameraYawRadians = dampAngleRadians(
|
||||||
|
this.cameraYawRadians,
|
||||||
|
targetYaw,
|
||||||
|
TARGET_ASSIST_YAW_SPEED * targetAssist.strength,
|
||||||
|
dt
|
||||||
|
);
|
||||||
const eyeHeight = getFirstPersonPlayerEyeHeight(this.activePlayerShape);
|
const eyeHeight = getFirstPersonPlayerEyeHeight(this.activePlayerShape);
|
||||||
const pivotY =
|
const pivotY =
|
||||||
this.smoothedFeetY + eyeHeight * CAMERA_PIVOT_EYE_HEIGHT_FACTOR;
|
this.smoothedFeetY + eyeHeight * CAMERA_PIVOT_EYE_HEIGHT_FACTOR;
|
||||||
|
|||||||
@@ -241,33 +241,6 @@ describe("ThirdPersonNavigationController", () => {
|
|||||||
controller.deactivate(targetContext);
|
controller.deactivate(targetContext);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses target direction as the lock-on base yaw immediately", () => {
|
|
||||||
const { context } = createRuntimeControllerContext();
|
|
||||||
const controller = new ThirdPersonNavigationController();
|
|
||||||
const targetContext = {
|
|
||||||
...context,
|
|
||||||
resolveThirdPersonTargetAssist: () => ({
|
|
||||||
targetPosition: {
|
|
||||||
x: 5,
|
|
||||||
y: 1,
|
|
||||||
z: 0
|
|
||||||
},
|
|
||||||
strength: 1
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
controller.activate(targetContext);
|
|
||||||
|
|
||||||
expect(Math.abs(targetContext.camera.position.x)).toBeLessThan(0.001);
|
|
||||||
|
|
||||||
controller.update(0);
|
|
||||||
|
|
||||||
expect(targetContext.camera.position.x).toBeLessThan(-3);
|
|
||||||
expect(Math.abs(targetContext.camera.position.z)).toBeLessThan(1);
|
|
||||||
|
|
||||||
controller.deactivate(targetContext);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("fades vertical target assist when camera collision pushes the camera close", () => {
|
it("fades vertical target assist when camera collision pushes the camera close", () => {
|
||||||
const { context } = createRuntimeControllerContext();
|
const { context } = createRuntimeControllerContext();
|
||||||
const controller = new ThirdPersonNavigationController();
|
const controller = new ThirdPersonNavigationController();
|
||||||
|
|||||||
Reference in New Issue
Block a user