Skip to content

bugfix(view): Fix ground level of bookmarks, replay camera and game world microphone#2595

Open
xezon wants to merge 1 commit intoTheSuperHackers:mainfrom
xezon:xezon/fix-view-groundlevel
Open

bugfix(view): Fix ground level of bookmarks, replay camera and game world microphone#2595
xezon wants to merge 1 commit intoTheSuperHackers:mainfrom
xezon:xezon/fix-view-groundlevel

Conversation

@xezon
Copy link
Copy Markdown

@xezon xezon commented Apr 12, 2026

This change fixes the ground level of bookmarks, replay camera and the game world microphone by merging View::m_groundLevel into View::m_pos::z.

View::m_pos::z was originally unused and View::m_groundLevel was effectively that. They are now consolidated which automatically adds the ground level into bookmarks and the replay camera through ViewLocation (cool).

The game world microphone, used for positional audio, did not calculate the microphone height correctly which was fixed as well.

In View::lookAt the pivot is now reset to the ground which corrects behavior as well.

TODO

  • Replicate in Generals
  • Test a few cutscenes

…orld microphone

By merging View::m_groundLevel into View::m_pos::z
@xezon xezon added this to the Camera Improvements milestone Apr 12, 2026
@xezon xezon added Bug Something is not working right, typically is user facing Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Refactor Edits the code with insignificant behavior changes, is never user facing ThisProject The issue was introduced by this project, or this task is specific to this project labels Apr 12, 2026
@xezon
Copy link
Copy Markdown
Author

xezon commented Apr 12, 2026

Generals will fail to compile until replicated.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 12, 2026

Greptile Summary

This PR consolidates View::m_groundLevel into View::m_pos::z, so the camera pivot's z-coordinate now tracks the terrain height. This automatically propagates ground level into bookmarks and the replay camera via ViewLocation, and W3DView::lookAt now calls resetPivotToGround() after positioning.

  • The microphone zScale formula in GameAudio.cpp line 317 is broken on elevated terrain: desiredHeight is an absolute world height but is divided by a relative vector component, doubling the terrain height contribution and placing the audio listener too high. The fix is (desiredHeight - cameraPivot.z) / groundToCameraVector.z.

Confidence Score: 4/5

Safe to merge after fixing the microphone zScale formula; all other changes look correct

One P1 bug: the zScale calculation in GameAudio.cpp incorrectly uses an absolute desired height in a formula that expects a height relative to cameraPivot, producing a microphone placed terrain_height units too high on elevated maps. All other changes — pivot merging, bookmark/replay camera propagation, lookAt reset, and serialization — appear correct.

Core/GameEngine/Source/Common/Audio/GameAudio.cpp — line 317 zScale formula

Important Files Changed

Filename Overview
Core/GameEngine/Source/Common/Audio/GameAudio.cpp Bug in microphone placement: zScale uses absolute desiredHeight instead of desiredHeight - cameraPivot.z, causing the microphone to be placed terrain_height units too high on elevated terrain when zScale < maxPercentage
Core/GameEngine/Source/GameClient/View.cpp Serialization correctly XFers m_pos.z; lookAt now calls resetPivotToGround() after setPosition so old saves with z=0 are correctly corrected at load time
Core/GameEngine/Include/GameClient/View.h Header adds resetPivotToGround virtual, userResetPivotToGround helper, and removes m_groundLevel — the public API change looks clean
Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp Core refactor: m_pos.z now stores terrain ground level; movePivotToGround, resetPivotToGround, lookAt updated correctly; stale m_groundLevel comment at line 507
Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h Adds m_initialGroundLevel under PRESERVE_RETAIL_SCRIPTED_CAMERA guard for backward compat with scripted cameras; declaration of resetPivotToGround added
Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp No meaningful changes — only reads listener position set by AudioManager::update()

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["View::lookAt(pos)"] --> B["setPosition(pos)"]
    B --> C["resetPivotToGround()"]
    C --> D["m_pos.z = terrain height at x,y"]
    D --> E["m_pos now = {x, y, ground_z}"]

    E --> F["View::getLocation()"]
    F --> G["ViewLocation stores {x, y, ground_z, angle, pitch, zoom}"]
    G --> H["Bookmarks / Replay camera\n✅ ground level preserved"]

    E --> I["AudioManager::update()"]
    I --> J["cameraPivot = getPosition()\ncameraPivot.z = ground_z"]
    J --> K["desiredHeight = micDesiredHeight + ground_z"]
    J --> L["groundToCameraVector = cameraPos − cameraPivot"]
    K --> M{"cameraPos.z <= desiredHeight?"}
    M -- yes --> N["bestScale = maxPercentage"]
    M -- no --> O["zScale = desiredHeight / groundToCameraVector.z ⚠️\nShould be: (desiredHeight - cameraPivot.z) / groundToCameraVector.z"]
    O --> P["bestScale = MIN(maxPercentage, zScale)"]
    N --> Q["micPos = cameraPivot + bestScale × groundToCameraVector"]
    P --> Q
Loading

Comments Outside Diff (1)

  1. Core/GameEngine/Source/Common/Audio/GameAudio.cpp, line 317 (link)

    P1 Incorrect zScale formula doubles terrain height in microphone placement

    desiredHeight is an absolute world-space height (m_microphoneDesiredHeightAboveTerrain + cameraPivot.z), but groundToCameraVector is a relative vector (cameraPos − cameraPivot). Dividing the absolute height by the relative vector's z gives a scale that places the microphone at cameraPivot.z + desiredHeight = 2·terrain_height + m_microphoneDesiredHeightAboveTerrain instead of the intended terrain_height + m_microphoneDesiredHeightAboveTerrain.

    The formula was correct before this PR only because cameraPivot.z was always 0. Now that it stores the terrain height, the scale must account for the pivot offset:

    Concretely: terrain = 100 m, camera = 300 m, m_microphoneDesiredHeightAboveTerrain = 30 m, maxPercentage = 0.5.

    • Current code: zScale = 130/200 = 0.65, capped to 0.5 → mic at 100 + 100 = 200 m (70 m too high).
    • Fixed code: zScale = 30/200 = 0.15 → mic at 100 + 30 = 130 m ✓
    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: Core/GameEngine/Source/Common/Audio/GameAudio.cpp
    Line: 317
    
    Comment:
    **Incorrect `zScale` formula doubles terrain height in microphone placement**
    
    `desiredHeight` is an *absolute* world-space height (`m_microphoneDesiredHeightAboveTerrain + cameraPivot.z`), but `groundToCameraVector` is a *relative* vector (`cameraPos − cameraPivot`). Dividing the absolute height by the relative vector's z gives a scale that places the microphone at `cameraPivot.z + desiredHeight = 2·terrain_height + m_microphoneDesiredHeightAboveTerrain` instead of the intended `terrain_height + m_microphoneDesiredHeightAboveTerrain`.
    
    The formula was correct before this PR only because `cameraPivot.z` was always 0. Now that it stores the terrain height, the scale must account for the pivot offset:
    
    
    
    Concretely: terrain = 100 m, camera = 300 m, `m_microphoneDesiredHeightAboveTerrain` = 30 m, `maxPercentage` = 0.5.
    - **Current code**: `zScale = 130/200 = 0.65`, capped to 0.5 → mic at 100 + 100 = 200 m (70 m too high).
    - **Fixed code**: `zScale = 30/200 = 0.15` → mic at 100 + 30 = 130 m ✓
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: Core/GameEngine/Source/Common/Audio/GameAudio.cpp
Line: 317

Comment:
**Incorrect `zScale` formula doubles terrain height in microphone placement**

`desiredHeight` is an *absolute* world-space height (`m_microphoneDesiredHeightAboveTerrain + cameraPivot.z`), but `groundToCameraVector` is a *relative* vector (`cameraPos − cameraPivot`). Dividing the absolute height by the relative vector's z gives a scale that places the microphone at `cameraPivot.z + desiredHeight = 2·terrain_height + m_microphoneDesiredHeightAboveTerrain` instead of the intended `terrain_height + m_microphoneDesiredHeightAboveTerrain`.

The formula was correct before this PR only because `cameraPivot.z` was always 0. Now that it stores the terrain height, the scale must account for the pivot offset:

```suggestion
		Real zScale = (desiredHeight - cameraPivot.z) / groundToCameraVector.z;
```

Concretely: terrain = 100 m, camera = 300 m, `m_microphoneDesiredHeightAboveTerrain` = 30 m, `maxPercentage` = 0.5.
- **Current code**: `zScale = 130/200 = 0.65`, capped to 0.5 → mic at 100 + 100 = 200 m (70 m too high).
- **Fixed code**: `zScale = 30/200 = 0.15` → mic at 100 + 30 = 130 m ✓

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp
Line: 507

Comment:
**Stale comment references removed member `m_groundLevel`**

The comment still refers to `m_groundLevel` which was merged into `m_pos.z` by this PR.

```suggestion
-- they assume that all maps are height 'm_pos.z' at the edges.
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "bugfix(view): Fix ground level of bookma..." | Re-trigger Greptile

{
Coord3D groundPos, microphonePos;
TheTacticalView->getPosition( &groundPos );
Coord3D microphonePos;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to line 327 where it is used for the first time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Something is not working right, typically is user facing Gen Relates to Generals Minor Severity: Minor < Major < Critical < Blocker Refactor Edits the code with insignificant behavior changes, is never user facing ThisProject The issue was introduced by this project, or this task is specific to this project ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants