Fix UICanvas adaptation issues (#2580)

* fix: the UICanvas.renderMode is CanvasRenderMode.ScreenSpaceCamera bug
 * fix: the issue with incorrect cache value of UICanvas._getCenter
 * fix: the issue that UICanvas did not refresh in time when setting the camera multiple times
This commit is contained in:
AZhan
2025-03-07 16:15:44 +08:00
committed by GitHub
parent c339685c69
commit e609141fac
2 changed files with 82 additions and 12 deletions

View File

@@ -7,6 +7,7 @@ import {
DisorderedArray,
Entity,
EntityModifyFlags,
Logger,
MathUtil,
Matrix,
Ray,
@@ -153,9 +154,22 @@ export class UICanvas extends Component implements IElement {
set renderCamera(value: Camera) {
const preCamera = this._renderCamera;
if (preCamera !== value) {
this._isSameOrChildEntity(value.entity) &&
Logger.warn(
"Camera entity matching or nested within the canvas entity disables canvas auto-adaptation in ScreenSpaceCamera mode."
);
this._renderCamera = value;
this._updateCameraObserver();
this._setRealRenderMode(this._getRealRenderMode());
const preRenderMode = this._realRenderMode;
const curRenderMode = this._getRealRenderMode();
if (preRenderMode === curRenderMode) {
if (curRenderMode === CanvasRenderMode.ScreenSpaceCamera) {
this._adapterPoseInScreenSpace();
this._adapterSizeInScreenSpace();
}
} else {
this._setRealRenderMode(curRenderMode);
}
}
}
@@ -318,8 +332,9 @@ export class UICanvas extends Component implements IElement {
case CanvasRenderMode.WorldSpace:
const boundsCenter = this._getCenter();
if (isOrthographic) {
Vector3.subtract(boundsCenter, cameraPosition, boundsCenter);
this._sortDistance = Vector3.dot(boundsCenter, cameraForward);
const distance = UICanvas._tempVec3;
Vector3.subtract(boundsCenter, cameraPosition, distance);
this._sortDistance = Vector3.dot(distance, cameraForward);
} else {
this._sortDistance = Vector3.distanceSquared(boundsCenter, cameraPosition);
}
@@ -382,15 +397,18 @@ export class UICanvas extends Component implements IElement {
const transform = this.entity.transform;
const realRenderMode = this._realRenderMode;
if (realRenderMode === CanvasRenderMode.ScreenSpaceCamera) {
const { transform: cameraTransform } = this._renderCamera.entity;
const { worldPosition: cameraWorldPosition, worldForward: cameraWorldForward } = cameraTransform;
const distance = this._distance;
transform.setWorldPosition(
cameraWorldPosition.x + cameraWorldForward.x * distance,
cameraWorldPosition.y + cameraWorldForward.y * distance,
cameraWorldPosition.z + cameraWorldForward.z * distance
);
transform.worldRotationQuaternion.copyFrom(cameraTransform.worldRotationQuaternion);
const cameraEntity = this._renderCamera.entity;
if (!this._isSameOrChildEntity(cameraEntity)) {
const { transform: cameraTransform } = cameraEntity;
const { worldPosition: cameraWorldPosition, worldForward: cameraWorldForward } = cameraTransform;
const distance = this._distance;
transform.setWorldPosition(
cameraWorldPosition.x + cameraWorldForward.x * distance,
cameraWorldPosition.y + cameraWorldForward.y * distance,
cameraWorldPosition.z + cameraWorldForward.z * distance
);
transform.worldRotationQuaternion.copyFrom(cameraTransform.worldRotationQuaternion);
}
} else {
const { canvas } = this.engine;
transform.setWorldPosition(canvas.width * 0.5, canvas.height * 0.5, 0);
@@ -646,6 +664,15 @@ export class UICanvas extends Component implements IElement {
}
}
}
private _isSameOrChildEntity(cameraEntity: Entity): boolean {
const canvasEntity = this.entity;
while (cameraEntity) {
if (cameraEntity === canvasEntity) return true;
cameraEntity = cameraEntity.parent;
}
return false;
}
}
/**

View File

@@ -95,6 +95,49 @@ describe("UICanvas", async () => {
expect(rootCanvas._isRootCanvas).to.eq(true);
});
// Pose
it("Pose Fit", () => {
const canvasTransform = <UITransform>canvasEntity.transform;
const canvasPosition = canvasTransform.position;
rootCanvas.referenceResolution = new Vector2(800, 600);
rootCanvas.renderMode = CanvasRenderMode.ScreenSpaceCamera;
rootCanvas.distance = 10;
canvasPosition.set(0, 0, 0);
expect(canvasPosition.x).to.eq(0);
expect(canvasPosition.y).to.eq(0);
expect(canvasPosition.z).to.eq(0);
// Same entity
const cameraSame = canvasEntity.addComponent(Camera);
rootCanvas.renderCamera = cameraSame;
expect(canvasPosition.x).to.eq(0);
expect(canvasPosition.y).to.eq(0);
expect(canvasPosition.z).to.eq(0);
rootCanvas.distance = 100;
expect(canvasPosition.x).to.eq(0);
expect(canvasPosition.y).to.eq(0);
expect(canvasPosition.z).to.eq(0);
// Not same entity or child entity
rootCanvas.renderCamera = camera;
expect(canvasPosition.x).to.eq(0);
expect(canvasPosition.y).to.eq(0);
expect(canvasPosition.z).to.eq(-100);
rootCanvas.distance = 10;
expect(canvasPosition.x).to.eq(0);
expect(canvasPosition.y).to.eq(0);
expect(canvasPosition.z).to.eq(-10);
// Child entity
const cameraEntityChild = canvasEntity.createChild("cameraChild");
const cameraChild = cameraEntityChild.addComponent(Camera);
cameraEntityChild.transform.setPosition(2, 2, 2);
rootCanvas.renderCamera = cameraChild;
expect(canvasPosition.x).to.eq(0);
expect(canvasPosition.y).to.eq(0);
expect(canvasPosition.z).to.eq(-10);
});
// Size
it("Size Fit", () => {
rootCanvas.referenceResolution = new Vector2(800, 600);