Skip to content

Add camera-based event filtering for WorldSpace UICanvas#2870

Merged
cptbtptpbcptdtptp merged 13 commits intogalacean:dev/2.0from
ym2050:feat/worldspace-event-camera
Feb 28, 2026
Merged

Add camera-based event filtering for WorldSpace UICanvas#2870
cptbtptpbcptdtptp merged 13 commits intogalacean:dev/2.0from
ym2050:feat/worldspace-event-camera

Conversation

@ym2050
Copy link
Copy Markdown

@ym2050 ym2050 commented Dec 11, 2025

Summary

WorldSpace canvases previously had no way to control which camera handles their UI events — all cameras with overlapping viewports could trigger events, leading to unintended interactions in multi-camera setups.

This PR extends the camera property to WorldSpace mode for event detection:

  • WorldSpace: When camera is assigned, only that camera can trigger UI events on this canvas. If unset, events fall back to the highest-priority camera (existing behavior).
  • ScreenSpaceCamera: Unchanged — controls rendering adaptation as before.

Additionally:

  • Renamed renderCameracamera (with renderCamera deprecated), since it now serves both rendering and event roles across modes.
  • Added _canProcessEvent() to decouple event filtering from render filtering (_canRender), fixing a bug where ScreenSpaceCamera fallback to ScreenSpaceOverlay would block all events.

User Value

Minimap without RenderTarget: A minimap camera uses a small viewport overlapping the main camera's full-screen viewport. Both cameras can see and raycast against WorldSpace UI in the scene. When the player clicks in the overlapping area, the minimap camera's ray could incorrectly trigger WorldSpace UI events meant for the main scene.

Overlay cameras without color clearing: Multiple cameras render to the same viewport without clearing the color buffer (e.g., for layered composition). All cameras can raycast against the same WorldSpace UI, causing duplicate or unintended event triggers.

By assigning canvas.camera = mainCamera, developers can restrict event detection to the intended camera in both scenarios.

Behavior Changes

Mode Condition Before After
ScreenSpaceOverlay All cameras (unchanged) All cameras (unchanged)
ScreenSpaceCamera With camera Only that camera Only that camera
ScreenSpaceCamera Fallback (no camera) All cameras blocked (bug) All cameras pass (fix)
WorldSpace With camera All cameras Only that camera (new)
WorldSpace No camera All cameras All cameras

Changes

  • Add _canProcessEvent() to decouple event filtering from render filtering (_canRender)
  • Use _canProcessEvent() in UIPointerEventEmitter for event dispatch
  • Rename renderCameracamera, deprecate renderCamera as proxy
  • Rename internal _renderCamera_camera

Test Plan

  • WorldSpace: no camera set → all cameras can process events
  • WorldSpace: camera set → only that camera can process events
  • ScreenSpaceCamera: only assigned camera can process events
  • ScreenSpaceCamera: fallback to ScreenSpaceOverlay → all cameras can process events
  • Clone preserves camera in both ScreenSpaceCamera and WorldSpace modes
  • renderCamera deprecated proxy still works

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 11, 2025

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds eventCamera support to UICanvas (storage, getter/setter, validation), per-camera event eligibility via _canProcessEvent, propagation of eventCamera during cloning, updates UIPointerEventEmitter to consult _canProcessEvent for pointer raycasts, and adds tests (with duplicated blocks) for these behaviors.

Changes

Cohort / File(s) Summary
UICanvas core
packages/ui/src/component/UICanvas.ts
Added private _eventCamera, public get/set eventCamera with validation and warnings, implemented _canProcessEvent(camera): boolean, clear _eventCamera when leaving WorldSpace, added _cloneCamera and updated _cloneTo to propagate eventCamera (resolve by entity path when possible).
Pointer event integration
packages/ui/src/input/UIPointerEventEmitter.ts
Replaced canvas eligibility check from canvas._canRender(camera) to canvas._canProcessEvent(camera) in processRaycast so pointer raycasts respect eventCamera rules.
Tests
tests/src/ui/UICanvas.test.ts
Added tests for setting/clearing eventCamera, _canProcessEvent behavior across WorldSpace and ScreenSpaceCamera modes, and cloning preservation of eventCamera. Note: test blocks appear duplicated in file.

Sequence Diagram(s)

sequenceDiagram
    participant Pointer as Pointer Input
    participant Emitter as UIPointerEventEmitter
    participant Canvas as UICanvas
    participant Camera as Camera

    Pointer->>Emitter: deliver pointer event (with Camera)
    Emitter->>Emitter: processRaycast(camera)
    loop each canvas
        Emitter->>Canvas: _canProcessEvent(camera)?
        alt Canvas.renderMode == WorldSpace and Canvas.eventCamera != null
            Canvas->>Camera: compare provided Camera to eventCamera
            Camera-->>Canvas: match / no match
        else Canvas.renderMode == ScreenSpaceCamera and Canvas.renderCamera != null
            Canvas->>Camera: compare provided Camera to renderCamera
            Camera-->>Canvas: match / no match
        else
            Canvas-->>Emitter: eligible
        end
        alt eligible
            Emitter->>Canvas: perform raycast & dispatch events
            Canvas-->>Emitter: hit (may return early) / miss
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I nudged a lens into the light,
WorldSpace knows which camera's right.
Rays hop straight, events find their way,
Cloned and set, they work today. 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR fully addresses issue #2793 by providing eventCamera property to specify which camera handles UI events for WorldSpace UICanvas, resolving the ambiguity in multi-camera scenes.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing eventCamera support for WorldSpace UICanvas; no extraneous modifications were introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title accurately and clearly describes the main change: adding eventCamera-based event filtering for WorldSpace UICanvas, which is the primary focus of the changeset.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/ui/src/component/UICanvas.ts (1)

181-204: Consider clearing eventCamera when renderMode changes away from WorldSpace.

The setter correctly warns when eventCamera is set in non-WorldSpace mode, but the eventCamera value persists. If a user sets eventCamera while in WorldSpace, then later changes renderMode to ScreenSpaceCamera, the eventCamera reference remains set (though ineffective). This could cause confusion when switching back to WorldSpace.

Consider clearing eventCamera when renderMode changes, or documenting this behavior explicitly. For reference, here's how the renderMode setter could be updated:

 set renderMode(mode: CanvasRenderMode) {
   const preMode = this._renderMode;
   if (preMode !== mode) {
     this._renderMode = mode;
+    if (mode !== CanvasRenderMode.WorldSpace && this._eventCamera) {
+      Logger.warn("EventCamera has been cleared because render mode is no longer WorldSpace.");
+      this._eventCamera = null;
+    }
     this._updateCameraObserver();
     this._setRealRenderMode(this._getRealRenderMode());
   }
 }
tests/src/ui/UICanvas.test.ts (2)

304-321: Unused variable camera2 in test.

The camera2 variable is created but never used in this test. Consider removing it or adding assertions that validate behavior with multiple cameras.

 it("EventCamera for WorldSpace", () => {
-    const camera2 = root.createChild("camera2").addComponent(Camera);
-    
     rootCanvas.renderMode = CanvasRenderMode.WorldSpace;

323-341: Consider adding test coverage for ScreenSpaceCamera mode.

The test validates WorldSpace behavior well, but _canProcessEvent also handles ScreenSpaceCamera mode (returning renderCamera === camera). Adding a test case for ScreenSpaceCamera mode would improve coverage and document the expected behavior.

Example additional test:

it("_canProcessEvent with ScreenSpaceCamera mode", () => {
  const camera2 = root.createChild("cameraSSC").addComponent(Camera);
  
  rootCanvas.renderMode = CanvasRenderMode.ScreenSpaceCamera;
  rootCanvas.renderCamera = camera;
  
  // @ts-ignore
  expect(rootCanvas._canProcessEvent(camera)).to.be.true;
  // @ts-ignore
  expect(rootCanvas._canProcessEvent(camera2)).to.be.false;
});
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 01a56df and 5b8bad3.

📒 Files selected for processing (3)
  • packages/ui/src/component/UICanvas.ts (4 hunks)
  • packages/ui/src/input/UIPointerEventEmitter.ts (1 hunks)
  • tests/src/ui/UICanvas.test.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/src/ui/UICanvas.test.ts (3)
packages/core/src/index.ts (1)
  • Camera (16-16)
packages/ui/src/index.ts (1)
  • CanvasRenderMode (21-21)
packages/ui/src/component/index.ts (1)
  • UICanvas (1-1)
🔇 Additional comments (5)
packages/ui/src/component/UICanvas.ts (3)

84-86: LGTM! Field declaration follows established patterns.

The @ignoreClone decorator is correctly applied since the eventCamera is manually handled in _cloneTo, consistent with how _renderCamera is managed.


307-319: Logic is correct and handles all render modes appropriately.

The _canProcessEvent method correctly:

  1. Returns renderCamera === camera for ScreenSpaceCamera mode (consistent with _canRender)
  2. Filters by eventCamera in WorldSpace when set, otherwise allows all cameras
  3. Returns true for ScreenSpaceOverlay (implicit via the final return true)

However, there's a subtle difference from _canRender: ScreenSpaceOverlay is not explicitly handled here, but since Overlay canvases are processed separately in UIPointerEventEmitter.processRaycast (lines 44-54), this is acceptable.


444-454: Cloning logic correctly mirrors the renderCamera pattern.

The implementation properly resolves the eventCamera's entity within the cloned hierarchy when possible, falling back to the original reference otherwise. This ensures cloned canvases with local event cameras work correctly.

packages/ui/src/input/UIPointerEventEmitter.ts (1)

85-92: Correct integration of the new event processing predicate.

The change from _canRender(camera) to _canProcessEvent(camera) properly separates rendering eligibility from event processing eligibility. This allows WorldSpace canvases to filter which cameras can generate pointer events while _canRender continues to control rendering behavior.

tests/src/ui/UICanvas.test.ts (1)

343-363: Test correctly validates cloning behavior for eventCamera.

The test verifies both external camera references and local (child entity) camera references are properly handled during cloning, which matches the implementation in _cloneTo.

@ym2050
Copy link
Copy Markdown
Author

ym2050 commented Dec 11, 2025

#2793

Comment thread packages/ui/src/component/UICanvas.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/ui/src/component/UICanvas.ts (1)

307-325: Consider basing _canProcessEvent on _realRenderMode and unifying comment language

Right now _canProcessEvent branches on this._renderMode. However, _getRealRenderMode() can downgrade ScreenSpaceCamera to ScreenSpaceOverlay when renderCamera is missing/disabled. In that fallback, the canvas will render as overlay but _canProcessEvent will still behave as if it were ScreenSpaceCamera and return false for all cameras because _renderCamera is null. If the intent is for pointer events to follow the actual effective render mode, using _realRenderMode (with a None fallback to _renderMode) would be more consistent.

For example:

-  _canProcessEvent(camera: Camera): boolean {
-    // WorldSpace模式下,如果设置了eventCamera,则只允许该相机处理事件
-    if (this._renderMode === CanvasRenderMode.WorldSpace && this._eventCamera) {
+  _canProcessEvent(camera: Camera): boolean {
+    const mode =
+      this._realRenderMode !== CanvasRealRenderMode.None ? this._realRenderMode : this._renderMode;
+
+    // In WorldSpace, if eventCamera is set, only that camera can process events.
+    if (mode === CanvasRenderMode.WorldSpace && this._eventCamera) {
       return this._eventCamera === camera;
     }
-    // ScreenSpaceCamera模式下,只允许renderCamera处理事件(与_canRender保持一致)
-    if (this._renderMode === CanvasRenderMode.ScreenSpaceCamera) {
+    // In ScreenSpaceCamera, only renderCamera can process events (consistent with _canRender).
+    if (mode === CanvasRenderMode.ScreenSpaceCamera) {
       return this._renderCamera === camera;
     }
-    // ScreenSpaceOverlay模式和WorldSpace未设置eventCamera时,所有相机都可以处理事件
+    // In ScreenSpaceOverlay and WorldSpace without eventCamera, all cameras can process events.
     return true;
   }

This also replaces the mixed Chinese comments with English, which keeps the file’s comment language consistent.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b8bad3 and 02e5553.

📒 Files selected for processing (1)
  • packages/ui/src/component/UICanvas.ts (4 hunks)
🔇 Additional comments (3)
packages/ui/src/component/UICanvas.ts (3)

85-87: Initialization and cloning flags for _eventCamera are consistent with existing camera fields

_eventCamera is initialized to null and marked with @ignoreClone, with cloning handled explicitly in _cloneTo, mirroring how _renderCamera is treated. This is a clean, predictable way to manage the optional reference.


181-205: eventCamera accessor semantics match the documented behavior

The getter/setter and warnings align with the documentation: the camera is only effective in WorldSpace, but the value is still stored (so it starts working immediately if renderMode is later switched to WorldSpace), and entity nesting checks mirror renderCamera’s validation. No functional issues spotted here.


449-459: Event camera cloning logic correctly mirrors renderCamera handling

The _cloneTo block for eventCamera reuses _targetTempPath and Entity._getEntityHierarchyPath/_getEntityByHierarchyPath in the same way as renderCamera, with a safe fallback to the original eventCamera reference when the hierarchy lookup fails. This is a solid, predictable cloning strategy.

Comment thread packages/ui/src/component/UICanvas.ts Outdated
Comment thread packages/ui/src/component/UICanvas.ts Outdated
Copy link
Copy Markdown
Collaborator

@cptbtptpbcptdtptp cptbtptpbcptdtptp left a comment

Choose a reason for hiding this comment

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

质量很好的 PR,有两个小建议可以修复一下。

- Extract _cloneCamera method to reduce code duplication
- Add null check for _renderCamera in _canProcessEvent
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/ui/src/component/UICanvas.ts (3)

85-87: eventCamera lifecycle and warnings look good; minor optional behavior tweak

The _eventCamera field, its getter/setter, and the clearing logic in renderMode when leaving WorldSpace together match the intended behavior and keep existing setups unchanged when eventCamera is unset. This looks solid.

One small behavioral nit: eventCamera currently logs a warning when set while renderMode is not WorldSpace but still accepts and stores the value. If you expect users to often “preconfigure” eventCamera before switching renderMode to WorldSpace, this warning may be a bit noisy; you might consider either:

  • Downgrading it (e.g., to an info/debug‑level log), or
  • Only warning when leaving WorldSpace while eventCamera is set (you already do this in the renderMode setter).

Not required for correctness, just a usability consideration.

Also applies to: 141-149, 186-209


308-310: Align _canProcessEvent with _realRenderMode to match ScreenSpaceCamera → Overlay fallback

_canProcessEvent currently branches on _renderMode and _renderCamera. When renderMode === ScreenSpaceCamera but the render camera is effectively not usable (e.g., disabled), _getRealRenderMode() downgrades the canvas to ScreenSpaceOverlay, but _canProcessEvent will still only allow events from _renderCamera. That can lead to a situation where the canvas renders as overlay but never receives events from active cameras.

To make event routing follow the actual mode (as used by _prepareRender and _updateSortDistance), consider basing the decision on _realRenderMode instead of _renderMode:

-  _canProcessEvent(camera: Camera): boolean {
-    // WorldSpace mode: if eventCamera is set, only that camera can process events
-    if (this._renderMode === CanvasRenderMode.WorldSpace && this._eventCamera) {
-      return this._eventCamera === camera;
-    }
-    
-    // ScreenSpaceCamera mode: only renderCamera can process events (consistent with _canRender)
-    if (this._renderMode === CanvasRenderMode.ScreenSpaceCamera && this._renderCamera) {
-      return this._renderCamera === camera;
-    }
-    
-    // ScreenSpaceOverlay mode and WorldSpace without eventCamera: all cameras can process events
-    return true;
-  }
+  _canProcessEvent(camera: Camera): boolean {
+    const mode = this._realRenderMode;
+
+    // WorldSpace mode: if eventCamera is set, only that camera can process events
+    if (mode === CanvasRenderMode.WorldSpace && this._eventCamera) {
+      return this._eventCamera === camera;
+    }
+
+    // ScreenSpaceCamera mode: only the active renderCamera can process events
+    if (mode === CanvasRenderMode.ScreenSpaceCamera && this._renderCamera) {
+      return this._renderCamera === camera;
+    }
+
+    // ScreenSpaceOverlay, WorldSpace without eventCamera, or None: all cameras can process events
+    return true;
+  }

This keeps the new eventCamera behavior but avoids divergence between “real” render mode and event routing in ScreenSpaceCamera fallback cases.

Also applies to: 312-329, 705-712


441-463: Make _cloneCamera null‑aware and type‑safe for both renderCamera and eventCamera

_cloneCamera is typed as taking and returning Camera, but:

  • It is called with this._eventCamera, which is Camera | null.
  • Its implementation already handles a falsy camera (if (!camera) return camera;), so the signature doesn’t reflect actual usage.
  • If Entity._getEntityByHierarchyPath or getComponent(Camera) fail, you can end up returning undefined/null where a Camera is expected.

To better match usage and avoid future typing issues (especially if strictNullChecks is enabled), you can make _cloneCamera generic over Camera | null and be defensive about missing targets:

-  private _cloneCamera(camera: Camera, srcRoot: Entity, targetRoot: Entity): Camera {
-    if (!camera) {
-      return camera;
-    }
-    const paths = UICanvas._targetTempPath;
-    // @ts-ignore
-    const success = Entity._getEntityHierarchyPath(srcRoot, camera.entity, paths);
-    // @ts-ignore
-    return success
-      ? // @ts-ignore
-        Entity._getEntityByHierarchyPath(targetRoot, paths).getComponent(Camera)
-      : camera;
-  }
+  private _cloneCamera<T extends Camera | null>(camera: T, srcRoot: Entity, targetRoot: Entity): T {
+    if (!camera) {
+      return camera;
+    }
+    const paths = UICanvas._targetTempPath;
+    // @ts-ignore
+    const success = Entity._getEntityHierarchyPath(srcRoot, camera.entity, paths);
+    if (!success) {
+      return camera;
+    }
+    // @ts-ignore
+    const targetEntity = Entity._getEntityByHierarchyPath(targetRoot, paths);
+    const targetCamera = targetEntity?.getComponent(Camera) as T | null;
+    return (targetCamera ?? camera) as T;
+  }

With this, target.renderCamera = this._cloneCamera(this._renderCamera, ...) infers T = Camera, and target.eventCamera = this._cloneCamera(this._eventCamera, ...) infers T = Camera | null, matching the property types and avoiding implicit any/null leakage.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c2cc47 and 4bda744.

📒 Files selected for processing (1)
  • packages/ui/src/component/UICanvas.ts (5 hunks)

cptbtptpbcptdtptp

This comment was marked as resolved.

Copy link
Copy Markdown
Collaborator

@cptbtptpbcptdtptp cptbtptpbcptdtptp left a comment

Choose a reason for hiding this comment

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

+1

Comment thread packages/ui/src/component/UICanvas.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/ui/src/component/UICanvas.ts`:
- Around line 444-455: In _cloneCamera, when
Entity._getEntityByHierarchyPath(targetRoot, paths).getComponent(Camera) can be
null you should preserve the original camera instead of dropping it: after
resolving the target entity (using Entity._getEntityByHierarchyPath and the same
paths from Entity._getEntityHierarchyPath) check the result of
getComponent(Camera) and return that component if non-null, otherwise return the
original camera parameter; target the _cloneCamera function and the calls to
Entity._getEntityHierarchyPath / Entity._getEntityByHierarchyPath to add this
null-coalescing fallback.
- Around line 145-149: In UICanvas, stop clearing the stored event camera when
toggling render modes: remove the assignment this._eventCamera = null (and the
associated Logger.warn about clearing) inside the block that checks preMode ===
CanvasRenderMode.WorldSpace && mode !== CanvasRenderMode.WorldSpace; instead
leave this._eventCamera intact so it’s simply ignored when mode !==
CanvasRenderMode.WorldSpace, preserving user configuration across mode switches.
- Around line 317-322: The event filtering in _canProcessEvent currently checks
_renderMode instead of _realRenderMode, causing events to be rejected when a
render mode falls back (e.g., ScreenSpaceCamera -> ScreenSpaceOverlay); change
the condition to use _realRenderMode so the method reads the effective mode when
deciding whether to require _eventCamera, and keep the rest of the logic
(_eventCamera comparison and fallback to _canRender(camera)) unchanged; update
references in _canProcessEvent to replace _renderMode with _realRenderMode to
ensure ScreenSpaceCamera fallback behavior is handled correctly.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4bda744 and adf0aa5.

📒 Files selected for processing (1)
  • packages/ui/src/component/UICanvas.ts

Comment thread packages/ui/src/component/UICanvas.ts Outdated
Comment on lines +145 to +149
// Clear eventCamera when renderMode changes away from WorldSpace
if (preMode === CanvasRenderMode.WorldSpace && mode !== CanvasRenderMode.WorldSpace && this._eventCamera) {
Logger.warn("EventCamera has been cleared because render mode is no longer WorldSpace.");
this._eventCamera = null;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t clear eventCamera on render mode switches.

On Line 146–149, clearing the reference loses user configuration when toggling modes at runtime. Ignoring it outside WorldSpace is enough; state reset is unnecessary and can break expected behavior.

💡 Proposed fix
-      // Clear eventCamera when renderMode changes away from WorldSpace
-      if (preMode === CanvasRenderMode.WorldSpace && mode !== CanvasRenderMode.WorldSpace && this._eventCamera) {
-        Logger.warn("EventCamera has been cleared because render mode is no longer WorldSpace.");
-        this._eventCamera = null;
-      }
+      if (preMode === CanvasRenderMode.WorldSpace && mode !== CanvasRenderMode.WorldSpace && this._eventCamera) {
+        Logger.warn("eventCamera is ignored unless renderMode is WorldSpace.");
+      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui/src/component/UICanvas.ts` around lines 145 - 149, In UICanvas,
stop clearing the stored event camera when toggling render modes: remove the
assignment this._eventCamera = null (and the associated Logger.warn about
clearing) inside the block that checks preMode === CanvasRenderMode.WorldSpace
&& mode !== CanvasRenderMode.WorldSpace; instead leave this._eventCamera intact
so it’s simply ignored when mode !== CanvasRenderMode.WorldSpace, preserving
user configuration across mode switches.

Comment thread packages/ui/src/component/UICanvas.ts Outdated
Comment thread packages/ui/src/component/UICanvas.ts Outdated
@GuoLei1990 GuoLei1990 changed the title fix(ui): add eventCamera support for WorldSpace UICanvas (#2793) Add camera-based event filtering for WorldSpace UICanvas Feb 27, 2026
@GuoLei1990 GuoLei1990 added the enhancement New feature or request label Feb 27, 2026
@GuoLei1990 GuoLei1990 added the GUI label Feb 27, 2026
@GuoLei1990 GuoLei1990 changed the base branch from main to dev/2.0 February 27, 2026 14:34
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 27, 2026

Codecov Report

❌ Patch coverage is 92.30769% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.15%. Comparing base (01a56df) to head (23e625e).
⚠️ Report is 31 commits behind head on dev/2.0.

Files with missing lines Patch % Lines
packages/ui/src/component/UICanvas.ts 94.11% 3 Missing ⚠️
packages/ui/src/input/UIPointerEventEmitter.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           dev/2.0    #2870      +/-   ##
===========================================
- Coverage    78.96%   78.15%   -0.82%     
===========================================
  Files          857      880      +23     
  Lines        93517    96111    +2594     
  Branches      9378     9585     +207     
===========================================
+ Hits         73846    75113    +1267     
- Misses       19522    20836    +1314     
- Partials       149      162      +13     
Flag Coverage Δ
unittests 78.15% <92.30%> (-0.82%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Collaborator

@cptbtptpbcptdtptp cptbtptpbcptdtptp left a comment

Choose a reason for hiding this comment

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

+1

@cptbtptpbcptdtptp cptbtptpbcptdtptp merged commit 8e84ff8 into galacean:dev/2.0 Feb 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request GUI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants