🚀 Auto-deploy: BrainWind atualizado em 28/07/2026 11:48:14

This commit is contained in:
2026-07-28 11:48:14 +00:00
parent 2ea79c363f
commit 3752f4a8a1
2 changed files with 30 additions and 35 deletions
+4 -4
View File
@@ -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);
+26 -31
View File
@@ -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}
/>