bugfix(view): Fix view ray cast behavior for mouse picks and drawable occlusion#2818
bugfix(view): Fix view ray cast behavior for mouse picks and drawable occlusion#2818xezon wants to merge 13 commits into
Conversation
|
| Filename | Overview |
|---|---|
| Core/Libraries/Source/WWVegas/WWMath/plane.h | Compute_Intersection return type changed from bool to IntersectionResType enum; enum values 0/1/2 preserve truthiness for old bool-style callers except OUTSIDE_LINE(2) is now truthy where the old code returned false — confirmed safe because no unmodified caller in the repo checks the return value. |
| Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp | screenToTerrain now returns Bool, screenToWorldAtZ returns IntersectionResType; pick-ray extended to sqr(Get_Depth()) to avoid far-clip truncation at low pitch; getAxisAlignedViewRegion falls back to draw region or map extent when view corners don't cleanly project onto Z=0. |
| Core/GameEngine/Source/GameClient/View.cpp | getScreenCornerWorldPointsAtZ returns worst-case IntersectionResType across all 4 corners; supports optional ViewportClass parameter for sub-viewport sampling; logic correctly distinguishes NO_INTERSECTION from OUTSIDE_LINE. |
| Core/GameEngineDevice/Source/W3DDevice/Common/System/W3DRadar.cpp | m_reconstructViewBox cleared at function entry (before early-return) so stale data persists on failure rather than triggering busy retries; variable renames start/end improve clarity; drawViewBox returns early on NO_INTERSECTION to avoid drawing an undefined box. |
| GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp | handleRadiusCursor, handleBuildPlacements, and triggerDoubleClickAttackMoveGuardHint all guarded against invalid terrain picks; placement icon and legality tint are only updated when a valid world position is available. |
| Core/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp | MSG_DOUBLE_CLICK_ATTACK_MOVE and MSG_MOUSE_LEFT_CLICK/RIGHT_CLICK handlers now break early when screenToTerrain fails; isPoint computed after the terrain check. |
| Core/GameEngineDevice/Source/W3DDevice/GameClient/WorldHeightMap.cpp | New getDrawRegion2D() helper extracts the existing inline heightmap-to-world-region computation into a reusable method. |
| Core/Libraries/Include/Lib/BaseType.h | setFromPointsNoZ renamed to setXYFromPoints; new setXY(Region2D) added; both intentionally leave Z unchanged, safe because all call sites unconditionally overwrite Z afterwards. |
| Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp | screenToTerrain return value checked; wave logic only executes on valid terrain hit; pauseWaves moved outside the terrain-check block. |
| GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp | Stub implementations updated to match the new signatures; all return appropriate NO_INTERSECTION / false defaults. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Input as Mouse Input
participant Caller as Command/UI Caller
participant View as W3DView
participant Ray as getPickRay
participant Terrain as TerrainRenderObj
participant Plane as PlaneClass
Input->>Caller: screen coordinate (ICoord2D)
alt screenToTerrain path
Caller->>View: screenToTerrain(screen, world)
View->>Ray: "getPickRay, rayEnd length = sqr(depth)"
Ray-->>View: line segment
View->>Terrain: Cast_Ray(lineseg)
alt terrain hit
Terrain-->>View: ContactPoint
View-->>Caller: "return true, world = hit point"
Caller->>Caller: issue game command
else no hit (sky / off-map)
Terrain-->>View: false
View-->>Caller: return false
Caller->>Caller: break / COMMAND_COMPLETE
end
end
alt screenToWorldAtZ path
Caller->>View: screenToWorldAtZ(screen, world, z)
View->>Ray: getPickRay
Ray-->>View: line segment
View->>Plane: Compute_Intersection(rayStart, rayEnd, t)
alt INSIDE_SEGMENT
Plane-->>View: INSIDE_SEGMENT
View-->>Caller: "return INSIDE_SEGMENT, world = intersection"
else OUTSIDE_LINE
Plane-->>View: OUTSIDE_LINE
View-->>Caller: "return OUTSIDE_LINE, world = extrapolated"
else NO_INTERSECTION
Plane-->>View: NO_INTERSECTION
View-->>Caller: return NO_INTERSECTION, world unchanged
end
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Input as Mouse Input
participant Caller as Command/UI Caller
participant View as W3DView
participant Ray as getPickRay
participant Terrain as TerrainRenderObj
participant Plane as PlaneClass
Input->>Caller: screen coordinate (ICoord2D)
alt screenToTerrain path
Caller->>View: screenToTerrain(screen, world)
View->>Ray: "getPickRay, rayEnd length = sqr(depth)"
Ray-->>View: line segment
View->>Terrain: Cast_Ray(lineseg)
alt terrain hit
Terrain-->>View: ContactPoint
View-->>Caller: "return true, world = hit point"
Caller->>Caller: issue game command
else no hit (sky / off-map)
Terrain-->>View: false
View-->>Caller: return false
Caller->>Caller: break / COMMAND_COMPLETE
end
end
alt screenToWorldAtZ path
Caller->>View: screenToWorldAtZ(screen, world, z)
View->>Ray: getPickRay
Ray-->>View: line segment
View->>Plane: Compute_Intersection(rayStart, rayEnd, t)
alt INSIDE_SEGMENT
Plane-->>View: INSIDE_SEGMENT
View-->>Caller: "return INSIDE_SEGMENT, world = intersection"
else OUTSIDE_LINE
Plane-->>View: OUTSIDE_LINE
View-->>Caller: "return OUTSIDE_LINE, world = extrapolated"
else NO_INTERSECTION
Plane-->>View: NO_INTERSECTION
View-->>Caller: return NO_INTERSECTION, world unchanged
end
end
Reviews (4): Last reviewed commit: "Fix style" | Re-trigger Greptile
… occlusion and radar box
7c85fda to
0db89be
Compare
| } | ||
| if( individualResults[i] == PlaneClass::OUTSIDE_LINE ) | ||
| { | ||
| combinedResult = PlaneClass::OUTSIDE_LINE; |
There was a problem hiding this comment.
No because NO_INTERSECTION will take precedence over OUTSIDE_LINE
stephanmeesters
left a comment
There was a problem hiding this comment.
Looks correct to me, also did a test using the map Arabia v2 and the issue is fixed as expected
This change fixes view ray casting behavior for mouse picks and drawable occlusion. The behavior for the radar view box is still not working correctly at low camera pitch but is otherwise still ok for regular top-down camera views. I do not yet know how to deal with the view box at low camera pitch.
The view ray now has a very long range making sure that the camera far clip plane is not limiting mouse picks. Also, view rays into the sky will no longer send units to 0,0,0: Invalid ray picks are now treated as no input.
The drawable updates made in the area created with
getAxisAlignedViewRegionare now working with low camera pitch. The function falls back to the terrain draw area if the view frustum does not fully intersect with the Z plane.Known issues
The Radar View Box still looks bad at low camera pitch as did always.
TODO