mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 03:14:00 +00:00
Merge pull request #1171 from Rohilalala/fix/director-goto-shot
fix(director): land on the requested shot
This commit is contained in:
4 files changed
+53
-4
No files matched your search
@@ -0,0 +1,3 @@
|
|||||||
|
- Director shot actions land on the requested shot. A seek to a shot's start
|
||||||
|
could round a hair below it and select the end of the previous shot for some
|
||||||
|
shot counts and durations (Aditya, @Rohilalala, #1171).
|
||||||
@@ -430,6 +430,8 @@ reference. Legacy projects retain their ordinary flights, content and edits.
|
|||||||
Seeking between ordinary camera poses uses the shortest longitude arc across the
|
Seeking between ordinary camera poses uses the shortest longitude arc across the
|
||||||
dateline while preserving both authored endpoint longitudes, and turns heading
|
dateline while preserving both authored endpoint longitudes, and turns heading
|
||||||
and roll the short way for any authored angles.
|
and roll the short way for any authored angles.
|
||||||
|
A seek to a shot's start, as a shot action makes, selects that shot rather than
|
||||||
|
the end of the previous one.
|
||||||
See [camera directions](DIRECTOR-CAMERA.md).
|
See [camera directions](DIRECTOR-CAMERA.md).
|
||||||
|
|
||||||
Realtime voice composes separate connection, response/tool, Radio handoff, input
|
Realtime voice composes separate connection, response/tool, Radio handoff, input
|
||||||
|
|||||||
@@ -72,19 +72,27 @@ export function sceneSeekState(scene, progress, durationForShot, holdForShot) {
|
|||||||
let shotIndex = scene.shots.length - 1;
|
let shotIndex = scene.shots.length - 1;
|
||||||
for (let index = 0; index < scene.shots.length; index += 1) {
|
for (let index = 0; index < scene.shots.length; index += 1) {
|
||||||
const endElapsedSec = startElapsedSec + durations[index];
|
const endElapsedSec = startElapsedSec + durations[index];
|
||||||
if (targetSec < endElapsedSec || index === scene.shots.length - 1) {
|
// Compare in progress units: a shot's startProgress (start / total)
|
||||||
|
// times total can round below its start and select the previous shot.
|
||||||
|
if (
|
||||||
|
normalized < endElapsedSec / totalSec ||
|
||||||
|
index === scene.shots.length - 1
|
||||||
|
) {
|
||||||
shotIndex = index;
|
shotIndex = index;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
startElapsedSec = endElapsedSec;
|
startElapsedSec = endElapsedSec;
|
||||||
}
|
}
|
||||||
|
// Keep the elapsed time inside the selected shot, so it agrees with
|
||||||
|
// shotIndex when targetSec rounded below the shot's start.
|
||||||
|
const elapsedSec = Math.max(targetSec, startElapsedSec);
|
||||||
const shot = scene.shots[shotIndex];
|
const shot = scene.shots[shotIndex];
|
||||||
const flightDurationSec = shot.durationSec || DEFAULT_SHOT_DURATION_SEC;
|
const flightDurationSec = shot.durationSec || DEFAULT_SHOT_DURATION_SEC;
|
||||||
const holdDurationSec = holdForShot(scene, shot);
|
const holdDurationSec = holdForShot(scene, shot);
|
||||||
const shotDurationSec = Math.max(0.001, flightDurationSec + holdDurationSec);
|
const shotDurationSec = Math.max(0.001, flightDurationSec + holdDurationSec);
|
||||||
const shotElapsedSec = Math.max(
|
const shotElapsedSec = Math.max(
|
||||||
0,
|
0,
|
||||||
Math.min(shotDurationSec, targetSec - startElapsedSec),
|
Math.min(shotDurationSec, elapsedSec - startElapsedSec),
|
||||||
);
|
);
|
||||||
const cameraProgress = clamp01(
|
const cameraProgress = clamp01(
|
||||||
shotElapsedSec / Math.max(0.001, flightDurationSec),
|
shotElapsedSec / Math.max(0.001, flightDurationSec),
|
||||||
@@ -99,8 +107,8 @@ export function sceneSeekState(scene, progress, durationForShot, holdForShot) {
|
|||||||
);
|
);
|
||||||
const move = resolveCameraMove(scene, shot);
|
const move = resolveCameraMove(scene, shot);
|
||||||
return {
|
return {
|
||||||
sceneProgress: totalSec > 0 ? targetSec / totalSec : 0,
|
sceneProgress: totalSec > 0 ? elapsedSec / totalSec : 0,
|
||||||
sceneElapsedSec: targetSec,
|
sceneElapsedSec: elapsedSec,
|
||||||
sceneDurationSec: totalSec,
|
sceneDurationSec: totalSec,
|
||||||
shotIndex,
|
shotIndex,
|
||||||
shot,
|
shot,
|
||||||
|
|||||||
@@ -49,3 +49,39 @@ test('camera seeking preserves cubic easing and shortest-angle orientation', ()
|
|||||||
);
|
);
|
||||||
assert.deepEqual(cameraAtProgress(null, camera(20, 350), 0), camera(20, 350));
|
assert.deepEqual(cameraAtProgress(null, camera(20, 350), 0), camera(20, 350));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('seeking to a shot start lands in that shot for every shot count and duration', () => {
|
||||||
|
const misses = [];
|
||||||
|
for (let count = 2; count <= 12; count += 1) {
|
||||||
|
for (let flightTenths = 1; flightTenths <= 100; flightTenths += 1) {
|
||||||
|
for (let holdTenths = 0; holdTenths <= 50; holdTenths += 1) {
|
||||||
|
const shots = Array.from({ length: count }, (_, index) => ({
|
||||||
|
id: `s${index}`,
|
||||||
|
// Every third shot is longer, so boundaries are not all equal steps.
|
||||||
|
durationSec: flightTenths / 10 + (index % 3 === 2 ? 1.7 : 0),
|
||||||
|
holdSec: holdTenths / 10,
|
||||||
|
camera: camera(20, 0),
|
||||||
|
}));
|
||||||
|
const mixed = { shots };
|
||||||
|
for (const [index, shot] of shots.entries()) {
|
||||||
|
const { startProgress, startElapsedSec } = sceneTimingForShot(
|
||||||
|
mixed,
|
||||||
|
shot,
|
||||||
|
duration,
|
||||||
|
);
|
||||||
|
const seek = sceneSeekState(mixed, startProgress, duration, hold);
|
||||||
|
// One or two ulps earlier still belongs to the previous shot.
|
||||||
|
const before = startProgress * (1 - Number.EPSILON);
|
||||||
|
const previous = sceneSeekState(mixed, before, duration, hold);
|
||||||
|
if (
|
||||||
|
seek.shotIndex !== index ||
|
||||||
|
seek.sceneElapsedSec < startElapsedSec ||
|
||||||
|
previous.shotIndex !== Math.max(0, index - 1)
|
||||||
|
)
|
||||||
|
misses.push(`${count}x${flightTenths}/${holdTenths}#${index}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.deepEqual(misses.slice(0, 5), []);
|
||||||
|
});
|
||||||
Reference in new issue
Block a user