🚀 Auto-deploy: BrainWind atualizado em 28/07/2026 11:48:14
This commit is contained in:
@@ -80,13 +80,13 @@ function WindDirectionIndicator({ angle, width, length, height }: { angle: numbe
|
||||
const isDark = useCanvasTheme() === 'dark';
|
||||
const color = isDark ? "#38bdf8" : "#0284c7"; // Light blue / dark blue
|
||||
|
||||
// Angle 0: Wind blows along X axis, from negative X towards origin (hitting Wall C at X=-width/2)
|
||||
// Angle 90: Wind blows along Z axis, from negative Z towards origin (hitting Wall A at Z=-length/2)
|
||||
// Angle 0: Wind blows along Z axis (Perpendicular à largura X)
|
||||
// Angle 90: Wind blows along X axis (Paralelo à largura X)
|
||||
|
||||
const dir = angle === 90 ? new THREE.Vector3(0, 0, 1) : new THREE.Vector3(1, 0, 0);
|
||||
const dir = angle === 0 ? new THREE.Vector3(0, 0, 1) : new THREE.Vector3(1, 0, 0);
|
||||
|
||||
const distance = Math.max(width, length) * 0.6 + 5;
|
||||
const startPos = angle === 90 ? new THREE.Vector3(0, height / 2, -distance) : new THREE.Vector3(-distance, height / 2, 0);
|
||||
const startPos = angle === 0 ? new THREE.Vector3(0, height / 2, -distance) : new THREE.Vector3(-distance, height / 2, 0);
|
||||
|
||||
const quat = new THREE.Quaternion();
|
||||
quat.setFromUnitVectors(new THREE.Vector3(0, 1, 0), dir);
|
||||
|
||||
@@ -60,10 +60,11 @@ export function AirflowSystem({ windAngle, width, length, height, permeabilityCa
|
||||
useFrame((state) => {
|
||||
if (!meshRef.current) return;
|
||||
const time = state.clock.elapsedTime;
|
||||
const isParallel = windAngle === 90;
|
||||
|
||||
// Vetor direção do vento
|
||||
const windDir = isParallel ? new THREE.Vector3(0, 0, 1) : new THREE.Vector3(1, 0, 0);
|
||||
// Agora 0° é paralelo à Parede A (ao longo do eixo Z)
|
||||
// E 90° é paralelo à Parede C (ao longo do eixo X)
|
||||
const isZAxis = windAngle === 0;
|
||||
const windDir = isZAxis ? new THREE.Vector3(0, 0, 1) : new THREE.Vector3(1, 0, 0);
|
||||
|
||||
const halfW = width / 2;
|
||||
const halfL = length / 2;
|
||||
@@ -72,7 +73,6 @@ export function AirflowSystem({ windAngle, width, length, height, permeabilityCa
|
||||
const roofAvgCpe = (roofCpe.E + roofCpe.F + roofCpe.G + roofCpe.H + roofCpe.I + roofCpe.J) / 6;
|
||||
|
||||
particles.forEach((p, i) => {
|
||||
// Determinar a zona e o Cpe local
|
||||
let localCpe = 0;
|
||||
let deflectY = 0;
|
||||
let deflectX = 0;
|
||||
@@ -93,29 +93,31 @@ export function AirflowSystem({ windAngle, width, length, height, permeabilityCa
|
||||
else if (Math.abs(pz - (halfL)) < margin) localCpe = wallCpe.B;
|
||||
else if (Math.abs(px - (-halfW)) < margin) localCpe = wallCpe.C;
|
||||
else if (Math.abs(px - (halfW)) < margin) localCpe = wallCpe.D;
|
||||
else localCpe = cpi; // Dentro do prédio
|
||||
else localCpe = cpi;
|
||||
|
||||
// Se bateu na parede a barlavento, desvia o fluxo (Aerodinâmica)
|
||||
// Colisão: Expulsar as partículas do interior com força (Desvio realístico)
|
||||
const isAirtight = permeabilityCase !== 'four-equally-permeable';
|
||||
if (isAirtight) {
|
||||
if (windAngle === 0 && px < -halfW + margin) {
|
||||
deflectY = p.baseSpeed * 1.5; // Sobe
|
||||
deflectZ = pz > 0 ? p.baseSpeed * 1.5 : -p.baseSpeed * 1.5; // Vai pros lados
|
||||
} else if (windAngle === 90 && pz < -halfL + margin) {
|
||||
deflectY = p.baseSpeed * 1.5; // Sobe
|
||||
deflectX = px > 0 ? p.baseSpeed * 1.5 : -p.baseSpeed * 1.5; // Vai pros lados
|
||||
if (windAngle === 0 && pz < -halfL + margin) {
|
||||
deflectY = p.baseSpeed * 2.0; // Levanta pro telhado
|
||||
deflectX = px > 0 ? p.baseSpeed * 2.0 : -p.baseSpeed * 2.0; // Contorna laterais
|
||||
p.position.z -= p.baseSpeed * 1.5; // Impede de avançar
|
||||
} else if (windAngle === 90 && px < -halfW + margin) {
|
||||
deflectY = p.baseSpeed * 2.0; // Levanta pro telhado
|
||||
deflectZ = pz > 0 ? p.baseSpeed * 2.0 : -p.baseSpeed * 2.0; // Contorna laterais
|
||||
p.position.x -= p.baseSpeed * 1.5; // Impede de avançar
|
||||
}
|
||||
}
|
||||
} else if (aboveRoof) {
|
||||
localCpe = roofAvgCpe;
|
||||
// Vórtice no telhado
|
||||
p.position.y += Math.sin(time * 5 + p.wobbleOffset) * 0.03;
|
||||
// Turbulência de vórtice severo no telhado
|
||||
p.position.y += Math.sin(time * 5 + p.wobbleOffset) * 0.05;
|
||||
}
|
||||
|
||||
// Suaviza a transição de Cpe para a cor não piscar
|
||||
// Suaviza a transição de Cpe para a cor fluir
|
||||
p.currentCpe += (localCpe - p.currentCpe) * 0.1;
|
||||
|
||||
// Modifica velocidade com base no Cpe (Pressão > 0 diminui vel, Sucção < 0 aumenta vel)
|
||||
// Modifica velocidade com base no Cpe (Pressão > 0 diminui, Sucção < 0 aumenta)
|
||||
const speedModifier = Math.max(0.2, 1 - (p.currentCpe * 0.5));
|
||||
const currentSpeed = p.baseSpeed * speedModifier;
|
||||
|
||||
@@ -128,46 +130,39 @@ export function AirflowSystem({ windAngle, width, length, height, permeabilityCa
|
||||
p.position.y += Math.sin(time * p.wobbleSpeed * 10 + p.wobbleOffset) * 0.01;
|
||||
|
||||
// Recicla partículas que saem da tela
|
||||
if (isParallel) {
|
||||
if (isZAxis) {
|
||||
if (p.position.z > halfL + 30) {
|
||||
p.position.z = -halfL - 30;
|
||||
p.position.y = Math.random() * (height * 2);
|
||||
p.position.y = Math.random() * (height * 2.5);
|
||||
p.position.x = (Math.random() - 0.5) * (width * 3);
|
||||
p.currentCpe = 0;
|
||||
}
|
||||
} else {
|
||||
if (p.position.x > halfW + 30) {
|
||||
p.position.x = -halfW - 30;
|
||||
p.position.y = Math.random() * (height * 2);
|
||||
p.position.y = Math.random() * (height * 2.5);
|
||||
p.position.z = (Math.random() - 0.5) * (length * 3);
|
||||
p.currentCpe = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Atualiza posição e escala na matriz
|
||||
dummy.position.copy(p.position);
|
||||
|
||||
// Aponta para a direção do movimento real
|
||||
const moveVec = new THREE.Vector3(windDir.x + deflectX, deflectY, windDir.z + deflectZ).normalize();
|
||||
dummy.lookAt(p.position.clone().add(moveVec));
|
||||
dummy.rotateX(Math.PI / 2);
|
||||
|
||||
// Estica a barrinha dependendo da velocidade (efeito blur)
|
||||
dummy.scale.set(1, 1 + currentSpeed * 5, 1);
|
||||
|
||||
// Estica barrinha com a velocidade
|
||||
dummy.scale.set(1, 1 + currentSpeed * 6, 1);
|
||||
dummy.updateMatrix();
|
||||
meshRef.current!.setMatrixAt(i, dummy.matrix);
|
||||
|
||||
// Atualiza Cor
|
||||
if (p.currentCpe > 0) {
|
||||
// Pressão (Quente: Vermelho -> Laranja)
|
||||
colorObj.set('#ef4444').lerp(new THREE.Color('#fcd34d'), 1 - Math.min(1, p.currentCpe));
|
||||
} else if (p.currentCpe < 0) {
|
||||
// Sucção (Frio: Azul claro -> Azul escuro)
|
||||
const intensity = Math.min(1, Math.abs(p.currentCpe));
|
||||
colorObj.set('#7dd3fc').lerp(new THREE.Color('#1e40af'), intensity);
|
||||
} else {
|
||||
// Neutro
|
||||
colorObj.set('#f1f5f9');
|
||||
}
|
||||
meshRef.current!.setColorAt(i, colorObj);
|
||||
@@ -181,11 +176,11 @@ export function AirflowSystem({ windAngle, width, length, height, permeabilityCa
|
||||
|
||||
return (
|
||||
<instancedMesh ref={meshRef} args={[undefined, undefined, count]}>
|
||||
<cylinderGeometry args={[0.015, 0.015, 1.5, 4]} />
|
||||
<cylinderGeometry args={[0.02, 0.02, 1.5, 4]} />
|
||||
<meshBasicMaterial
|
||||
color="#ffffff"
|
||||
transparent
|
||||
opacity={0.5}
|
||||
opacity={0.7}
|
||||
blending={THREE.AdditiveBlending}
|
||||
depthWrite={false}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user