🚀 Auto-deploy: BrainWind atualizado em 23/07/2026 20:38:36
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
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<THREE.InstancedMesh>(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 (
|
||||
<instancedMesh ref={meshRef} args={[undefined, undefined, count]}>
|
||||
<cylinderGeometry args={[1, 1, 1, 8]} />
|
||||
<meshBasicMaterial color="#60a5fa" transparent opacity={0.4} />
|
||||
</instancedMesh>
|
||||
);
|
||||
}
|
||||
|
||||
export function ResizableBox3D({ l1, l2, h }: ResizableBox3DProps) {
|
||||
const meshRef = useRef<THREE.Mesh>(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 (
|
||||
<group>
|
||||
{/* Ground plane for reference */}
|
||||
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, 0, 0]} receiveShadow>
|
||||
<planeGeometry args={[100, 100]} />
|
||||
<meshStandardMaterial color="#333" depthWrite={false} transparent opacity={0.2} />
|
||||
</mesh>
|
||||
<gridHelper args={[100, 40, '#666', '#444']} position={[0, 0.01, 0]} />
|
||||
|
||||
{/* The Animated Box */}
|
||||
<mesh ref={meshRef} castShadow receiveShadow>
|
||||
<boxGeometry args={[1, 1, 1]} />
|
||||
<meshStandardMaterial color="#4f46e5" transparent opacity={0.7} roughness={0.2} metalness={0.8} />
|
||||
<Edges scale={1} threshold={15} color="#818cf8" />
|
||||
</mesh>
|
||||
|
||||
{/* Wind Flow Animation */}
|
||||
<WindParticles l1={l1} l2={l2} h={h} />
|
||||
</group>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user