diff --git a/src/core/scene/scene-process/service/camera.ts b/src/core/scene/scene-process/service/camera.ts index d11a3e6c2..fa6b19673 100644 --- a/src/core/scene/scene-process/service/camera.ts +++ b/src/core/scene/scene-process/service/camera.ts @@ -165,7 +165,7 @@ export class CameraService extends BaseService implements ICamera if (config) { this._applyConfig(config, false); } - const gizmoConfig = await rpc.request('sceneConfigInstance', 'get', ['gizmo', 'local']) as Partial | undefined; + const gizmoConfig = await rpc.request('sceneConfigInstance', 'get', ['gizmo']) as Partial | undefined; if (gizmoConfig) { this._applyGizmoViewMode(gizmoConfig); this._applyGizmoDisplay(gizmoConfig); @@ -194,8 +194,7 @@ export class CameraService extends BaseService implements ICamera private _applyGizmoDisplay(config: Partial): void { if (config.gridVisible !== undefined) this.setGridVisible(config.gridVisible, false); if (config.gridColor !== undefined) this.setGridColor(config.gridColor); - if (config.originAxis2D !== undefined) this.setOriginAxes2D(config.originAxis2D); - if (config.originAxis3D !== undefined) this.setOriginAxes3D(config.originAxis3D); + this._syncControllerGridVisibility(); Service.Engine.repaintInEditMode(); } @@ -220,11 +219,13 @@ export class CameraService extends BaseService implements ICamera x: originAxes.x, y: originAxes.y, }); + this._syncControllerGridVisibility(); Service.Engine?.repaintInEditMode?.(); } setOriginAxes3D(originAxes: IOriginAxesConfig): void { (this._controller3D as any).updateOriginAxisByConfig?.(originAxes); + this._syncControllerGridVisibility(); Service.Engine?.repaintInEditMode?.(); } @@ -327,10 +328,7 @@ export class CameraService extends BaseService implements ICamera if (value === undefined || value === null) return; this._controller2D.isGridVisible = value; this._controller3D.isGridVisible = value; - const deActiveCtrl = this._controller === this._controller3D - ? this._controller2D - : this._controller3D; - deActiveCtrl.showGrid(false); + this._syncControllerGridVisibility(); Service.Engine.repaintInEditMode(); if (persist) { const rpc = Rpc.getInstance(); @@ -342,6 +340,16 @@ export class CameraService extends BaseService implements ICamera return this._controller?.isGridVisible ?? true; } + private _syncControllerGridVisibility(): void { + if (!this._controller || !this._controller2D || !this._controller3D) return; + const activeCtrl = this._controller; + const inactiveCtrl = activeCtrl === this._controller3D + ? this._controller2D + : this._controller3D; + activeCtrl.showGrid(activeCtrl.isGridVisible); + inactiveCtrl.showGrid(false); + } + setCameraProperty(options: any, persist = true): void { if (typeof options !== 'object' || !this._camera) return; Object.keys(options).forEach((key) => { diff --git a/src/core/scene/scene-process/service/camera/camera-controller-2d.ts b/src/core/scene/scene-process/service/camera/camera-controller-2d.ts index 185dd6d82..d0910ec10 100644 --- a/src/core/scene/scene-process/service/camera/camera-controller-2d.ts +++ b/src/core/scene/scene-process/service/camera/camera-controller-2d.ts @@ -8,6 +8,7 @@ import { IdleMode2D } from './modes/idle-mode-2d'; import { PanMode2D } from './modes/pan-mode-2d'; import { tweenPosition } from './tween'; import type { ISceneMouseEvent, ISceneKeyboardEvent } from '../operation/types'; +import { Rpc } from '../../rpc'; function getCanvasSize(): ISizeLike { const canvas = (cc as any).game?.canvas; @@ -77,7 +78,7 @@ export class CameraController2D extends CameraControllerBase { showGrid(visible: boolean) { super.showGrid(visible); if (this._originAxisHorizontalMeshComp?.node) { - this._originAxisHorizontalMeshComp.node.active = visible; + this._originAxisHorizontalMeshComp.node.active = visible && (this.originAxisX_Visible || this.originAxisY_Visible); } } @@ -382,6 +383,22 @@ export class CameraController2D extends CameraControllerBase { this.originAxisX_Visible = true; this.originAxisY_Visible = true; this._originAxisHorizontalMeshComp.node.active = false; + void this.initOriginAxisFromConfig(); + } + + private async initOriginAxisFromConfig() { + try { + const rpc = Rpc.getInstance(); + const gizmos = await rpc.request('sceneConfigInstance', 'get', ['gizmo']) as any; + if (gizmos?.originAxis2D) { + this.updateOriginAxisByConfig({ + x: gizmos.originAxis2D.x, + y: gizmos.originAxis2D.y, + }, false); + } + } catch { + // Use the default 2D origin axes when config is unavailable. + } } updateOriginAxisByConfig(config: { x?: boolean; y?: boolean }, update = true) { @@ -390,7 +407,7 @@ export class CameraController2D extends CameraControllerBase { const showAxis = this.originAxisX_Visible || this.originAxisY_Visible; if (this._originAxisHorizontalMeshComp?.node) { - this._originAxisHorizontalMeshComp.node.active = showAxis; + this._originAxisHorizontalMeshComp.node.active = !!this._gridMeshComp?.node?.active && showAxis; } if (update) { diff --git a/src/core/scene/scene-process/service/camera/camera-controller-3d.ts b/src/core/scene/scene-process/service/camera/camera-controller-3d.ts index 419ae7b97..f73d40c58 100644 --- a/src/core/scene/scene-process/service/camera/camera-controller-3d.ts +++ b/src/core/scene/scene-process/service/camera/camera-controller-3d.ts @@ -12,6 +12,7 @@ import type ModeBase3D from './modes/mode-base-3d'; import type { ISceneMouseEvent, ISceneKeyboardEvent } from '../operation/types'; import { Service } from '../core/decorator'; import { getRaycastResultsForSnap } from '../gizmo/utils/engine-utils'; +import { Rpc } from '../../rpc'; // ---------- node utility helpers ---------- @@ -499,10 +500,10 @@ export class CameraController3D extends CameraControllerBase { showGrid(visible: boolean) { super.showGrid(visible); if (this._originAxisHorizontalMeshComp?.node) { - this._originAxisHorizontalMeshComp.node.active = visible; + this._originAxisHorizontalMeshComp.node.active = visible && (this.originAxisX_Visible || this.originAxisZ_Visible); } if (this._originAxisVerticalMeshComp?.node) { - this._originAxisVerticalMeshComp.node.active = visible; + this._originAxisVerticalMeshComp.node.active = visible && this.originAxisY_Visible; } } @@ -519,6 +520,19 @@ export class CameraController3D extends CameraControllerBase { this.originAxisZ_Visible = true; this._originAxisHorizontalMeshComp.node.active = (this.originAxisX_Visible || this.originAxisZ_Visible); this._originAxisVerticalMeshComp.node.active = this.originAxisY_Visible; + void this.initOriginAxisFromConfig(); + } + + private async initOriginAxisFromConfig() { + try { + const rpc = Rpc.getInstance(); + const gizmos = await rpc.request('sceneConfigInstance', 'get', ['gizmo']) as any; + if (gizmos?.originAxis3D) { + this.updateOriginAxisByConfig(gizmos.originAxis3D, false); + } + } catch { + // Use the default 3D origin axes when config is unavailable. + } } updateOriginAxisByConfig(config: { x?: boolean; y?: boolean; z?: boolean }, update = true) { @@ -527,10 +541,10 @@ export class CameraController3D extends CameraControllerBase { if (config.z !== undefined) this.originAxisZ_Visible = config.z; if (this._originAxisHorizontalMeshComp?.node) { - this._originAxisHorizontalMeshComp.node.active = (this.originAxisX_Visible || this.originAxisZ_Visible); + this._originAxisHorizontalMeshComp.node.active = !!this._gridMeshComp?.node?.active && (this.originAxisX_Visible || this.originAxisZ_Visible); } if (this._originAxisVerticalMeshComp?.node) { - this._originAxisVerticalMeshComp.node.active = this.originAxisY_Visible; + this._originAxisVerticalMeshComp.node.active = !!this._gridMeshComp?.node?.active && this.originAxisY_Visible; } if (update) { @@ -565,8 +579,6 @@ export class CameraController3D extends CameraControllerBase { } private updateOriginAxisVertical() { - if (!this._originAxisVerticalMeshComp?.node?.active) return; - const { startY, endY, cameraPos } = this.getOriginAxisData(); const positions: number[] = []; const colors: number[] = []; @@ -594,8 +606,6 @@ export class CameraController3D extends CameraControllerBase { } private updateOriginAxisHorizontal() { - if (!this._originAxisHorizontalMeshComp?.node?.active) return; - const { startY, endY, startX, endX, cameraPos } = this.getOriginAxisData(); const positions: number[] = []; const colors: number[] = []; diff --git a/src/core/scene/test/camera-view-mode-config.test.ts b/src/core/scene/test/camera-view-mode-config.test.ts index 2d25bb30b..3c599f195 100644 --- a/src/core/scene/test/camera-view-mode-config.test.ts +++ b/src/core/scene/test/camera-view-mode-config.test.ts @@ -31,6 +31,7 @@ class MockController { init = jest.fn(); on = jest.fn(); updateGrid = jest.fn(); + updateOriginAxisByConfig = jest.fn(); refresh = jest.fn(); focus = jest.fn(); showGrid = jest.fn(); @@ -172,6 +173,46 @@ describe('CameraService view mode config', () => { expect(camera.is2D).toBe(true); expect(defaultFocus).toHaveBeenCalledWith('scene-uuid'); }); + + it('loads merged gizmo config without applying origin axes in CameraService', async () => { + const originAxis3D = { x: true, y: false, z: true }; + mockRpcRequest.mockImplementation((_service, _method, args) => { + const [key] = args; + if (key === 'gizmo') return Promise.resolve({ is2D: false, originAxis3D }); + return Promise.resolve(undefined); + }); + + const { CameraService } = require('../scene-process/service/camera'); + const camera = new CameraService(); + camera.init(); + + camera.onEditorOpened(); + await flushConfigRestore(); + + expect(mockRpcRequest).toHaveBeenCalledWith('sceneConfigInstance', 'get', ['gizmo']); + expect(mockRpcRequest).not.toHaveBeenCalledWith('sceneConfigInstance', 'get', ['gizmo', 'local']); + expect(camera.controller2D.updateOriginAxisByConfig).not.toHaveBeenCalled(); + expect(camera.controller3D.updateOriginAxisByConfig).not.toHaveBeenCalled(); + }); + + it('keeps the inactive controller grid hidden when origin axes are updated externally', () => { + const originAxis2D = { x: true, y: true, z: false }; + const originAxis3D = { x: true, y: false, z: true }; + + const { CameraService } = require('../scene-process/service/camera'); + const camera = new CameraService(); + camera.init(); + camera.setOriginAxes2D(originAxis2D); + camera.setOriginAxes3D(originAxis3D); + + expect(camera.controller2D.updateOriginAxisByConfig).toHaveBeenCalledWith({ + x: originAxis2D.x, + y: originAxis2D.y, + }); + expect(camera.controller3D.updateOriginAxisByConfig).toHaveBeenCalledWith(originAxis3D); + expect(camera.controller2D.showGrid).toHaveBeenLastCalledWith(false); + expect(camera.controller3D.showGrid).toHaveBeenLastCalledWith(true); + }); }); export {};