Repository navigation
Port: keep follow-camera turns moving at walls and shorten zoom recovery - #134
Merged
Merged
Conversation
Right-stick and mouse look both turn the follow camera through direct yaw. It proved the whole turn clear at the current distance, with one capsule around both the eased and the pending eye, and dropped whatever it could not prove. Retail rotates the pending eye and corrects its distance at walls; the port's clearance check instead rejected the turn. Retail's correction leaves the pending eye a few units from a wall it slides along, so even the starting pose failed the check and every later turn was refused. In the first Underground Channel corridor a held stick or mouse turn toward the wall stops after a few degrees. Direct yaw now uses retail's rotate-then-correct response: the pending eye rotates about its look-at point, and retail's ground and wall correction brings it in front of any wall on its view, so the turn goes on and the next update moves the eye back out. The port keeps turning the drawn eye by the same angle at once. The view the tick's step then shows is checked against every wall except those that already hid the drawn view, from the eased look-at point and, when retail's correction uses an explicit collision target, from that target too. Each placement is checked through the step itself. Where moving the drawn eye suffices, retail's pending pose is kept: the drawn eye moves on along its easing path toward a pending eye its look-at point sees, then in toward its look-at point. Failing both, both eyes are placed on a view from the stepped look-at point at least ten units long, so the camera keeps a usable direction: the stepped view, or the nearest in heading of views turned from it in eighths of a half turn either way, as far out as a search finds in sight. Each search starts just beyond ten units, so the view still measures ten once stored as floats and stepped. If none of the sampled headings has a usable starting point, the turn is dropped for that update. Presentation blending is cut when the eye passes a camera wall, or when any of those other walls crosses either protected sightline between the drawn pose and the next, such as a thin post the view passes across, using the view sweep that wheel zoom already checks, now shared as CameraViewSweeps. Retail's obstacle avoidance now waits during mouse turns, as it already did for stick turns; otherwise it swung the eye back against a turn along a wall. Direct pitch keeps its conservative check. The tests that expected a refused or clipped turn now expect the eye in front of the wall, and new ones cover a turn that starts beside a wall, a pending eye behind one, a full turn along a wall without a cut, obstacle avoidance waiting, a corner hidden from a lagging look-at point, a thin post crossed by direct, stick and mouse turns with zoom off, a post already hiding the view that excuses no other wall, an explicit collision target kept in sight by direct, stick and mouse turns, a turn near a wall end that must keep a usable view, a post crossing only the collision target's sightline, and a turn held past a wall end with a led look-at point, which must keep turning. tools/input/dungeon-camera-wall-turn.input replays a stick and then a mouse turn into the first corridor's wall.
With wheel zoom on, a zoomed-out camera that a wall pulled in was slow to come back out, and turning it along a wall jumped: - Every game frame the wall pushed the eye further in struck another pull-in, so backing into one wall reached the longest hold at once. Walking away left the eye at retail's follow distance for up to six seconds, closer than retail's own camera, before it began to return. - Once the view behind it cleared, it waited 20 game frames and then returned 4% of the remaining gap per frame, about two and a half seconds to come most of the way back to the far limit. - Every pull-in, however small, reset the quiet period and took up the hold again, so foliage brushing a still view kept a far camera held. - An eased eye placed in front of a wall always cut presentation interpolation, so a zoomed-out turn along a wall jumped repeatedly. Pulling in further before the eye begins moving out now counts as the same pull-in, and a first pull-in does not hold: once past the wall the eye returns as soon as the view farther stays clear, as retail's does. A wall met again while recent pull-ins are remembered still holds, from a second and a half doubling up to six seconds, so walking through rocks keeps the shorter distance. The return waits 15 game frames and takes 10% of the gap per frame, at least two units, so the eye is nine tenths of the way back within about a second and a third; a shorter wait let the orbiting pillar ring pump the distance. A pull-in of less than ten units still shortens the eye but neither counts nor holds. The placed eye is cut to only where a display frame blending to it would show a wall, the characters' walls included; otherwise frames blend to it as to any pull-in. The camera updates once per game frame, 30 a second, so docs/PC.md now gives the zoom timings in game frames; it described them as 60 Hz ticks, which halved every time. Tests cover backing into a wall and away, repeated pull-ins holding longer, small pull-ins, and the return time.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Before
Turning at walls. Right-stick look and mouse look both go through direct yaw (
MouseCameraYaw,port/src/camera_mouse.cpp). It proved the whole turn clear at the current distance, using one capsule around both the eased and the pending eye, and dropped any part it could not prove. Retail rotates the pending eye and corrects its distance at walls. The port's direct-input clearance check can instead reject the turn. Retail's wall correction leaves the pending eye a few units from a wall it slides along, so even the starting pose failed the check and every later turn was refused. In the first Underground Channel corridor, holding the right stick or moving the mouse toward the wall turns the view a few degrees and then nothing more.Wheel zoom at walls (
input.mouse_zoom, off by default):After
How
MouseCameraYawrotates both eyes, then retail'sCheckGround/CheckCollisioncorrects the pending eye against the bounded orbit collection thatCCameraControl::MoveCameraalready gathers.check_ref. A view already obstructed before input does not exempt newly crossed geometry from visibility checks.KeepInSightfirst tries moving only the drawn eye along its easing path and then toward its look-at point, retaining retail's pending pose where possible. If neither works, it finds and validates a nondegenerate fallback through the actual step. It checks the eased look-at sightline and, when required, the explicit collision-target sightline against each polygon that blocked neither starting sightline. The fallback places both eyes at least ten units from the stepped look-at point: on the stepped view, or on the nearest in heading of views turned from it in eighths of a half turn. Each view's search starts at 10.01 units to allow for float rounding at ordinary game coordinates; the stored, stepped view must still pass the ten-unit length and sightline checks. This fixed margin does not guarantee a usable anchor at arbitrary far-from-origin coordinates. This is a bounded search of sampled headings. If none has a usable starting point, the turn is dropped for that update and retail's camera stays as it was. Recovery can change the heading abruptly in tight wall-end geometry.CameraViewSweepsfromcamera_zoom.cpp.ClearArc) is removed.cameracontrol.cppsetsCAMERA_ROT_CANCEL_AUTO_MOVEfor a fresh mouse yaw, as it already did for stick yaw.CameraZoom(port/src/camera_zoom.*),Strike(drop)counts significant pull-ins once until outward recovery starts (pulled), and ignores drops underminor_pull_in(10 units).clear_ticksgoes from 20 to 15,release_ratefrom 0.04 to 0.1 andrelease_minfrom 1 to 2.KeepVisiblechecks the blended views against both camera and character collision. It cuts if the sweep finds an obstruction or cannot complete its geometry collection.No files under
ps2/are touched.tools/input/dungeon-camera-wall-turn.inputis the only new file.Testing
--jump dungeon:0:1 --fast-load --headless --offscreen,tools/input/dungeon-mouse-camera.inputup to frame 2260, then a turn toward the corridor wall):tools/input/dungeon-camera-wall-turn.input(right stick from 2400, then 2000 mouse counts from 2700; captures at 2600 and 2900).-R Camerapasses 95/95 on the branch, and 91/91 on the first commit alone (1817c82).CameraMouse.TurnPastACornerWithALaggingTargetStaysInViewAfterTheStep(a wall ending short of a lagging drawn target),CameraMouse.TurnCarryingTheViewAcrossAThinPostCutsInterpolationandCameraMouse.StickAndMouseTurnsAcrossAThinPostCutInterpolationWithoutZoom(default zoom off, throughMoveCamerafor both the stick and the mouse).CameraMouse.APostAlreadyHidingTheViewExcusesNoOtherWall,CameraMouse.TurnKeepsTheViewInSightOfAnExplicitCollisionTargetandCameraMouse.StickAndMouseTurnsKeepAnExplicitCollisionTargetInSight.check_ref. The view must be clear from both the look-at point and the collision target after the actual step.CameraMouse.TurnNearAWallEndKeepsAUsableView(direct, with and without an explicit collision target) andCameraMouse.StickAndMouseTurnsNearAWallEndKeepAUsableView(both wrappers) cover the zero-direction wall-end case. They require the yaw to be accepted in the direct case. After the actual step they require a view longer than five units, a camera matrix whose 3x3 determinant has magnitude 1, and clear look-at and collision-target sightlines.CameraMouse.TurnCarryingThePlayersSightlineAcrossAPostCutsInterpolationcovers the off-centre explicit-target post, direct and through both wrappers, with zoom off. The endpoints stay clear, the turn is accepted and interpolation cuts.CameraMouse.TurnHeldPastALedWallEndKeepsTurning(direct yaw accepted on each of 300 updates) andCameraMouse.StickAndMouseTurnsHeldPastALedWallEndKeepTurning(both wrappers for 300 updates; never 30 updates without motion, over a full turn in all). Every update's view must be usable, with both sightlines clear. Both fail on 2dfc825f5, where the camera never moves.camera_mouse.cpp,camera_mouse.hppandcameracontrol.cpp, the round-1 regressions and five rewritten wall tests failed (8 of 21CameraMousetests). That run predates rounds 2 and 3.-j2, head ca757e8): 1,867 passed, 54 skipped and none failed, plus one disabled test.GeoramaParts.PaintedFencesMatchRetailRecursion, which is intermittent even when run alone and also fails on the item-limit branch build, which has none of this camera code.MglibAspect.FloorMapPassagesAreSolidAt3840x2160timing out instead; PaintedFences passed in that run, and the GPU case passed in the earlier run.