fix: 优化Gizmo
This commit is contained in:
@@ -3,6 +3,7 @@ import userEvent from "@testing-library/user-event";
|
||||
import { afterEach, beforeEach, vi } from "vitest";
|
||||
import { clearViewportCaptureHandler, setViewportCaptureHandler } from "../io/captureBridge";
|
||||
import { createInitialDirectorState, useDirectorStore } from "../store/directorStore";
|
||||
import { DEFAULT_DIRECTOR_CAMERA_VIEW_SNAPSHOT, getCameraLookRotationFromTarget } from "../schema/cameraGeometry";
|
||||
import { CameraPanel } from "./CameraPanel";
|
||||
|
||||
function seedCameraCapture() {
|
||||
@@ -98,7 +99,9 @@ it("renders the approved camera panel fields", () => {
|
||||
expect(screen.getByLabelText("切换机位")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("机位位置 X")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("注视目标模式")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("注视坐标 X")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("机位水平角")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("机位俯仰角")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("机位横滚角")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("机位 FOV")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -181,7 +184,7 @@ it("renders target mode as the custom dropdown menu", async () => {
|
||||
await user.click(screen.getByLabelText("注视目标模式"));
|
||||
|
||||
const menu = screen.getByRole("listbox", { name: "注视目标模式" });
|
||||
const manualOption = within(menu).getByRole("option", { name: "手动坐标" });
|
||||
const manualOption = within(menu).getByRole("option", { name: "手动角度" });
|
||||
|
||||
expect(menu).toHaveClass("inspector-dropdown-menu");
|
||||
expect(manualOption).toHaveClass("is-selected");
|
||||
@@ -200,7 +203,7 @@ it("lists visible viewport models as camera focus targets and centers on the sel
|
||||
const menu = screen.getByRole("listbox", { name: "注视目标模式" });
|
||||
const modelNames = within(menu).getAllByRole("option").map((option) => option.textContent);
|
||||
|
||||
expect(modelNames).toEqual(["手动坐标", "角色01", "角色02", "立方体"]);
|
||||
expect(modelNames).toEqual(["手动角度", "角色01", "角色02", "立方体"]);
|
||||
expect(within(menu).queryByRole("option", { name: "机位01" })).not.toBeInTheDocument();
|
||||
|
||||
await user.click(within(menu).getByRole("option", { name: "角色02" }));
|
||||
@@ -212,14 +215,18 @@ it("lists visible viewport models as camera focus targets and centers on the sel
|
||||
expect(focusedObject).toBeTruthy();
|
||||
expect(camera?.targetMode).toBe("object");
|
||||
expect(camera?.targetObjectId).toBe(focusedObject?.id);
|
||||
expect(camera?.target).toEqual([-1.25, 0.99, 0]);
|
||||
// 锁定物体 = 把「机位 → 物体」这条视线换算成注视朝向角
|
||||
expect(camera?.lookRotation).toEqual(
|
||||
getCameraLookRotationFromTarget(camera!.transform.position, [-1.25, 0.99, 0])
|
||||
);
|
||||
expect(screen.getByLabelText("注视目标模式")).toHaveTextContent("角色02");
|
||||
expect(screen.getByLabelText("注视坐标 X")).toHaveValue(-1.25);
|
||||
expect(screen.getByLabelText("注视坐标 Y")).toHaveValue(0.99);
|
||||
expect(screen.getByLabelText("注视坐标 Z")).toHaveValue(0);
|
||||
// rotation = [俯仰角 pitch(X), 水平角 yaw(Y), 横滚角 roll(Z)]
|
||||
expect(screen.getByLabelText("机位水平角")).toHaveValue(camera!.lookRotation[1]);
|
||||
expect(screen.getByLabelText("机位俯仰角")).toHaveValue(camera!.lookRotation[0]);
|
||||
expect(screen.getByLabelText("机位横滚角")).toHaveValue(camera!.lookRotation[2]);
|
||||
});
|
||||
|
||||
it("resets the camera position and the look-at target from their own title buttons", async () => {
|
||||
it("resets the camera position and the look angles from their own buttons", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<CameraPanel />);
|
||||
|
||||
@@ -227,7 +234,12 @@ it("resets the camera position and the look-at target from their own title butto
|
||||
const seededCamera = readCamera();
|
||||
expect(seededCamera).toBeTruthy();
|
||||
|
||||
["位置", "注视坐标"].forEach((label) => {
|
||||
const positionReset = within(screen.getByRole("group", { name: "位置" })).getByRole("button", { name: "重置位置" });
|
||||
expect(positionReset).toHaveClass("inspector-axis-reset-button");
|
||||
expect(positionReset.querySelector("svg")).toBeInTheDocument();
|
||||
|
||||
// 三个角度各自一行,行首带重置按钮
|
||||
["水平角", "俯仰角", "横滚角"].forEach((label) => {
|
||||
const button = within(screen.getByRole("group", { name: label })).getByRole("button", { name: `重置${label}` });
|
||||
|
||||
expect(button).toHaveClass("inspector-axis-reset-button");
|
||||
@@ -236,24 +248,32 @@ it("resets the camera position and the look-at target from their own title butto
|
||||
|
||||
useDirectorStore.getState().updateCamera("cam_1", {
|
||||
transform: { ...seededCamera!.transform, position: [7, 3, 7] },
|
||||
target: [1, 2, 3],
|
||||
lookRotation: [12, 34, 56],
|
||||
});
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "重置位置" }));
|
||||
|
||||
// 机位回到默认机位位置(不是归零:相机压在世界原点会让视线方向退化)
|
||||
expect(readCamera()?.transform.position).toEqual([0, 1.55, 5.4]);
|
||||
// 只重置位置,注视点保持原样
|
||||
expect(readCamera()?.target).toEqual([1, 2, 3]);
|
||||
// 只重置位置,注视朝向保持原样
|
||||
expect(readCamera()?.lookRotation).toEqual([12, 34, 56]);
|
||||
|
||||
await user.click(screen.getByRole("button", { name: "重置注视坐标" }));
|
||||
// 单独重置「俯仰角」→ 归零(水平),不带动水平角 / 横滚角
|
||||
await user.click(within(screen.getByRole("group", { name: "俯仰角" })).getByRole("button", { name: "重置俯仰角" }));
|
||||
expect(readCamera()?.lookRotation).toEqual([0, 34, 56]);
|
||||
|
||||
expect(readCamera()?.target).toEqual([0, 1.05, 0]);
|
||||
await user.click(screen.getByRole("button", { name: "重置注视角度" }));
|
||||
|
||||
// 俯仰角重置为水平 0°,水平角 / 横滚角回到默认机位
|
||||
expect(readCamera()?.lookRotation).toEqual([
|
||||
0,
|
||||
DEFAULT_DIRECTOR_CAMERA_VIEW_SNAPSHOT.lookRotation[1],
|
||||
DEFAULT_DIRECTOR_CAMERA_VIEW_SNAPSHOT.lookRotation[2],
|
||||
]);
|
||||
expect(readCamera()?.targetMode).toBe("manual");
|
||||
expect(screen.getByLabelText("注视坐标 Z")).toHaveValue(0);
|
||||
});
|
||||
|
||||
it("updates camera position and target coordinates across all axes", async () => {
|
||||
it("updates camera position and look angles across all axes", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<CameraPanel />);
|
||||
|
||||
@@ -261,14 +281,15 @@ it("updates camera position and target coordinates across all axes", async () =>
|
||||
await user.type(screen.getByLabelText("机位位置 Y"), "3.4");
|
||||
await user.clear(screen.getByLabelText("机位位置 Z"));
|
||||
await user.type(screen.getByLabelText("机位位置 Z"), "7.5");
|
||||
await user.clear(screen.getByLabelText("注视坐标 Y"));
|
||||
await user.type(screen.getByLabelText("注视坐标 Y"), "1.8");
|
||||
await user.clear(screen.getByLabelText("注视坐标 Z"));
|
||||
await user.type(screen.getByLabelText("注视坐标 Z"), "2");
|
||||
await user.clear(screen.getByLabelText("机位水平角"));
|
||||
await user.type(screen.getByLabelText("机位水平角"), "210");
|
||||
await user.clear(screen.getByLabelText("机位俯仰角"));
|
||||
await user.type(screen.getByLabelText("机位俯仰角"), "12");
|
||||
|
||||
const camera = useDirectorStore.getState().project.cameras[0];
|
||||
expect(camera.transform.position).toEqual([0, 3.4, 7.5]);
|
||||
expect(camera.target).toEqual([0, 1.8, 2]);
|
||||
// lookRotation = [俯仰角 pitch(X), 水平角 yaw(Y), 横滚角 roll(Z)]
|
||||
expect(camera.lookRotation).toEqual([12, 210, 0]);
|
||||
});
|
||||
|
||||
it("captures the current camera preview from the properties tab and shows it in the screenshots overview", async () => {
|
||||
|
||||
Reference in New Issue
Block a user