fibras do fuso
Signed-off-by: Rodrigo Bertoldo de Sousa Martins <rodrigo@martinsevieira.adv.br>
This commit is contained in:
1 parent
3195bdd724
commit
2dc5a167ed
1 file changed
+53
-25
@@ -23,6 +23,38 @@ function smoothing(delta: number, halfLifeSeconds = 0.18) {
|
|||||||
return 1 - Math.pow(0.5, delta / halfLifeSeconds);
|
return 1 - Math.pow(0.5, delta / halfLifeSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Geometria das fibras do fuso: cada cilindro vai de A até B de verdade
|
||||||
|
// (não só "perto" do centrossomo com um ângulo aproximado) — calculamos
|
||||||
|
// a posição (ponto médio), o comprimento e a rotação (quaternion) direto
|
||||||
|
// dos dois pontos, então a fibra sempre nasce exatamente na esfera do
|
||||||
|
// centrossomo e se afunila em leque até perto do centro da célula, como
|
||||||
|
// o fuso mitótico de verdade.
|
||||||
|
const CENTROSOME_X = 0.65;
|
||||||
|
const FIBER_FAN = [-0.26, -0.12, 0.12, 0.26];
|
||||||
|
|
||||||
|
function cylinderBetween(from: THREE.Vector3, to: THREE.Vector3) {
|
||||||
|
const direction = new THREE.Vector3().subVectors(to, from);
|
||||||
|
const length = direction.length();
|
||||||
|
const position = new THREE.Vector3().addVectors(from, to).multiplyScalar(0.5);
|
||||||
|
const quaternion = new THREE.Quaternion().setFromUnitVectors(
|
||||||
|
new THREE.Vector3(0, 1, 0), // eixo padrão do CylinderGeometry
|
||||||
|
direction.clone().normalize(),
|
||||||
|
);
|
||||||
|
return { position, quaternion, length };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Um leque de fibras por polo, todas nascendo EXATAMENTE no centrossomo
|
||||||
|
// (0, ±CENTROSOME_X ao longo de X) e convergindo pra perto do centro da
|
||||||
|
// célula — computado uma única vez (é geometria fixa, não depende de
|
||||||
|
// estado/props) em vez de recalcular a cada render.
|
||||||
|
const FIBER_DEFS = ([-1, 1] as const).flatMap((side) => {
|
||||||
|
const from = new THREE.Vector3(side * CENTROSOME_X, 0, 0);
|
||||||
|
return FIBER_FAN.map((offset) => {
|
||||||
|
const to = new THREE.Vector3(side * 0.12, offset * 0.55, offset * 0.55);
|
||||||
|
return { side, ...cylinderBetween(from, to) };
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
interface SelectionProps {
|
interface SelectionProps {
|
||||||
selected: CellComponentId | null;
|
selected: CellComponentId | null;
|
||||||
onSelect: (id: CellComponentId) => void;
|
onSelect: (id: CellComponentId) => void;
|
||||||
@@ -220,31 +252,27 @@ function AnimatedCellSlot({
|
|||||||
</group>
|
</group>
|
||||||
{/* fibras do fuso — só a partir da prófase (quando `spindle: true`) */}
|
{/* fibras do fuso — só a partir da prófase (quando `spindle: true`) */}
|
||||||
<group ref={fibersRef}>
|
<group ref={fibersRef}>
|
||||||
{[-1, 1].map((side) => (
|
{FIBER_DEFS.map((fiber, i) => (
|
||||||
<group key={side}>
|
<mesh
|
||||||
{[-0.25, -0.1, 0.1, 0.25].map((offset, i) => (
|
key={i}
|
||||||
<mesh
|
position={fiber.position}
|
||||||
key={i}
|
quaternion={fiber.quaternion}
|
||||||
position={[side * 0.65 + side * -0.32, offset * 0.6, offset]}
|
onClick={(e) => {
|
||||||
rotation={[0, 0, side > 0 ? Math.PI / 2 + offset * 0.3 : -Math.PI / 2 + offset * 0.3]}
|
e.stopPropagation();
|
||||||
onClick={(e) => {
|
onSelect("fibras");
|
||||||
e.stopPropagation();
|
}}
|
||||||
onSelect("fibras");
|
>
|
||||||
}}
|
{/* raio um pouco maior só pra facilitar o clique — a fibra
|
||||||
>
|
visual continua fina, isso é puramente a área alvo */}
|
||||||
{/* raio um pouco maior só pra facilitar o clique — a fibra
|
<cylinderGeometry args={[0.018, 0.018, fiber.length, 6]} />
|
||||||
visual continua fina, isso é puramente a área alvo */}
|
<meshStandardMaterial
|
||||||
<cylinderGeometry args={[0.02, 0.02, 0.64, 6]} />
|
color="#f8fafc"
|
||||||
<meshStandardMaterial
|
transparent
|
||||||
color="#f8fafc"
|
opacity={fiberSelected ? 0.9 : 0.4}
|
||||||
transparent
|
emissive={fiberSelected ? HIGHLIGHT : BLACK}
|
||||||
opacity={fiberSelected ? 0.9 : 0.4}
|
emissiveIntensity={fiberSelected ? 0.6 : 0}
|
||||||
emissive={fiberSelected ? HIGHLIGHT : BLACK}
|
/>
|
||||||
emissiveIntensity={fiberSelected ? 0.6 : 0}
|
</mesh>
|
||||||
/>
|
|
||||||
</mesh>
|
|
||||||
))}
|
|
||||||
</group>
|
|
||||||
))}
|
))}
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
Reference in new issue
Block a user