Compare commits

..

2 Commits

Author SHA1 Message Date
zhangshun
c1d5240d2c 固定模型缩略图比例 2026-06-01 16:56:35 +08:00
zhangshun
33f1163aa7 调整预览基点显示单位 2026-06-01 16:52:54 +08:00
2 changed files with 70 additions and 23 deletions

View File

@@ -131,7 +131,8 @@
.thumb {
position: relative;
min-height: 150px;
aspect-ratio: 4 / 3;
min-height: 0;
display: grid;
place-items: center;
/* background:
@@ -179,6 +180,7 @@
}
.thumb img {
display: block;
width: 100%;
height: 100%;
object-fit: contain;

View File

@@ -122,6 +122,11 @@ const zeroBasePoint: PreviewResolvedBasePoint = {
ry: 0,
rz: 0
};
const RAD_TO_DEG = 180 / Math.PI;
const DEG_TO_RAD = Math.PI / 180;
const BASE_POINT_DECIMAL_PLACES = 3;
const THUMBNAIL_WIDTH = 512;
const THUMBNAIL_HEIGHT = 384;
const previewEnvironmentUrl = "/DayCityOutdoor.exr";
const DEFAULT_PREVIEW_FRAME_INTERVAL_MS = 20;
@@ -179,12 +184,12 @@ export function openModelPreview(
</div>
<div class="preview-basepoint-grid">
<label><span>X</span><input name="baseX" type="number" value="0" step="0.001" /></label>
<label><span>Y</span><input name="baseY" type="number" value="0" step="0.001" /></label>
<label><span>Z</span><input name="baseZ" type="number" value="0" step="0.001" /></label>
<label><span>RX</span><input name="baseRx" type="number" value="0" step="0.001" /></label>
<label><span>RY</span><input name="baseRy" type="number" value="0" step="0.001" /></label>
<label><span>RZ</span><input name="baseRz" type="number" value="0" step="0.001" /></label>
<label><span>X(mm)</span><input name="baseX" type="number" value="0.000" step="0.001" /></label>
<label><span>Y(mm)</span><input name="baseY" type="number" value="0.000" step="0.001" /></label>
<label><span>Z(mm)</span><input name="baseZ" type="number" value="0.000" step="0.001" /></label>
<label><span>RX(°)</span><input name="baseRx" type="number" value="0.000" step="0.001" /></label>
<label><span>RY(°)</span><input name="baseRy" type="number" value="0.000" step="0.001" /></label>
<label><span>RZ(°)</span><input name="baseRz" type="number" value="0.000" step="0.001" /></label>
</div>
</div>
</div>
@@ -245,7 +250,7 @@ export function setPreviewBasePoint(basePoint: PreviewBasePoint, enabled = true)
for (const [key, name] of fieldMap) {
const input = document.querySelector<HTMLInputElement>(`.preview-basepoint-grid input[name="${name}"]`);
if (input && basePoint[key] !== undefined) {
input.value = String(basePoint[key]);
input.value = formatBasePointDisplayValue(key, basePoint[key]);
}
}
@@ -596,15 +601,31 @@ async function screenshotModel(modelId: number, onThumbnailSaved?: () => Promise
controls.update();
const oldBackground = scene.background;
const oldClearAlpha = renderer.getClearAlpha();
if (transparent) {
scene.background = null;
renderer.setClearColor(0x000000, 0);
}
renderer.render(scene, camera);
const thumbnail = renderer.domElement.toDataURL("image/png");
if (transparent) {
scene.background = oldBackground;
renderer.setClearAlpha(oldClearAlpha);
const oldPixelRatio = renderer.getPixelRatio();
const oldWidth = renderer.domElement.width / oldPixelRatio;
const oldHeight = renderer.domElement.height / oldPixelRatio;
const oldAspect = camera.aspect;
let thumbnail = "";
try {
if (transparent) {
scene.background = null;
renderer.setClearColor(0x000000, 0);
}
renderer.setPixelRatio(1);
renderer.setSize(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, false);
camera.aspect = THUMBNAIL_WIDTH / THUMBNAIL_HEIGHT;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
thumbnail = renderer.domElement.toDataURL("image/png");
} finally {
camera.aspect = oldAspect;
camera.updateProjectionMatrix();
renderer.setPixelRatio(oldPixelRatio);
renderer.setSize(oldWidth, oldHeight, false);
if (transparent) {
scene.background = oldBackground;
renderer.setClearAlpha(oldClearAlpha);
}
renderer.render(scene, camera);
}
await api(`/api/models/${modelId}/thumbnail`, {
@@ -626,12 +647,12 @@ function getSelectedOperation(operations: PreviewOperation[]) {
function readPreviewBasePoint(): PreviewResolvedBasePoint {
return resolveBasePoint({
x: readNumberInput("baseX"),
y: readNumberInput("baseY"),
z: readNumberInput("baseZ"),
rx: readNumberInput("baseRx"),
ry: readNumberInput("baseRy"),
rz: readNumberInput("baseRz")
x: roundBasePointValue(readNumberInput("baseX")),
y: roundBasePointValue(readNumberInput("baseY")),
z: roundBasePointValue(readNumberInput("baseZ")),
rx: degreesToRadians(readNumberInput("baseRx")),
ry: degreesToRadians(readNumberInput("baseRy")),
rz: degreesToRadians(readNumberInput("baseRz"))
});
}
@@ -641,6 +662,30 @@ function readNumberInput(name: string) {
return Number.isFinite(numberValue) ? numberValue : 0;
}
function formatBasePointDisplayValue(key: keyof PreviewResolvedBasePoint, value: number) {
const displayValue = key === "rx" || key === "ry" || key === "rz"
? radiansToDegrees(value)
: value;
return formatBasePointNumber(displayValue);
}
function radiansToDegrees(value: number) {
return roundBasePointValue(value * RAD_TO_DEG);
}
function degreesToRadians(value: number) {
return Number.isFinite(value) ? value * DEG_TO_RAD : 0;
}
function roundBasePointValue(value: number) {
if (!Number.isFinite(value)) return 0;
return Number(value.toFixed(BASE_POINT_DECIMAL_PLACES));
}
function formatBasePointNumber(value: number) {
return roundBasePointValue(value).toFixed(BASE_POINT_DECIMAL_PLACES);
}
function bindImportScene(
model: ModelItem,
operations: PreviewOperation[],