import { useEffect } from "react"; import { ClampToEdgeWrapping, FrontSide, RepeatWrapping, TextureLoader, Vector2, Vector3, } from "three"; import { ImprovedNoise } from "three/examples/jsm/Addons.js"; const canvas = document.createElement("canvas", { is: "canvas" }); const grassTexture = new TextureLoader().load("./texture_grass.jpg"); grassTexture.wrapS = grassTexture.wrapT = RepeatWrapping; grassTexture.repeat.set(100, 100); const SCALE = 5; const AMPLITUDE = 10; const GEOMETRY = 50; const SIZE = 100; // CHANGE WITH CAUTION const OVERLAP = 0.5; // CHANGE WITH CAUTION const CHUNK_SIZE = 100; // CHANGE WITH CAUTION const ADJUSTED_GEOMETRY = GEOMETRY + OVERLAP * 2; const ADJUSTED_SIZE = SIZE + OVERLAP * 2; const ADJUSTED_SCALE = SIZE / SCALE; export function Chunk(props: { position: Vector2; seed: number }): JSX.Element { const noise = (x: number, y: number): number => { const noise = new ImprovedNoise(); return noise.noise(x, y, props.seed); }; canvas.width = canvas.height = ADJUSTED_SIZE; const context = canvas.getContext("2d", { willReadFrequently: true }); if (!context) throw new Error("Canvas context not found"); const offsetX = -OVERLAP + props.position.x; const offsetY = -OVERLAP + props.position.y; const imageData = context.getImageData(0, 0, ADJUSTED_SIZE, ADJUSTED_SIZE); const data = imageData.data; for (let x = 0; x < ADJUSTED_SIZE; x++) { for (let y = 0; y < ADJUSTED_SIZE; y++) { const n = noise((x + offsetX) / ADJUSTED_SCALE, (y + offsetY) / ADJUSTED_SCALE) * 127 + 127; const id = (x + y * ADJUSTED_SIZE) * 4; data[id] = n; data[id + 1] = n; data[id + 2] = n; data[id + 3] = 255; } } context.putImageData(imageData, 0, 0); const displacementMap = new TextureLoader().load(canvas.toDataURL()); displacementMap.wrapS = displacementMap.wrapT = ClampToEdgeWrapping; useEffect(() => { return () => { displacementMap.dispose(); }; }, [displacementMap]); return ( ); }