Preview: apply ghost height, keep name labels world-scale above scaled ghosts
This commit is contained in:
@@ -129,29 +129,34 @@ function buildStatics(scene) {
|
|||||||
// ---------- live ghosts ----------
|
// ---------- live ghosts ----------
|
||||||
const active = new Map(); // uid -> { rec, group, label }
|
const active = new Map(); // uid -> { rec, group, label }
|
||||||
let followUid = null;
|
let followUid = null;
|
||||||
|
let ghostHeight = 4; // cm, from scene.ghostHeightCm
|
||||||
const clockSamples = []; let clockOffset = 0;
|
const clockSamples = []; let clockOffset = 0;
|
||||||
|
|
||||||
async function addGhost(rec) {
|
async function addGhost(rec) {
|
||||||
if (active.has(rec.uid)) return;
|
if (active.has(rec.uid)) return;
|
||||||
const group = await buildGhost(rec, gradients, modelManifest);
|
const group = await buildGhost(rec, gradients, modelManifest);
|
||||||
|
group.userData.setHeight(ghostHeight);
|
||||||
const label = textSprite(rec.name, COLORS[rec.color] || '#fff');
|
const label = textSprite(rec.name, COLORS[rec.color] || '#fff');
|
||||||
label.position.y = 28;
|
label.scale.set(20, 5, 1);
|
||||||
group.add(label);
|
scn.add(group); scn.add(label); // label stays world-scale, outside the scaled group
|
||||||
scn.add(group);
|
|
||||||
active.set(rec.uid, { rec, group, label });
|
active.set(rec.uid, { rec, group, label });
|
||||||
renderList();
|
renderList();
|
||||||
}
|
}
|
||||||
function removeGhost(uid) {
|
function removeGhost(uid) {
|
||||||
const e = active.get(uid);
|
const e = active.get(uid);
|
||||||
if (!e) return;
|
if (!e) return;
|
||||||
scn.remove(e.group);
|
scn.remove(e.group); scn.remove(e.label);
|
||||||
active.delete(uid);
|
active.delete(uid);
|
||||||
if (followUid === uid) followUid = null;
|
if (followUid === uid) followUid = null;
|
||||||
renderList();
|
renderList();
|
||||||
}
|
}
|
||||||
|
|
||||||
const net = new ExhibitNet();
|
const net = new ExhibitNet();
|
||||||
net.on('scene', m => buildStatics(m.scene))
|
net.on('scene', m => {
|
||||||
|
buildStatics(m.scene);
|
||||||
|
ghostHeight = m.scene.ghostHeightCm || 4;
|
||||||
|
for (const e of active.values()) e.group.userData.setHeight(ghostHeight);
|
||||||
|
})
|
||||||
.on('active', async m => {
|
.on('active', async m => {
|
||||||
for (const uid of [...active.keys()]) removeGhost(uid);
|
for (const uid of [...active.keys()]) removeGhost(uid);
|
||||||
for (const rec of m.ghosts) await addGhost(rec);
|
for (const rec of m.ghosts) await addGhost(rec);
|
||||||
@@ -208,12 +213,14 @@ fit();
|
|||||||
(function loop(t) {
|
(function loop(t) {
|
||||||
requestAnimationFrame(loop);
|
requestAnimationFrame(loop);
|
||||||
const now = Date.now() + clockOffset;
|
const now = Date.now() + clockOffset;
|
||||||
for (const { rec, group } of active.values()) {
|
for (const { rec, group, label } of active.values()) {
|
||||||
ghostTransform(rec, now, _tmp);
|
ghostTransform(rec, now, _tmp);
|
||||||
group.position.copy(_tmp.position);
|
group.position.copy(_tmp.position);
|
||||||
group.rotation.y = _tmp.rotationY;
|
group.rotation.y = _tmp.rotationY;
|
||||||
group.userData.setOpacity(_tmp.opacity * 0.92);
|
group.userData.setOpacity(_tmp.opacity * 0.92);
|
||||||
group.userData.tick(t / 1000);
|
group.userData.tick(t / 1000);
|
||||||
|
label.position.set(_tmp.position.x, _tmp.position.y + ghostHeight + 3, _tmp.position.z);
|
||||||
|
label.material.opacity = _tmp.opacity;
|
||||||
}
|
}
|
||||||
if (followUid && active.has(followUid)) orbit.target.lerp(active.get(followUid).group.position, 0.08);
|
if (followUid && active.has(followUid)) orbit.target.lerp(active.get(followUid).group.position, 0.08);
|
||||||
orbit.update();
|
orbit.update();
|
||||||
|
|||||||
Reference in New Issue
Block a user