World/Live: 3D ball nodes (spheres) instead of flat discs
Switch the Live view's structure nodes + agent pawns from flat CircleGeometry to lit SphereGeometry (MeshStandardMaterial with emissive + ambient/directional lights), so they read as 3D balls from any orbit angle instead of going edge-on. The additive glow sprites + particle effects are unlit, so the neon look is kept. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
db7569e5d3
commit
928e27cde5
@@ -229,7 +229,13 @@ export function WorldCanvas({ roots, selectedId, onSelect, expanded, onToggleExp
|
|||||||
});
|
});
|
||||||
|
|
||||||
const glow = makeGlowTexture();
|
const glow = makeGlowTexture();
|
||||||
const circle = new THREE.CircleGeometry(1, 28);
|
const sphere = new THREE.SphereGeometry(1, 18, 14);
|
||||||
|
// lights so the Live nodes/pawns read as shaded 3D balls (the additive glow
|
||||||
|
// sprites + particles stay unlit, so the neon effects are unaffected)
|
||||||
|
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
|
||||||
|
const keyLight = new THREE.DirectionalLight(0xffffff, 0.95);
|
||||||
|
keyLight.position.set(0.4, 1, 0.8);
|
||||||
|
scene.add(keyLight);
|
||||||
|
|
||||||
// Two render groups so the formation tabs switch whole views cleanly.
|
// Two render groups so the formation tabs switch whole views cleanly.
|
||||||
const gourceGroup = new THREE.Group();
|
const gourceGroup = new THREE.Group();
|
||||||
@@ -557,17 +563,19 @@ export function WorldCanvas({ roots, selectedId, onSelect, expanded, onToggleExp
|
|||||||
liveNodeIds.add(n.id);
|
liveNodeIds.add(n.id);
|
||||||
let m = nodeMeshes.get(n.id);
|
let m = nodeMeshes.get(n.id);
|
||||||
if (!m) {
|
if (!m) {
|
||||||
m = new THREE.Mesh(circle, new THREE.MeshBasicMaterial({ transparent: true, depthWrite: false }));
|
m = new THREE.Mesh(sphere, new THREE.MeshStandardMaterial({ transparent: true, depthWrite: false, roughness: 0.45, metalness: 0.15 }));
|
||||||
m.userData.id = n.id;
|
m.userData.id = n.id;
|
||||||
nodeMeshes.set(n.id, m);
|
nodeMeshes.set(n.id, m);
|
||||||
gourceGroup.add(m);
|
gourceGroup.add(m);
|
||||||
}
|
}
|
||||||
const r = n.r * (1 + n.heat * 0.4);
|
const r = n.r * (1 + n.heat * 0.4);
|
||||||
m.position.set(n.x, n.y, 0);
|
m.position.set(n.x, n.y, 0);
|
||||||
m.scale.set(r, r, 1);
|
m.scale.set(r, r, r);
|
||||||
const mat = m.material as THREE.MeshBasicMaterial;
|
const mat = m.material as THREE.MeshStandardMaterial;
|
||||||
col.set(n.color).lerp(white, n.heat * 0.6);
|
col.set(n.color).lerp(white, n.heat * 0.6);
|
||||||
mat.color.copy(col);
|
mat.color.copy(col);
|
||||||
|
mat.emissive.copy(col);
|
||||||
|
mat.emissiveIntensity = 0.35 + n.heat * 0.6;
|
||||||
mat.opacity = n.alpha * (n.tier === "root" ? 1 : 0.6 + n.heat * 0.4);
|
mat.opacity = n.alpha * (n.tier === "root" ? 1 : 0.6 + n.heat * 0.4);
|
||||||
let g = nodeGlows.get(n.id);
|
let g = nodeGlows.get(n.id);
|
||||||
if (!g) {
|
if (!g) {
|
||||||
@@ -635,16 +643,18 @@ export function WorldCanvas({ roots, selectedId, onSelect, expanded, onToggleExp
|
|||||||
livePawnIds.add(p.id);
|
livePawnIds.add(p.id);
|
||||||
let m = pawnMeshes.get(p.id);
|
let m = pawnMeshes.get(p.id);
|
||||||
if (!m) {
|
if (!m) {
|
||||||
m = new THREE.Mesh(circle, new THREE.MeshBasicMaterial({ transparent: true, depthWrite: false }));
|
m = new THREE.Mesh(sphere, new THREE.MeshStandardMaterial({ transparent: true, depthWrite: false, roughness: 0.45, metalness: 0.15 }));
|
||||||
m.userData.id = p.id;
|
m.userData.id = p.id;
|
||||||
pawnMeshes.set(p.id, m);
|
pawnMeshes.set(p.id, m);
|
||||||
gourceGroup.add(m);
|
gourceGroup.add(m);
|
||||||
}
|
}
|
||||||
const pa = p.alpha * (showPawns ? 1 : 0.5);
|
const pa = p.alpha * (showPawns ? 1 : 0.5);
|
||||||
m.position.set(p.x, p.y, 2);
|
m.position.set(p.x, p.y, 2);
|
||||||
m.scale.set(8, 8, 1);
|
m.scale.set(8, 8, 8);
|
||||||
const mat = m.material as THREE.MeshBasicMaterial;
|
const mat = m.material as THREE.MeshStandardMaterial;
|
||||||
mat.color.set(p.color);
|
mat.color.set(p.color);
|
||||||
|
mat.emissive.set(p.color);
|
||||||
|
mat.emissiveIntensity = 0.7;
|
||||||
mat.opacity = pa;
|
mat.opacity = pa;
|
||||||
let g = pawnGlows.get(p.id);
|
let g = pawnGlows.get(p.id);
|
||||||
if (!g) {
|
if (!g) {
|
||||||
@@ -766,7 +776,7 @@ export function WorldCanvas({ roots, selectedId, onSelect, expanded, onToggleExp
|
|||||||
pawnMeshes.forEach((m) => (m.material as THREE.Material).dispose());
|
pawnMeshes.forEach((m) => (m.material as THREE.Material).dispose());
|
||||||
pawnGlows.forEach((s) => (s.material as THREE.Material).dispose());
|
pawnGlows.forEach((s) => (s.material as THREE.Material).dispose());
|
||||||
neuronGlows.forEach((s) => (s.material as THREE.Material).dispose());
|
neuronGlows.forEach((s) => (s.material as THREE.Material).dispose());
|
||||||
circle.dispose();
|
sphere.dispose();
|
||||||
edgeGeom.dispose();
|
edgeGeom.dispose();
|
||||||
beamGeom.dispose();
|
beamGeom.dispose();
|
||||||
brainEdgeGeom.dispose();
|
brainEdgeGeom.dispose();
|
||||||
|
|||||||
Reference in New Issue
Block a user