Home
Core systems

Vegetation System

GPU-instanced grass, trees, and rocks with wind animation

🌿 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.

Quick Start

import { GrassInstances, TreeInstances, RockInstances } from 'strata-game-library/core';

<GrassInstances count={10000} spread={100} />
<TreeInstances count={500} spread={200} />
<RockInstances count={200} spread={150} />

Components

<GrassInstances>

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)}
/>

Props

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

<TreeInstances>

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]}
/>

Props

PropTypeDefaultDescription
countnumber100Number of trees
spreadnumber100Distribution radius
minDistancenumber5Minimum tree spacing
minHeightnumber3Minimum tree height
maxHeightnumber8Maximum tree height
typesstring[]['default']Tree type names
lodLevelsnumber3LOD quality levels

<RockInstances>

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}
/>

<GPUInstancedMesh>

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]
  })}
/>

Distribution Patterns

Random Distribution

<GrassInstances
  spread={100}
  spreadType="random"
  seed={12345}  // Reproducible randomness
/>

Grid Distribution

<GrassInstances
  spread={100}
  spreadType="grid"
  gridSpacing={0.5}
  gridJitter={0.2}  // Add randomness to grid
/>

Noise-Based Distribution

<GrassInstances
  spread={100}
  spreadType="noise"
  noiseScale={0.05}
  noiseThreshold={0.3}  // Only place above threshold
/>

Biome-Based Distribution

<GrassInstances
  spread={100}
  spreadType="biome"
  biomeMap={biomeTexture}
  biomeColors={{
    grassland: '#4a7c23',
    desert: '#c2b280',
    snow: '#e8e8e8'
  }}
/>

Terrain Following

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}
/>

Wind Animation

Global Wind

<GrassInstances
  windSpeed={1.5}
  windStrength={0.4}
  windDirection={[1, 0, 0.5]}
  windTurbulence={0.2}
/>

Wind Zones

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
/>

Custom Wind Function

<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);
  }}
/>

Level of Detail (LOD)

Automatic LOD

<TreeInstances
  count={1000}
  spread={300}

  lodLevels={4}
  lodDistances={[30, 100, 250, 500]}
  lodReductions={[1, 0.5, 0.25, 0.1]}  // Polygon reduction
/>

Billboard LOD

Trees become billboards at distance:

<TreeInstances
  count={1000}
  spread={300}

  billboardDistance={200}  // Switch to billboard
  billboardTexture={treeBillboard}
/>

Fade Out

<GrassInstances
  count={10000}
  spread={100}

  fadeStart={80}
  fadeEnd={100}
/>

Custom Vegetation

Custom Grass Geometry

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}
/>

Custom Tree Models

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}
    />
  );
}

Performance

PlatformGrassTreesRocks
Mobile3,000-5,000100-20050-100
Desktop10,000-20,000500-1,000200-400
High-end50,000+2,000+500+

Optimization Tips

  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} />

Live Demo

See the interactive vegetation demo running live in your browser.

View Live Demo | View Source