Entrega 3 - Computacion-Visual-Interactiva/proyecto GitHub Wiki
-
Cómo se hizo: Se accedió al Edit Mode, se seleccionaron las caras correspondientes a cada ala y al cuerpo, y se utilizó la opción
P → Selectionpara separarlos como objetos independientes. -
Por qué: La animación de aleteo requiere que cada ala tenga sus propios vértices para rotar de forma independiente, sin afectar el cuerpo.
-
Los objetos se renombraron como
Body,LeftWingyRightWing. -
Esto permite que al exportar el modelo en formato OBJ, los nombres se conserven en las cabeceras (
o Body,o LeftWing,o RightWing) y el script Python los utilice para determinar a qué parte pertenece cada triángulo.
-
Se activaron las opciones Objects as OBJ Objects y Objects as OBJ Groups al exportar.
-
Esto introduce líneas
o ...yg ...en el archivo, facilitando que el conversor Python asigne correctamente un flag a cada vértice:-1para el ala izquierda,+1para la derecha,0para el cuerpo.
pythonCopiarEditarkey = (vi, ti, wingFlag) # vi = índice posición, ti = índice UV
-
Por qué: Si no se incluye el
wingFlagcomo parte de la clave, vértices compartidos entre el cuerpo y un ala se fusionarían, lo que provoca que el cuerpo también se anime como ala.
cppCopiarEditarstruct Vertex { float3 Pos; float2 UV; float Wing; };
-
Se genera un array interleaved de 6
floatspor vértice:(x, y, z),(u, v)yflag.
-
Se utiliza un
OrderedDictpara mapear por primera vez cada tupla(vi, ti, flag)a un índice. En llamadas siguientes, se reutiliza ese índice, evitando duplicados.
cppCopiarEditar{0, 0, 3, VT_FLOAT32, false}, // Pos → ATTRIB0 {1, 0, 2, VT_FLOAT32, false}, // UV → ATTRIB1 {2, 0, 1, VT_FLOAT32, false}, // Flag → ATTRIB2
-
Por qué: Se configuran los tres atributos esperados por el shader. El layout usa un único
slotconstride = sizeof(Vertex)(24 bytes).
cppCopiarEditarstruct VSConstants { float4x4 WorldViewProj; float WingAngle; };
-
Por qué: Al pasar
WingAnglecomo constante al vertex shader, se evita recalcular senos y cosenos en cada vértice. La frecuencia del batido queda bajo control del CPU.
cppCopiarEditarfloat angularRevPS = kSpeed / (2*PI_F); float wingFreq = kWingFactor * angularRevPS; CB->WingAngle = sin(m_PathTime * 2*PI_F * wingFreq) * kWingAmp;
-
Por qué: La frecuencia del aleteo está ligada a la velocidad de vuelo. Reducir
kSpeedralentiza también el batido.
cppCopiarEditarfloat theta = m_PathTime * kSpeed; pos = { kRadius*cosθ, y(t), kRadius*sinθ };
cppCopiarEditary(t) = kBaseHeight + kBobAmp * sin(2π kBobFreq t)
-
Se agrega un armónico suave para romper la simetría perfecta del movimiento.
cppCopiarEditarforward = normalize({ -kRadius*sinθ, 0, kRadius*cosθ }); World = MakeWorld(pos, forward, {0, 1, 0});
-
Por qué: El cuerpo sólo rota en yaw (alrededor del eje Y), lo que evita movimientos bruscos y mantiene la estabilidad visual.
hlslCopiarEditarif (abs(IN.WingFlg) > 0.5) { float pivot = PIVOT_X * IN.WingFlg; p.x -= pivot;float a = g_WingAngle * IN.WingFlg; float2 xy = mul(float2x2(cos(a), -sin(a), sin(a), cos(a)), p.xy); p.x = xy.x; p.y = xy.y; p.x += pivot;}
-
Traslación a la bisagra: evita que el ala se desprenda visualmente.
-
Rotación en XY (eje Z): produce un aleteo vertical puro.
-
Signo opuesto: hace que ambas alas suban y bajen en sincronía.
-
Exclusión del cuerpo: como
WingFlg == 0, el cuerpo no entra al bloque.
| Parámetro | Valor | Justificación |
|---|---|---|
| kRadius | 6 u | Circulación amplia y legible. |
| kSpeed | 0.20 rad/s | Vuelo pausado (31s por vuelta). |
| kBobAmp | 0.25 u | Ondulación perceptible. |
| kBobFreq | 0.8 Hz | 3 bobs por vuelta. |
| kWingFactor | 12 | ~3 batidos por bob. |
| kWingAmp | 0.35 rad | Aleteo de ~20°. |
| PIVOT_X | 0.02 u | Bisagra realista visualmente. |
-
Movimiento: La mariposa describe un vuelo circular fluido, sube y baja suavemente, y se orienta tangencialmente sin cabecear.
-
Animación: Ambas alas se abren y cierran de forma sincronizada, con una amplitud y frecuencia que se ajusta dinámicamente a la velocidad.
-
Modularidad: Cambiar radio, velocidad o amplitud solo requiere ajustar constantes; no es necesario modificar geometría ni shaders.
-
Rendimiento: Solo se realiza un
draw-call, con un buffer y un vertex shader simples. La animación esO(1)por vértice.