mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-05-03 02:53:57 +00:00
92 lines
3.9 KiB
Markdown
92 lines
3.9 KiB
Markdown
# ROI Direction Conventions & Third-Person Camera
|
|
|
|
## Background: The Two Z-Axis Conventions
|
|
|
|
The game engine represents an actor's facing direction via the z-axis of its ROI
|
|
(Real-time Object Instance) local-to-world transform. Two opposite conventions
|
|
exist throughout the codebase:
|
|
|
|
| Convention | ROI z-axis points... | Used by |
|
|
|----------------|--------------------------|--------------------------------------------------------|
|
|
| **forward-z** | Toward visual forward | `PlaceActor` (with `m_cameraFlag=TRUE`), cam anim end |
|
|
| **backward-z** | Away from visual forward | After `Enter()`'s `TurnAround()`, vehicle ROIs |
|
|
|
|
Toggling between conventions is done by `IslePathActor::TurnAround` (or the
|
|
local `FlipMatrixDirection` helper): negate the z-axis and recompute the right
|
|
vector.
|
|
|
|
## Design Choice: Forward-Z
|
|
|
|
The third-person orbit camera uses **forward-z**, matching the convention that
|
|
`PlaceActor` naturally produces. This eliminates the need to flip the ROI
|
|
direction after every `PlaceActor` call.
|
|
|
|
`ComputeOrbitVectors` treats local Z+ as the character's visual forward and
|
|
places the camera at local -Z (behind the character), looking toward +Z.
|
|
|
|
## Engine Behavior
|
|
|
|
The engine's actor lifecycle:
|
|
|
|
```
|
|
Enter()
|
|
-> ResetWorldTransform(TRUE) sets m_cameraFlag = TRUE
|
|
-> TurnAround() flips to backward-z
|
|
-> TransformPointOfView() sets 1st-person camera
|
|
|
|
PlaceActor() resets to forward-z <- what we use
|
|
```
|
|
|
|
`PlaceActor` always produces forward-z (when `m_cameraFlag=TRUE`), which is
|
|
exactly what the orbit camera expects. No direction correction is needed after
|
|
`PlaceActor` runs.
|
|
|
|
## World Transition Timing
|
|
|
|
The one remaining complexity is timing during world transitions. The event order
|
|
is:
|
|
|
|
1. `OnWorldEnabled` fires (from `LegoWorld::Enable`, BEFORE `SpawnPlayer`)
|
|
2. `ReinitForCharacter` sets up the display ROI and marks `m_active = true`
|
|
3. `Enter()` fires `OnActorEnter` -- ROI is at **stale position** from previous session
|
|
4. `PlaceActor` sets ROI to correct spawn position
|
|
5. First `Tick` -- `ApplyOrbitCamera` sets the camera at the correct position
|
|
|
|
Between steps 3 and 5, the ROI position is stale. If we set up the orbit camera
|
|
in step 3, the stale view would freeze on screen during the ~500ms world load.
|
|
|
|
The `m_pendingWorldTransition` flag handles this: set in `OnWorldEnabled`,
|
|
it causes `OnActorEnter` and `ReinitForCharacter` to skip camera setup.
|
|
Cleared in the first `Tick` after `PlaceActor`, where `ApplyOrbitCamera`
|
|
naturally handles the camera. The orbit state (yaw, pitch, distance) is also
|
|
reset to defaults in `OnWorldEnabled`.
|
|
|
|
## Display Clone Direction
|
|
|
|
The native actor ROI is invisible in 3rd-person mode. A display clone renders
|
|
the character model instead. Character meshes face -z, so the clone needs
|
|
backward-z to look correct. When syncing the clone's transform from the native
|
|
ROI (which is in forward-z), `Tick` negates the z-axis and recomputes the right
|
|
vector -- the same operation as `TurnAround`.
|
|
|
|
This also affects the right vector (X-axis): forward-z and backward-z produce
|
|
opposite right vectors. The orbit yaw input is negated to compensate, keeping
|
|
drag-right = camera-moves-right.
|
|
|
|
## Cam Anim Interaction
|
|
|
|
While a cam anim locks the player (`GetActorState() == c_disabled`), two
|
|
things protect the orbit camera:
|
|
|
|
1. **Tick guard**: `ApplyOrbitCamera` is skipped so it doesn't fight the cam
|
|
anim's `TransformPointOfView`. Without this, the cam anim end handler would
|
|
read our elevated orbit camera position and place the actor in the air.
|
|
|
|
2. **`OnCamAnimEnd`**: When the cam anim releases the player (first space bar
|
|
interruption or natural end), this callback calls `SetupCamera` to restore
|
|
the orbit camera.
|
|
|
|
After the first interruption, the actor state resets to `c_initial` and the
|
|
orbit camera resumes immediately -- even if `m_animRunning` is still true for
|
|
background animations playing in the world.
|