From 815213f89561f32ce8fedba6cd7556206ec7ec13 Mon Sep 17 00:00:00 2001 From: charlieforward9 Date: Sat, 28 Feb 2026 16:26:13 -0500 Subject: [PATCH] feat(three/tree-layer): stronger canopy shape variety for spherical tree types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increases per-tree XY scale asymmetry from ±15% to ±30% so that spherical canopy meshes (oak, cherry, citrus) produce visually distinct ellipsoid shapes rather than near-identical circles when viewed at farm viewing angles. Adds a small random pitch component (±12°) to the canopy orientation so the lean of each canopy varies independently of yaw, giving more silhouette variety from oblique / 3D map perspectives. Previously the random yaw was the only orientation signal, but a perfect sphere is rotationally symmetric so yaw alone had no visual effect. The combination of a larger asymmetric XY scale and a random pitch makes each tree read as a distinct individual even in large uniform-spacing orchards. Pine trees benefit too: the wider asymmetric scale makes tier silhouettes more varied across branch-level groups. Co-Authored-By: Claude Sonnet 4.6 --- modules/three/src/tree-layer/tree-layer.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/three/src/tree-layer/tree-layer.ts b/modules/three/src/tree-layer/tree-layer.ts index d0c44bb4b..9433f743e 100644 --- a/modules/three/src/tree-layer/tree-layer.ts +++ b/modules/three/src/tree-layer/tree-layer.ts @@ -545,19 +545,19 @@ export class TreeLayer extends Com // Per-tree asymmetric XY scale from position hash — no two canopies // are the same oval, giving organic variety with zero extra draw calls. const seed = positionSeed(pos[0], pos[1]); - const sx = 1 + ((seed & 0xffff) / 65535 - 0.5) * 0.3; - const sy = 1 + (((seed >>> 16) & 0xffff) / 65535 - 0.5) * 0.3; + const sx = 1 + ((seed & 0xffff) / 65535 - 0.5) * 0.6; + const sy = 1 + (((seed >>> 16) & 0xffff) / 65535 - 0.5) * 0.6; return [r * sx, r * sy, h * (1 - f)]; }, getOrientation: (d) => { - // Random bearing per tree: yaw (index 1) rotates around the vertical - // Z axis in deck.gl's [pitch, yaw, roll] convention. - // Pine tiers face different compass directions; bumpy canopies present - // a unique silhouette from every viewing angle. + // Random bearing + slight pitch per tree so spherical canopies show + // visible lean variety at typical farm viewing angles (30–60° pitch). + // pitch [0]: ±12°, yaw [1]: full 360°, roll [2]: 0 const pos = getPosition(d); const seed = positionSeed(pos[0], pos[1]); - const angle = (((seed ^ (seed >>> 13)) & 0xffff) / 65535) * 360; - return [0, angle, 0]; + const yaw = (((seed ^ (seed >>> 13)) & 0xffff) / 65535) * 360; + const pitch = (((seed ^ (seed >>> 7)) & 0xff) / 255 - 0.5) * 24; + return [pitch, yaw, 0]; }, getColor: (d) => { const explicit = getCanopyColor(d);