El objetivo de esta guía es enseñarles a crear efectos donde cada línea generada dura exactamente un frame de video. Esta técnica es la base para efectos de estelas, barridos de partículas, morphing y cualquier animación que requiera un control total sobre cada instante del movimiento.
La variable frame_dur: Kara Effector nos proporciona esta variable global, que contiene la duración en milisegundos de un solo cuadro de video (usualmente 41.708 para un video a 23.976 fps).
Variables Clave en la Casilla variable: Para mantener nuestro código limpio y eficiente, definiremos dos variables elementales al inicio:
-- 1. Calculamos el número total de frames que dura el efecto.
frames_totales = math.ceil(line.dur / frame_dur);
-- 2. Calculamos el progreso de la animación (de 0 a 1) basado en el frame actual 'j'.
-- Esto nos servirá para todas nuestras animaciones.
progreso = (j - 1) / (frames_totales - 1);
Configurar el bucle para la animación: El loop ya no será una fórmula, sino que usará la variable que acabamos de crear.
loop: frames_totalesConfigurar el timing para cada frame: Haremos que cada línea generada aparezca en un frame específico, pero le daremos una duración mayor para crear un efecto de estela suave.
start_t: l.start_time + (j - 1) * frame_dur - (0.5 * frame_dur)end_t: fx.start_time + frame_dur + 550 (Aparece en su frame y dura 550ms más).Con esta base, cada iteración (j) corresponderá a la aparición de una partícula en un frame exacto de la animación, y tendremos una variable progreso lista para animar cualquier propiedad de forma sincronizada.
math.bezier()| Casilla | Contenido |
|---|---|
| Template Type | Line (o el que prefieran) |
variable |
Define todas las variables. pnt = { -150, -50, l.width * 0.33, 350, l.width * 0.66, -350, l.width+150, 50 }; frames_totales = math.ceil(line.dur / frame_dur); progreso = (j-1)/(frames_totales-1); color_inicial = shape.color1; color_final = shape.color3; |
loop |
frames_totales |
start_t |
l.start_time + (j - 1) * frame_dur - (0.5 * frame_dur) |
end_t |
fx.start_time + frame_dur + 550 |
fun_x |
Calcula la coordenada X usando module. math.bezier("x", pnt) |
fun_y |
Calcula la coordenada Y usando module. math.bezier("y", pnt) |
center_x |
l.left |
center_y |
l.middle |
size |
El tamaño disminuye a medida que avanza la animación, 1.6 la escala inicial, 50 lo que disminuye. (1.6 - progreso) * 50 |
add_tags |
Cambia el color y añade la estela. format("\\1c%s", color.interpolate(progreso, color_inicial, color_final)), "\\bord2\\blur2\\t(0,550,\\bord6\\blur16)\\t(frame_dur,frame_dur+1,\\134c(shape.color4))\\fad(0,frame_dur + 550)" |
return(fx) |
shape.star |
variable: Esta casilla centraliza todos los cálculos clave. Se definen los pnt (puntos) de la curva, se calcula frames_totales, y lo más importante, se calcula progreso una sola vez por iteración para usarlo en otras casillas.loop: Se establece con la variable frames_totales. Esto es importante, ya que asegura que la variable interna module ((j-1)/(maxj-1)) se calcule correctamente para cada frame.start_t / end_t: Cada estrella se genera en su frame correspondiente, pero vive por más de medio segundo, creando una superposición suave que forma la estela.fun_x / fun_y: En cada frame (j), module cambia, y por lo tanto math.bezier devuelve una nueva posición a lo largo de la curva pnt.center_x / center_y: Mueve toda la trayectoria de la curva para que comience en el borde izquierdo (l.left) y en el centro vertical (l.middle) de la línea de karaoke original.size: El tamaño de la estrella es más grande al principio (un factor de 1.6) y se reduce linealmente a medida que progreso aumenta, reforzando el efecto de estela.add_tags: Aquí ocurren varias animaciones:
format(...): Cambia el color de cada estrella usando progreso para interpolar entre el color inicial y el final.\\bord2\\blur2: Establece una apariencia base para la estrella.\\t(0,550,...): Anima el borde y el desenfoque, haciéndolos más grandes con el tiempo.\\t(frame_dur,...): Crea un cambio a un color diferente justo después de que la estrella aparece.\\fad(...): Hace que cada estrella se desvanezca suavemente durante su vida útil.return(fx): Define que cada partícula de la estela es una estrella.Resultado:
Morphing de Shapes: En lugar de generar una estela, podemos crear un único objeto que se transforma suavemente de una forma a otra. Para tener control total sobre la velocidad y el tiempo, pre-calcularemos la animación y la mostraremos cuadro por cuadro.
Sumamos al ejemplo anterior estos cambios:
variable:
-- 1. Preparamos las shapes, asegurando que tengan la misma estructura.
shape1 = shape.to_bezier(shape.star);
shape2 = shape.circle;
-- 2. Creamos una tabla con todos los "fotogramas" de la animación de morphing.
-- Usamos 50 pasos para una animación suave.
formas_morphing = table.ipol({shape1, shape2}, 50);
-- 3. Creamos una función que devolverá la shape correcta para cada frame.
Frame = 0; -- Nuestro propio contador de frames.
Anim = function()
Frame = Frame + 1;
-- Calculamos el índice del fotograma a mostrar.
-- Dividimos entre 2 para ralentizar la animación (cambia cada 2 frames).
local indice = math.floor((Frame - 1) / 2) + 1;
-- Usamos math.clamp para asegurarnos de que el índice no se salga
-- de los límites de nuestra tabla (de 1 a 50).
indice = math.clamp(indice, 1, #formas_morphing);
return formas_morphing[indice];
end;
return(fx):
Anim( )
El resultado final es un cambio completo de forma: