Skip to content

Commit 5034b42

Browse files
committed
feat: add juvenile tree variants (35% small trees), taller trunks
1 parent 6337445 commit 5034b42

2 files changed

Lines changed: 26 additions & 13 deletions

File tree

client/VegetationSystem.js

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import { createTerrainField } from '/src/terrain/TerrainField.js'
66
import { generateContinent, CONTINENT_PRESETS } from '/src/terrain/ContinentGen.js'
77

88
const TREE_CONFIG = {
9-
oak: { type: TreeType.Deciduous, bark: BarkType.Oak, leaf: LeafType.Oak, trunkLen: 16, levels: 3, leafCount: 28, leafSize: 2.2, scale: 0.8 },
10-
pine: { type: TreeType.Evergreen, bark: BarkType.Pine, leaf: LeafType.Pine, trunkLen: 20, levels: 3, leafCount: 42, leafSize: 1.6, scale: 0.9 },
11-
fir: { type: TreeType.Evergreen, bark: BarkType.Pine, leaf: LeafType.Pine, trunkLen: 22, levels: 3, leafCount: 48, leafSize: 1.4, scale: 1.0 },
12-
willow: { type: TreeType.Deciduous, bark: BarkType.Willow, leaf: LeafType.Aspen, trunkLen: 12, levels: 4, leafCount: 34, leafSize: 1.8, scale: 0.7 },
13-
palm: { type: TreeType.Deciduous, bark: BarkType.Birch, leaf: LeafType.Ash, trunkLen: 18, levels: 2, leafCount: 26, leafSize: 2.4, scale: 0.8 }
9+
oak: { type: TreeType.Deciduous, bark: BarkType.Oak, leaf: LeafType.Oak, trunkLen: 24, levels: 3, leafCount: 28, leafSize: 2.2, scale: 0.8 },
10+
pine: { type: TreeType.Evergreen, bark: BarkType.Pine, leaf: LeafType.Pine, trunkLen: 28, levels: 3, leafCount: 42, leafSize: 1.6, scale: 0.9 },
11+
fir: { type: TreeType.Evergreen, bark: BarkType.Pine, leaf: LeafType.Pine, trunkLen: 32, levels: 3, leafCount: 48, leafSize: 1.4, scale: 1.0 },
12+
willow: { type: TreeType.Deciduous, bark: BarkType.Willow, leaf: LeafType.Aspen, trunkLen: 18, levels: 4, leafCount: 34, leafSize: 1.8, scale: 0.7 },
13+
palm: { type: TreeType.Deciduous, bark: BarkType.Birch, leaf: LeafType.Ash, trunkLen: 24, levels: 2, leafCount: 26, leafSize: 2.4, scale: 0.8 }
1414
}
1515

1616
const CARD_CONFIG = {
@@ -45,22 +45,22 @@ function makeCardTexture(color) {
4545
const t = new THREE.CanvasTexture(c); t.colorSpace = THREE.SRGBColorSpace; return t
4646
}
4747

48-
function bakeTreeVariant(name, variantSeed) {
48+
function bakeTreeVariant(name, variantSeed, juvenile = false) {
4949
const cfg = TREE_CONFIG[name]; if (!cfg) return null
5050
const t = new Tree()
5151
t.options.seed = variantSeed
5252
if (cfg.type) t.options.type = cfg.type
5353
if (cfg.bark && t.options.bark) t.options.bark.type = cfg.bark
5454
if (cfg.leaf && t.options.leaves) {
5555
t.options.leaves.type = cfg.leaf
56-
if (cfg.leafCount != null) t.options.leaves.count = cfg.leafCount
57-
if (cfg.leafSize != null) t.options.leaves.size = cfg.leafSize
56+
if (cfg.leafCount != null) t.options.leaves.count = juvenile ? Math.max(4, Math.floor(cfg.leafCount * 0.5) : cfg.leafCount
57+
if (cfg.leafSize != null) t.options.leaves.size = juvenile ? cfg.leafSize * 0.7 : cfg.leafSize
5858
t.options.leaves.alphaTest = 0.5
5959
}
6060
if (t.options.branch) {
61-
t.options.branch.levels = cfg.levels
61+
t.options.branch.levels = juvenile ? Math.max(1, cfg.levels - 1) : cfg.levels
6262
if (t.options.branch.length && typeof t.options.branch.length === 'object') {
63-
t.options.branch.length[0] = cfg.trunkLen
63+
t.options.branch.length[0] = juvenile ? Math.max(3, cfg.trunkLen * 0.5) : cfg.trunkLen
6464
}
6565
}
6666
try { t.generate() } catch (e) { console.error(`[Vegetation] bake ${name}#${variantSeed}:`, e.message); return null }
@@ -148,8 +148,14 @@ export function createVegetationSystem(scene, args = {}) {
148148
for (const name of SPECIES_LIST) {
149149
if (TREE_SPECIES.has(name)) {
150150
const variants = []
151+
// Mature variants
151152
for (let vi = 0; vi < VARIANTS_PER_SPECIES; vi++) {
152-
const baked = bakeTreeVariant(name, (name.charCodeAt(0) * 101 + vi * 4099) | 0)
153+
const baked = bakeTreeVariant(name, (name.charCodeAt(0) * 101 + vi * 4099) | 0, false)
154+
if (baked) variants.push(baked)
155+
}
156+
// Juvenile variants
157+
for (let vi = 0; vi < VARIANTS_PER_SPECIES; vi++) {
158+
const baked = bakeTreeVariant(name, (name.charCodeAt(0) * 101 + vi * 4099 + 10000) | 0, true)
153159
if (baked) variants.push(baked)
154160
}
155161
if (variants.length) {
@@ -196,7 +202,9 @@ export function createVegetationSystem(scene, args = {}) {
196202
const sp = species.get(p.species); if (!sp) continue
197203
const cap = sp.kind === 'card' ? MAX_GROUND_COVER_PER_CHUNK : MAX_INSTANCES_PER_CHUNK
198204
const variantCount = sp.kind === 'tree' ? sp.variants.length : 1
199-
const variantIdx = variantCount > 1 ? ((p.seed >>> 16) % variantCount) : 0
205+
// Use scale to choose variant: < 0.5 = juvenile, >= 0.5 = mature
206+
const baseIdx = (p.scale ?? 1) < 0.5 ? VARIANTS_PER_SPECIES : 0
207+
const variantIdx = baseIdx + (variantCount > 1 ? ((p.seed >>> 16) % VARIANTS_PER_SPECIES) : 0)
200208
const key = p.species + '#' + variantIdx
201209
let arr = byBucket.get(key)
202210
if (!arr) { arr = { sp, variantIdx, list: [] }; byBucket.set(key, arr) }

src/terrain/VegetationPlacement.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export function createVegetationPlacement(args = {}) {
8181
const WATER_BAND = waterlineBand
8282
const INV_WATER_BAND = WATER_BAND > 0 ? 1 / WATER_BAND : 0
8383
const CLUMPING = clumping
84+
const JUVENILE_RATIO = 0.35
8485
const _clumps = new Map()
8586

8687
const heightFn = sampleHeight || (field ? field.sampleHeight : null)
@@ -194,8 +195,12 @@ export function createVegetationPlacement(args = {}) {
194195
const scaleRange = TREE_SPECIES.has(sp) ? 0.4 : 0.3
195196
const scaleMin = TREE_SPECIES.has(sp) ? 0.65 : 0.8
196197
const rawScale = scaleMin + rand01(cellHash ^ 0x27d4eb2f) * scaleRange
198+
// Determine if juvenile based on random - 35% chance for small trees
199+
const isJuvenile = TREE_SPECIES.has(sp) && rand01(cellHash ^ 0xdeadbabe) < JUVENILE_RATIO
200+
// Juvenile trees get smaller final scale
201+
const juvenileScale = isJuvenile ? rawScale * 0.4 : rawScale
197202
const stressFactor = 0.55 + 0.45 * terrainFactor
198-
const scale = TREE_SPECIES.has(sp) ? rawScale * ageScaleFactor * stressFactor : rawScale
203+
const scale = TREE_SPECIES.has(sp) ? (isJuvenile ? juvenileScale : rawScale * ageScaleFactor * stressFactor) : rawScale
199204
const tiltAngle = rand01(cellHash ^ 0x165667b1) * 2 * Math.PI
200205
const tiltAmt = TREE_SPECIES.has(sp) ? rand01(cellHash ^ 0xd1b2ae35) * 0.08 : 0
201206
const health = 0.7 + rand01(cellHash ^ 0x7f4a7c15) * 0.3

0 commit comments

Comments
 (0)