Skip to content

Vegetation System

Strata’s vegetation system uses GPU instancing to render 10,000+ instances of grass, trees, and rocks at 60fps with procedural wind animation and biome-based distribution.

import { GrassInstances, TreeInstances, RockInstances } from '@strata-game-library/core';
<GrassInstances count={10000} spread={100} />
<TreeInstances count={500} spread={200} />
<RockInstances count={200} spread={150} />

GPU-instanced grass with wind animation:

import { GrassInstances } from '@strata-game-library/core';
<GrassInstances
// Instance count
count={10000}
// Distribution
spread={100}
spreadType="random" // or "grid", "noise"
// Appearance
color="#4a7c23"
colorVariation={0.2}
height={0.5}
heightVariation={0.3}
width={0.05}
// Wind
windSpeed={1}
windStrength={0.3}
windDirection={[1, 0, 1]}
// Position
position={[0, 0, 0]}
// Terrain following
terrain={terrainRef}
terrainHeight={(x, z) => getHeight(x, z)}
/>
PropTypeDefaultDescription
countnumber1000Number of grass blades
spreadnumber50Distribution radius
spreadTypestring'random'Distribution pattern
colorstring'#4a7c23'Base grass color
colorVariationnumber0.2Color randomness
heightnumber0.5Blade height
heightVariationnumber0.3Height randomness
windSpeednumber1Wind animation speed
windStrengthnumber0.3Wind bend amount

GPU-instanced trees with variety:

import { TreeInstances } from '@strata-game-library/core';
<TreeInstances
// Instance count
count={500}
// Distribution
spread={200}
minDistance={5} // Minimum spacing
// Size variation
minHeight={4}
maxHeight={12}
minRadius={1}
maxRadius={3}
// Appearance
trunkColor="#4a3728"
foliageColor="#2d5a27"
foliageVariation={0.3}
// Tree types
types={['pine', 'oak', 'birch']}
typeWeights={[0.5, 0.3, 0.2]}
// Wind
windSpeed={0.5}
windStrength={0.1}
// LOD
lodLevels={3}
lodDistances={[50, 150, 400]}
/>
PropTypeDefaultDescription
countnumber100Number of trees
spreadnumber100Distribution radius
minDistancenumber5Minimum tree spacing
minHeightnumber3Minimum tree height
maxHeightnumber8Maximum tree height
typesstring[]['default']Tree type names
lodLevelsnumber3LOD quality levels

GPU-instanced rocks and boulders:

import { RockInstances } from '@strata-game-library/core';
<RockInstances
// Instance count
count={200}
// Distribution
spread={150}
clusterSize={5}
clusterSpread={10}
// Size variation
minScale={0.5}
maxScale={3}
// Appearance
color="#666666"
colorVariation={0.15}
roughness={0.8}
// Types
types={['boulder', 'flat', 'jagged']}
// Moss
moss
mossColor="#3a5f0b"
mossAmount={0.3}
/>

Generic GPU instancing for any mesh:

import { GPUInstancedMesh } from '@strata-game-library/core';
<GPUInstancedMesh
geometry={customGeometry}
material={customMaterial}
count={1000}
// Transform data
positions={positionsArray}
rotations={rotationsArray}
scales={scalesArray}
colors={colorsArray}
// Animation
animated
animationFn={(instance, time) => ({
position: [instance.x, Math.sin(time + instance.x) * 0.1, instance.z]
})}
/>
<GrassInstances
spread={100}
spreadType="random"
seed={12345} // Reproducible randomness
/>
<GrassInstances
spread={100}
spreadType="grid"
gridSpacing={0.5}
gridJitter={0.2} // Add randomness to grid
/>
<GrassInstances
spread={100}
spreadType="noise"
noiseScale={0.05}
noiseThreshold={0.3} // Only place above threshold
/>
<GrassInstances
spread={100}
spreadType="biome"
biomeMap={biomeTexture}
biomeColors={{
grassland: '#4a7c23',
desert: '#c2b280',
snow: '#e8e8e8'
}}
/>

Make vegetation follow terrain height:

// Using a height function
<GrassInstances
count={10000}
spread={100}
terrainHeight={(x, z) => {
return noise2D(x * 0.02, z * 0.02) * 20;
}}
/>
// Using a terrain reference
const terrainRef = useRef();
<Terrain ref={terrainRef} />
<GrassInstances
count={10000}
spread={100}
terrain={terrainRef}
/>
<GrassInstances
windSpeed={1.5}
windStrength={0.4}
windDirection={[1, 0, 0.5]}
windTurbulence={0.2}
/>
import { WindZone } from '@strata-game-library/core';
<WindZone
position={[50, 0, 50]}
radius={30}
strength={2}
direction={[1, 0, 0]}
/>
<GrassInstances
count={10000}
spread={100}
useWindZones
/>
<GrassInstances
windFunction={(position, time) => {
// Custom wind calculation
const wave = Math.sin(position.x * 0.1 + time);
return new Vector3(wave * 0.3, 0, wave * 0.1);
}}
/>
<TreeInstances
count={1000}
spread={300}
lodLevels={4}
lodDistances={[30, 100, 250, 500]}
lodReductions={[1, 0.5, 0.25, 0.1]} // Polygon reduction
/>

Trees become billboards at distance:

<TreeInstances
count={1000}
spread={300}
billboardDistance={200} // Switch to billboard
billboardTexture={treeBillboard}
/>
<GrassInstances
count={10000}
spread={100}
fadeStart={80}
fadeEnd={100}
/>
import { createGrassGeometry } from '@strata-game-library/core';
const customGrass = createGrassGeometry({
segments: 5,
curve: 0.3,
width: 0.05,
height: 0.6
});
<GPUInstancedMesh
geometry={customGrass}
material={grassMaterial}
count={10000}
/>
import { useGLTF } from '@react-three/drei';
function CustomTrees() {
const { scene } = useGLTF('/models/custom-tree.glb');
return (
<TreeInstances
count={500}
spread={200}
customModel={scene}
modelScale={0.1}
/>
);
}
PlatformGrassTreesRocks
Mobile3,000-5,000100-20050-100
Desktop10,000-20,000500-1,000200-400
High-end50,000+2,000+500+
  1. Use LOD for distant vegetation
  2. Reduce count on mobile devices
  3. Use billboards for very distant trees
  4. Fade out grass beyond camera view
  5. Cluster rocks for visual density with fewer instances
// Mobile-optimized scene
<GrassInstances count={3000} spread={50} fadeEnd={60} />
<TreeInstances count={100} spread={80} lodLevels={2} />
<RockInstances count={50} spread={60} />
// Desktop scene
<GrassInstances count={15000} spread={120} />
<TreeInstances count={800} spread={200} lodLevels={4} />
<RockInstances count={300} spread={180} />

See the interactive vegetation demo running live in your browser.

View Live Demo | View Source