import { useRef, useMemo } from 'react'; import { useFrame } from '@react-three/fiber'; import { Edges } from '@react-three/drei'; import * as THREE from 'three'; interface ResizableBox3DProps { l1: number; l2: number; h: number; } function WindParticles({ l1, l2, h }: { l1: number, l2: number, h: number }) { const count = 40; const meshRef = useRef(null); // Create dummy object to compute matrix for each instance const dummy = useMemo(() => new THREE.Object3D(), []); // Generate random starting positions const particles = useMemo(() => { const temp = []; for (let i = 0; i < count; i++) { temp.push({ x: (Math.random() - 0.5) * (l1 * 3), // Spread wider than the building y: Math.random() * (h * 1.5), // Spread higher than the building z: (Math.random() * 40) + l2 / 2 + 5, // Start in front of the building speed: 10 + Math.random() * 15, // Random speeds offset: Math.random() * 100 // Phase offset }); } return temp; }, [l1, l2, h, count]); useFrame((_state, delta) => { if (!meshRef.current) return; particles.forEach((particle, i) => { // Move particle along Z axis (wind direction) particle.z -= particle.speed * delta; // If particle passed the building, reset it to the front if (particle.z < -l2 - 10) { particle.z = (Math.random() * 20) + l2 / 2 + 10; particle.x = (Math.random() - 0.5) * (l1 * 3); particle.y = Math.random() * (h * 1.5); } // Simple avoidance / turbulence effect around the building let currentX = particle.x; let currentY = particle.y; // If particle is close to the front face, push it out if (particle.z > -l2/2 && particle.z < l2/2 + 2) { const isHittingFront = Math.abs(particle.x) < l1/2 + 0.5 && particle.y < h + 0.5; if (isHittingFront) { // Push to the sides or up if (Math.abs(particle.x) > (l1/2) * 0.7) { currentX += Math.sign(particle.x) * (20 * delta); } else { currentY += 20 * delta; } } } dummy.position.set(currentX, currentY, particle.z); dummy.scale.set(0.05, 0.05, Math.max(0.5, particle.speed * 0.1)); // Stretch by speed dummy.updateMatrix(); meshRef.current!.setMatrixAt(i, dummy.matrix); }); meshRef.current.instanceMatrix.needsUpdate = true; }); return ( ); } export function ResizableBox3D({ l1, l2, h }: ResizableBox3DProps) { const meshRef = useRef(null); // Create target scale and position based on inputs const targetScale = useMemo(() => new THREE.Vector3(l1, h, l2), [l1, l2, h]); useFrame((_state, delta) => { if (meshRef.current) { // Smoothly animate the scale meshRef.current.scale.lerp(targetScale, delta * 5); // Smoothly animate the position to keep the base on the ground meshRef.current.position.lerp( new THREE.Vector3(0, meshRef.current.scale.y / 2, 0), delta * 5 ); } }); return ( {/* Ground plane for reference */} {/* The Animated Box */} {/* Wind Flow Animation */} ); }