import React, { useMemo } from 'react'; import * as THREE from 'three'; import { createNoise2D } from 'simplex-noise'; import { getTerrainHeight } from './math'; export const Landscape: React.FC<{ seed: number }> = ({ seed }) => { const geometry = useMemo(() => { // Generate a very large plane with many segments const size = 1200; const segments = 128; const geo = new THREE.PlaneGeometry(size, size, segments, segments); geo.rotateX(-Math.PI / 2); // Lay flat on XZ plane const pos = geo.attributes.position; const vertex = new THREE.Vector3(); // Recreate same noise instance the Generator used let rSeed = seed; const rng = () => { const x = Math.sin(rSeed++) * 10000; return x - Math.floor(x); }; const noise2D = createNoise2D(() => rng()); for (let i = 0; i < pos.count; i++) { vertex.fromBufferAttribute(pos, i); // Main height from the math utility so objects match exactly const h = getTerrainHeight(noise2D, vertex.x, vertex.z); // Curve down massively at edges to form a "planet" horizon // If we are at dist R from center, we drop it down smoothly. const dist = Math.sqrt(vertex.x * vertex.x + vertex.z * vertex.z); const edgeRadius = 400; let drop = 0; if (dist > edgeRadius) { // Drop quadratically beyond edgeRadius const d = dist - edgeRadius; drop = (d * d) * 0.05; } pos.setY(i, h - drop); } geo.computeVertexNormals(); return geo; }, [seed]); return ( ); }; export default Landscape;