Skip to content

Commit 9dca9d1

Browse files
authored
Make label height consistent across screen sizes (#640)
1 parent ec76994 commit 9dca9d1

File tree

2 files changed

+15
-5
lines changed

2 files changed

+15
-5
lines changed

src/viser/client/src/BatchedLabelManager.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ export const BatchedLabelManager: React.FC<{
261261
);
262262

263263
// Billboard rotation, position updates, and visibility culling in render loop.
264-
useFrame(({ camera }) => {
264+
useFrame(({ camera, size }) => {
265265
if (!group) return;
266266

267267
// Sync dirty batches (batches multiple add/remove/update calls).
@@ -324,14 +324,15 @@ export const BatchedLabelManager: React.FC<{
324324
let paddingY = LABEL_BACKGROUND_PADDING_Y;
325325

326326
if (textInfo.fontSizeMode === "screen") {
327-
// Scale based on distance and FOV to maintain consistent visual size.
327+
// Scale based on distance, FOV, and viewport size to maintain consistent pixel size.
328328
// Convert text position from local space to world space using group's matrix.
329329
tempWorldPos.copy(text.position);
330330
tempWorldPos.applyMatrix4(group.matrixWorld);
331331
const scale = calculateScreenSpaceScale(
332332
camera,
333333
tempWorldPos,
334334
tempCameraSpacePos,
335+
size.height,
335336
);
336337

337338
// Set fontSize directly - Troika applies this as a scale, no sync needed.

src/viser/client/src/LabelUtils.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,22 @@ export function calculateBaseFontSize(
7979
return mode === "screen" ? 0.3 * screenScale : sceneHeight;
8080
}
8181

82+
/**
83+
* Reference viewport height for screen-space label sizing.
84+
* Labels maintain consistent pixel size by scaling relative to this reference.
85+
*/
86+
const REFERENCE_VIEWPORT_HEIGHT = 800;
87+
8288
/**
8389
* Calculate screen-space scale factor for labels.
8490
* Returns scale factor to apply to base font size.
91+
* Accounts for camera distance, FOV, and viewport size to maintain constant pixel size.
8592
*/
8693
export function calculateScreenSpaceScale(
8794
camera: THREE.Camera,
8895
worldPosition: THREE.Vector3,
8996
tempCameraSpacePos: THREE.Vector3,
97+
viewportHeight: number,
9098
): number {
9199
if ("fov" in camera && typeof camera.fov === "number") {
92100
// PerspectiveCamera: use Z-coordinate in camera space (not Euclidean distance).
@@ -99,9 +107,10 @@ export function calculateScreenSpaceScale(
99107
((camera as THREE.PerspectiveCamera).fov * Math.PI) / 360,
100108
);
101109
// Reference depth is 10 units (baseFontSize is calibrated for this).
102-
return (depth / 10.0) * fovScale;
110+
// Scale by reference/actual viewport height to maintain constant pixel size.
111+
return (depth / 10.0) * fovScale * (REFERENCE_VIEWPORT_HEIGHT / viewportHeight);
103112
} else {
104-
// OrthographicCamera: use constant scale (no perspective).
105-
return 1.0;
113+
// OrthographicCamera: scale based on viewport height only.
114+
return REFERENCE_VIEWPORT_HEIGHT / viewportHeight;
106115
}
107116
}

0 commit comments

Comments
 (0)