取景视角限定在 (0, 180),非法值回落到默认视角

- packages/model3d-viewer/src/framing.ts:新增 normalizeFovDegrees,fovDegrees 只在 (0, 180) 内采用,>=180 时 tan(halfFovY) 非正会把 limitY/limitX 与 fallbackDistance 算成 0 或负数,污染取景距离与 near/far
- packages/model3d-viewer/src/framing.test.ts:补 180 / 360 / 0 / 负数 / NaN 回落到默认视角的用例
This commit is contained in:
2026-09-24 17:23:19 +08:00
parent e5076eb27c
commit 3624f454e2
2 changed files with 33 additions and 4 deletions
@@ -146,6 +146,25 @@ describe('computeModel3dViewerFitDistance', () => {
});
describe('createModel3dViewerFitSolver', () => {
it('视角超出 (0, 180) 时回落到默认视角,不把取景距离算成非正数', () => {
for (const fovDegrees of [180, 360, 0, -45, Number.NaN]) {
const solver = createModel3dViewerFitSolver({
center: { x: 0, y: 0, z: 0 },
aspect: 1,
fovDegrees,
});
expect(solver.resolve(), String(fovDegrees)).toBeCloseTo(
createModel3dViewerFitSolver({
center: { x: 0, y: 0, z: 0 },
aspect: 1,
fovDegrees: MODEL3D_VIEWER_CAMERA_FOV_DEGREES,
}).resolve(),
6,
);
}
});
it('喂包围盒角点时与包围盒口径一致', () => {
const expected = computeModel3dViewerFitDistance({ box: CUBE, aspect: 2 });
+14 -4
View File
@@ -71,6 +71,19 @@ function normalizePositive(value: number, fallback: number): number {
return Number.isFinite(value) && value > 0 ? value : fallback;
}
/**
* 取景视角必须落在 (0, 180):>=180 时 `tan(halfFovY)` 非正,`limitY/limitX` 与
* `fallbackDistance` 会算出 0 或负数,取景距离跟着变成负数并污染 near/far 与轨道范围。
*/
function normalizeFovDegrees(value: number | null | undefined): number {
return typeof value === 'number' &&
Number.isFinite(value) &&
value > 0 &&
value < 180
? value
: MODEL3D_VIEWER_CAMERA_FOV_DEGREES;
}
function subtract(
left: Model3dViewerVector3,
right: Model3dViewerVector3,
@@ -152,10 +165,7 @@ export function createModel3dViewerFitSolver(
input: Model3dViewerFitSolverInput,
): Model3dViewerFitSolver {
const aspect = normalizePositive(input.aspect, FALLBACK_ASPECT);
const fovDegrees = normalizePositive(
input.fovDegrees ?? MODEL3D_VIEWER_CAMERA_FOV_DEGREES,
MODEL3D_VIEWER_CAMERA_FOV_DEGREES,
);
const fovDegrees = normalizeFovDegrees(input.fovDegrees);
const fitFraction = normalizePositive(
input.fitFraction ?? MODEL3D_VIEWER_FIT_FRACTION,
MODEL3D_VIEWER_FIT_FRACTION,