@@ -6,11 +6,11 @@ import { createTerrainField } from '/src/terrain/TerrainField.js'
66import { generateContinent , CONTINENT_PRESETS } from '/src/terrain/ContinentGen.js'
77
88const 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
1616const 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 ) }
0 commit comments