import { useRef, useEffect, useMemo, forwardRef } from "react"; import { Instance, Instances } from "@react-three/drei"; import { useGLTFWithKTX2 } from "../utils/useGLTFWithKTX2"; import { convertMaterialsToBasic } from "../utils/convertToBasic"; import * as THREE from "three"; const TreeSwayMaterial = forwardRef(({ time, ...props }, ref) => { const uniforms = useRef({ time: { value: 0 }, swayAmount: { value: 0.3 }, swaySpeed: { value: 0.7 }, baseFrequency: { value: 0.8 }, map: { value: props.map }, }); useEffect(() => { if (uniforms.current) { uniforms.current.time.value = time; } }, [time]); const vertexShader = ` uniform float time; uniform float swayAmount; uniform float swaySpeed; uniform float baseFrequency; attribute float instanceScale; varying vec2 vUv; varying float vHeight; void main() { vUv = uv; vHeight = position.y; // Normalize the height for easier calculations (0 at base, 1 at top) float normalizedHeight = position.y / 10.0; // Divisor based on tree height, but honestly doesn't really matter too much // Multi-frequency sway for more organic movement float sway1 = sin(time * swaySpeed * 0.8 + position.x * baseFrequency) * 0.5; float sway2 = cos(time * swaySpeed * 1.3 + position.z * baseFrequency * 1.7) * 0.3; float sway3 = sin(time * swaySpeed * 0.5 + position.x * baseFrequency * 0.3) * 0.2; // Combine sway effects with more influence at the top float combinedSway = (sway1 + sway2 + sway3) * swayAmount; float trunkStiffness = 1.0 - smoothstep(0.0, 0.3, normalizedHeight); // More stiff at bottom of tree // Apply sway with height influence and trunk stiffness vec3 swayedPosition = position; swayedPosition.x += combinedSway * 0.3 * normalizedHeight * (1.0 - trunkStiffness); swayedPosition.z += combinedSway * 0.4 * normalizedHeight * (1.0 - trunkStiffness); // Add a slight vertical movement for leaf flutter swayedPosition.y += sin(time * swaySpeed * 2.0 + position.x) * 0.02 * normalizedHeight; // Some wind direction for variation float windDirection = sin(time * 0.1) * 0.5 + 0.5; swayedPosition.xz += windDirection * combinedSway * 0.1 * normalizedHeight; // Adjust the position vec4 modelPosition = instanceMatrix * vec4(swayedPosition, 1.0); vec4 viewPosition = viewMatrix * modelPosition; vec4 projectedPosition = projectionMatrix * viewPosition; gl_Position = projectedPosition; } `; const fragmentShader = ` uniform sampler2D map; varying vec2 vUv; varying float vHeight; void main() { // Use the texture with original colors vec4 texColor = texture2D(map, vUv); // Discard transparency pixels below threshold if (texColor.a < 0.1) discard; gl_FragColor = texColor; } `; return ( ); }); export default function Model(props) { const { nodes, materials } = useGLTFWithKTX2("/models/Eighth.glb"); const newMaterials = useMemo( () => convertMaterialsToBasic(materials), [materials] ); const materialRef = useRef(); return ( ); }