Rendimiento
Los sistemas de partículas pueden volverse costosos rápidamente. El coste suele estar en uno de varios lugares: demasiadas partículas activas a la vez, trabajo costoso por partícula en cada fotograma, o características específicas con costes elevados por emisión (clonación de modelos, GraphBlender de Beam, sombras en tiempo real).
Este capítulo recorre las causas más comunes de problemas de fotogramas por segundo con el plugin, ordenadas aproximadamente por la frecuencia con la que cada una es la verdadera responsable.
Lo primero que hay que comprobar: ¿cuántas partículas están activas a la vez?
Sección titulada «Lo primero que hay que comprobar: ¿cuántas partículas están activas a la vez?»El coste dominante en cualquier sistema de partículas es el número de partículas activas. Para un emisor de emisión continua, el número promedio de partículas vivas en cualquier momento es aproximadamente:
active particles ≈ Rate × average LifetimeUn emisor con Rate = 30 y Lifetime = 1.0,2.0 tiene aproximadamente 30 × 1.5 = 45 partículas activas en promedio. Un emisor con Rate = 100 y Lifetime = 5.0 tiene 500. Una escena con veinte emisores de este tipo tiene 10.000 partículas activas en cada fotograma.
Cada partícula activa cuesta:
- Una actualización de movimiento por fotograma (cálculo de CFrame)
- Una evaluación de gráfico por fotograma por cada propiedad de gráfico activa (Speed, Size, Color, Transparency, etc.)
- Una escritura de propiedad por fotograma en el visual duplicado (o cálculo de mezcla por fotograma para Beam)
Para diez mil partículas activas con cinco gráficos activos cada una, eso son 50.000 evaluaciones de gráficos por fotograma — aproximadamente el límite superior de lo que el motor maneja con fluidez en hardware de gama media.
El principal control de rendimiento más efectivo: reduce Rate o Lifetime. Reducir cualquiera de los dos a la mitad reduce el número de partículas activas a la mitad. Para la mayoría de los efectos, el coste visual de una reducción del 50% es mucho menor que el coste percibido — los espectadores no cuentan partículas individuales, perciben la densidad y el movimiento general.
Las partículas de malla cuestan más que las partículas de bloque
Sección titulada «Las partículas de malla cuestan más que las partículas de bloque»Un emisor de tipo Part que renderiza una forma primitiva (Block, Sphere, Cylinder) es más económico por partícula que un emisor basado en MeshPart. El motor duplica geometría más simple más rápido, y la GPU dibuja formas primitivas con mayor eficiencia que mallas personalizadas.
Para emisores de alta tasa donde la calidad visual de una primitiva es aceptable, da preferencia a las primitivas. La diferencia visual entre una partícula Block y una partícula MeshPart en tamaños pequeños (menos de 1 stud) a menudo es invisible en pantalla.
Cuando se requiere un MeshPart (una moneda modelada a medida, un fragmento de vidrio con forma no primitiva), el coste por partícula es real pero aceptable para tasas moderadas. Supera Rate = 50 con un MeshPart complejo y verás el coste.
Coste de clonación del subárbol de Model
Sección titulada «Coste de clonación del subárbol de Model»Cada emisión de un Model clona el subárbol completo del modelo. Un Model con veinte descendientes cuesta aproximadamente veinte veces la duplicación de una sola Part. Con Rate = 30, eso son 600 clones de descendientes por segundo pasando por el motor.
Dos formas de reducir esto:
- Reducir el número de descendientes. Un Model de bola de fuego con ocho Parts hijas puramente decorativas probablemente puede lograr el mismo efecto visual con tres o cuatro. Audita el Model en busca de hijos que no contribuyan al aspecto final.
- Usar un emisor de tipo
Partcon hijos anidados en su lugar. UnaPartcuyoRenderTemplatecontiene el mismo conjunto de hijos que el subárbol PrimaryPart de tu Model te ofrece el mismo efecto de partícula compuesta sin el envoltorio de Model, a veces con una clonación más económica. Contrapartida: pierdes el gráficoScalede Model, pero la mayoría de los casos funcionan bien conSizeX/Y/Zen la Part en su lugar.
Si el Model realmente necesita muchos descendientes y una tasa de emisión alta, perfila en el MicroProfiler de Studio para confirmar que la clonación es el cuello de botella antes de asumir que lo es.
:ScaleTo() por paso en Models
Sección titulada «:ScaleTo() por paso en Models»En cada paso de simulación, cada partícula-Model activa recibe una llamada a Model:ScaleTo() con el valor actual del gráfico Scale. :ScaleTo recorre todo el subárbol y multiplica el Size de cada descendiente, el tamaño de cada malla y el desplazamiento de cada Attachment. La granularidad del paso la establece TotalKeyFrames (Anim. Steps) — con los 100 pasos predeterminados durante un Lifetime de un segundo, eso es aproximadamente una o dos llamadas a :ScaleTo por fotograma a 60Hz; con Lifetimes más largos las llamadas se espacian proporcionalmente.
Para un Model con cincuenta descendientes y treinta partículas activas, eso son aproximadamente 1.500 actualizaciones de propiedades internas por paso de simulación solo para el escalado. El plugin no omite si no hay cambios — incluso un gráfico Scale constante sigue activando :ScaleTo en cada paso.
Si tu gráfico Scale es constante o casi constante, establece todos los puntos clave en 1.0 y la llamada sigue ocurriendo, pero el trabajo que :ScaleTo realiza internamente es mínimo (no se propagan cambios de tamaño reales). El coste es el recorrido por paso, que escala con el número de descendientes.
Para Models donde Scale no necesita animarse, la optimización de menor fricción es mantener el número de descendientes pequeño. Reducir TotalKeyFrames también disminuye la tasa de llamadas, a costa de una animación de escala más entrecortada.
Coste de asignación de GraphBlender
Sección titulada «Coste de asignación de GraphBlender»Los emisores de Beam con GraphBlender de múltiples estados construyen una nueva NumberSequence y ColorSequence por cada beam activo en cada fotograma. El motor reutiliza los tiempos fusionados precomputados entre mezclas, por lo que el trabajo por mezcla es económico, pero los propios objetos de secuencia son asignaciones que el GC eventualmente limpiará.
Con cantidades ordinarias de beams el coste es aceptable. Con cantidades muy altas (muchos decenas de beams GraphBlender activos a la vez) las asignaciones empiezan a aparecer en el MicroProfiler como presión de GC.
Si puedes crear el mismo efecto con un único Color y Transparency estáticos en lugar de GraphBlender de múltiples estados, te ahorras la asignación. GraphBlender es la opción correcta cuando genuinamente necesitas interpolación de múltiples estados; cuando un solo estado bastaría, omítelo.
PointLight: el límite de 8–16 luces dinámicas
Sección titulada «PointLight: el límite de 8–16 luces dinámicas»El motor de iluminación de Roblox renderiza un límite flexible de 8–16 luces dinámicas por fragmento, dependiendo del nivel de hardware. Más allá de eso, las luces adicionales silenciosamente no contribuyen al cálculo de iluminación — el motor elige las más cercanas o brillantes e ignora el resto.
Esto significa que un emisor PointLight con Rate = 30 y Lifetime = 2.0 (60 luces activas en cualquier momento) no se verá realmente como 60 luces. La mayoría no se renderizarán. El coste de que el motor lo intente es real (cada una pasa por la verificación de visibilidad), pero el resultado visual no coincidirá con lo que esperarías.
Para emisores PointLight, mantén Rate × Lifetime razonablemente pequeño. Rate = 5, Lifetime = 1.0 (5 luces activas) está dentro del presupuesto. Rate = 30, Lifetime = 2.0 es un desperdicio — la mayoría de las luces no se renderizarán.
Para efectos de resplandor que necesiten parecer muchas luces, considera un único emisor PointLight con Rate bajo combinado con Color brillante y Range alto. Una luz brillante transmite más “presencia” que diez luces tenues.
Las luces que proyectan sombras son especialmente costosas
Sección titulada «Las luces que proyectan sombras son especialmente costosas»Un PointLight con Shadows = true añade el coste de renderizado de sombras sobre el cálculo de iluminación por fragmento. Cada luz que proyecta sombras afecta el paso de sombras de cada superficie cercana.
Roblox impone un límite más estricto sobre las luces que proyectan sombras que sobre las luces regulares — típicamente 1–4 por fragmento dependiendo del hardware. Pasado ese límite, las sombras silenciosamente no contribuyen.
Para PointLights de estilo partícula — orbes mágicos, resplandores de proyectiles, destellos breves — deja Shadows = false. Recurre a las sombras solo en PointLights estacionarios y deliberados donde la sombra proyectada forma parte del efecto (una antorcha con una sombra de personaje visible en la pared, por ejemplo).
Decodificación de textura en la primera emisión
Sección titulada «Decodificación de textura en la primera emisión»La primera vez que un emisor con textura (Part / Beam / Trail / ImageLabel) emite, Roblox carga y decodifica el recurso de textura bajo demanda. La decodificación tarda entre 50 y 200 milisegundos — tiempo suficiente para abarcar varios fotogramas a 60 fps. Durante esa ventana, las partículas se renderizan sin textura.
Esto no es un problema de fotogramas por segundo en sí mismo, pero aparece como un “destello” visible en la primera emisión de un efecto con textura. La solución es PreloadTexture = true, que fuerza la carga del recurso antes de la emisión. Consulta Anclaje de texturas.
Para momentos cinematográficos importantes (la primera emisión de un efecto crítico), usa PreloadTexture. Para efectos ambientales donde la primera emisión no está estrictamente cronometrada, el destello suele ser invisible.
La emisión de ImageLabel es económica
Sección titulada «La emisión de ImageLabel es económica»De todos los tipos de emisores, ImageLabel tiene el menor coste por partícula. La ruta de renderizado 2D no pasa por la canalización 3D — sin deformación, sin proyección de sombras, sin cálculos de iluminación por fragmento. El coste está principalmente en la evaluación de gráficos y las actualizaciones de propiedades por partícula.
Los emisores ImageLabel con Rate = 100 o incluso Rate = 200 son viables en hardware de gama media. Si tienes efectos del lado de la interfaz de usuario que necesitan sentirse densos (números de daño, indicadores de puntuación, destellos) y te preocupa el coste, ImageLabel es la opción económica comparada con los emisores de Part 3D.
Escalado para dispositivos de gama baja frente a gama alta
Sección titulada «Escalado para dispositivos de gama baja frente a gama alta»Los jugadores de Roblox abarcan un amplio rango de hardware — desde móviles de gama baja hasta PC de gama alta. Un efecto que se ejecuta con fluidez en PC puede entrecortarse en móvil. Dos enfoques para manejar esto:
El primero es la emisión condicional — tu script verifica el nivel del dispositivo y reduce Rate (u omite la emisión por completo) en dispositivos de gama baja. Roblox proporciona UserInputService:GetPlatform() y similares; combina con detección manual del nivel de calidad.
El segundo son los presupuestos predeterminados más bajos — diseña para el objetivo de gama baja y acepta que los dispositivos de gama alta tienen margen. Para la mayoría de los juegos, esta es la decisión correcta. Los jugadores en hardware de gama baja son el cuello de botella; diseñar para ellos produce una experiencia que funciona en todas partes.
Evita la trampa de diseñar con calidad máxima en una máquina de desarrollo de gama alta y publicarlo a jugadores en móvil. Prueba en un dispositivo móvil de gama media o usa las herramientas de emulación de Studio para detectar problemas de rendimiento con antelación.
Cómo perfilar
Sección titulada «Cómo perfilar»El MicroProfiler de Studio (Ctrl+F6) muestra desgloses de tiempo por fotograma. Busca:
- Una etiqueta
Part_Icleso etiquetaHeartbeatcreciendo bajo carga — ese es el bucle de actualización del plugin. Si es el cuello de botella, el número de partículas es demasiado alto. - Picos de
GarbageCollection— son las asignaciones de GraphBlender u otras asignaciones por fotograma acumulándose. Reduce el número de beams con GraphBlender. - Picos de
Renderercon altos conteos de partículas de malla — es la GPU. Reduce el número de partículas o cambia a primitivas.
Perfila con los escenarios de juego reales, no solo con la vista previa del emisor en el modo de edición de Studio. Los costes de partículas solo importan cuando se acumulan junto con el resto del presupuesto de tiempo de fotograma de tu juego.
Qué sigue
Sección titulada «Qué sigue»Diferencias de tipo es la referencia rápida de mismo nombre, forma diferente (polimorfismo) — propiedades cuyo tipo de dato o significado varía según el tipo de emisor, con una tabla de consulta para los problemas más comunes.