From 3e426a10064143fe9e444b0073fb50d25cd79486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Mon, 21 Sep 2026 15:17:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=B9=E5=99=A8=E9=A6=96=E5=B8=A7=E6=97=A0?= =?UTF-8?q?=E5=B0=BA=E5=AF=B8=E6=97=B6=E6=8C=89=E7=9C=9F=E5=AE=9E=E6=AF=94?= =?UTF-8?q?=E4=BE=8B=E9=87=8D=E7=AE=97=E5=8F=96=E6=99=AF=20-=20=E5=8F=96?= =?UTF-8?q?=E6=99=AF=E5=8E=9F=E5=85=88=E5=8F=AA=E5=9C=A8=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=97=B6=E6=8C=89=20measureViewport()=20?= =?UTF-8?q?=E7=9A=84=E5=AE=BD=E9=AB=98=E6=AF=94=E7=AE=97=E4=B8=80=E6=AC=A1?= =?UTF-8?q?=EF=BC=8C=E9=9A=90=E8=97=8F=E9=9D=A2=E6=9D=BF=E9=87=8C=E6=8C=82?= =?UTF-8?q?=E8=BD=BD=E6=97=B6=E5=8F=AA=E8=83=BD=E6=8B=BF=E5=88=B0=E6=96=B9?= =?UTF-8?q?=E5=BD=A2=E5=85=9C=E5=BA=95=E5=80=BC=20-=20=E6=8A=BD=E5=87=BA?= =?UTF-8?q?=20computeFraming(aspect)=EF=BC=8CResizeObserver=20=E9=A6=96?= =?UTF-8?q?=E6=AC=A1=E9=87=8F=E5=88=B0=E9=9D=9E=E9=9B=B6=E5=B0=BA=E5=AF=B8?= =?UTF-8?q?=E5=90=8E=E6=8C=89=E7=9C=9F=E5=AE=9E=E6=AF=94=E4=BE=8B=E9=87=8D?= =?UTF-8?q?=E7=AE=97=E5=B9=B6=E5=A4=8D=E4=BD=8D=E4=B8=80=E6=AC=A1=EF=BC=8C?= =?UTF-8?q?=E4=B9=8B=E5=90=8E=E4=B8=8D=E5=86=8D=E8=A6=86=E7=9B=96=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=9A=84=E7=BC=A9=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/model3d-viewer/src/scene.ts | 58 +++++++++++++++++++--------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/packages/model3d-viewer/src/scene.ts b/packages/model3d-viewer/src/scene.ts index 440a57333..bfc11ce3e 100644 --- a/packages/model3d-viewer/src/scene.ts +++ b/packages/model3d-viewer/src/scene.ts @@ -272,25 +272,34 @@ export async function createModel3dViewerScene( abortIfNeeded(); const bounds = new THREE.Box3().setFromObject(model3d); - const size = measureViewport(); - const fitBox = { - min: { x: bounds.min.x, y: bounds.min.y, z: bounds.min.z }, - max: { x: bounds.max.x, y: bounds.max.y, z: bounds.max.z }, - }; - const fitCenter = computeModel3dViewerBoxCenter(fitBox); - const fitSolver = createModel3dViewerFitSolver({ - center: fitCenter, - aspect: size.aspect, - fovDegrees: MODEL3D_VIEWER_CAMERA_FOV_DEGREES, - fallbackRadius: computeModel3dViewerBoxRadius(fitBox), - }); - feedModel3dViewerFitSolver(model3d, (x, y, z) => fitSolver.add(x, y, z)); - const framing = computeModel3dViewerFraming({ - box: fitBox, - aspect: size.aspect, - fovDegrees: MODEL3D_VIEWER_CAMERA_FOV_DEGREES, - distance: fitSolver.resolve(), - }); + const viewport = measureViewport(); + + /** + * 按给定宽高比重算取景。容器在隐藏面板里挂载时首帧量不到尺寸,只能先按方形兜底, + * 等容器真正有尺寸后必须用真实比例重算,否则模型会按方形取景、被裁掉或显得过小。 + */ + function computeFraming(aspect: number) { + const fitBox = { + min: { x: bounds.min.x, y: bounds.min.y, z: bounds.min.z }, + max: { x: bounds.max.x, y: bounds.max.y, z: bounds.max.z }, + }; + const fitSolver = createModel3dViewerFitSolver({ + center: computeModel3dViewerBoxCenter(fitBox), + aspect, + fovDegrees: MODEL3D_VIEWER_CAMERA_FOV_DEGREES, + fallbackRadius: computeModel3dViewerBoxRadius(fitBox), + }); + feedModel3dViewerFitSolver(model3d, (x, y, z) => fitSolver.add(x, y, z)); + return computeModel3dViewerFraming({ + box: fitBox, + aspect, + fovDegrees: MODEL3D_VIEWER_CAMERA_FOV_DEGREES, + distance: fitSolver.resolve(), + }); + } + + let framing = computeFraming(viewport.aspect); + let hasFramedViewport = viewport.width > 0 && viewport.height > 0; function measureViewport(): { width: number; @@ -342,6 +351,17 @@ export async function createModel3dViewerScene( if (typeof ResizeObserver !== 'undefined') { resizeObserver = new ResizeObserver(() => { applyViewport(); + if (disposed || hasFramedViewport) { + return; + } + // 首次拿到非零尺寸:按真实比例重算取景并复位,用户此后的缩放不再被覆盖。 + const current = measureViewport(); + if (current.width === 0 || current.height === 0) { + return; + } + hasFramedViewport = true; + framing = computeFraming(current.aspect); + resetView(); }); resizeObserver.observe(container); }