unity-rlottie Lottie Animation Plugin

repository·dev·Indexed 42 days ago

https://github.com/gindemit/unity-rlottie

A Unity plugin (version 0.5.0-dev.242) that enables playing Lottie animations exported via bodymovin JSON as Texture2D objects. It utilizes Samsung's rlottie library for high-performance, low-memory vector animation rendering. The plugin includes the AnimatedImage class for UGUI integration and supports multiple graphics APIs including OpenGL ES 3, Vulkan, and Metal across Android, iOS, and WebGL platforms.

Tokens
15.1K
Snippets
31
Records
67
Agent score
54%

What's inside unity-rlottie

  1. Overview of Graphy features

    dev

    Graphy is a stats monitor and debugger for Unity projects. It provides real-time visualization of performance metrics through graphs and text.

    Core Monitoring Capabilities:

    • FPS: Frames per second monitoring.
    • Memory: RAM and memory usage tracking.
    • Audio: Audio-related performance stats.
    • Device Info: Advanced device information.

    Debugging Features:

    • Conditional Debugging: Set conditions that trigger specific consequences when met, such as taking a screenshot, pausing the editor, printing to the console, or calling custom methods from your own code.
    • Customization: Supports multiple layouts, customizable look and feel, and custom inspectors.
    • Compatibility: Works on multiple platforms and supports Unity 2019.3+ (with legacy support for Unity 5.4+ via specific releases).
  2. Performance considerations for Android GPUs

    dev

    When choosing between OpenGL ES 3 and Vulkan for Lottie animations on Android, performance varies significantly by GPU vendor:

    • Mali GPUs (e.g., Galaxy S20+): Vulkan is significantly faster at high resolutions (e.g., 1024px), providing a ~17-23% performance gain over OpenGL ES 3.
    • Adreno GPUs (e.g., Galaxy A52): Performance is roughly equal between the two APIs, with Vulkan occasionally performing slightly worse at high resolutions.

    General Budgeting: For high-resolution animations (512px or 1024px) with multiple simultaneous instances, be aware that the workload may exceed the 16.67ms (60 FPS) frame budget on many mobile devices.

  3. Identify unsupported Unity renderers and fallback behavior

    dev

    The plugin uses RendererCommon::ToRenderer() to map Unity's graphics API to a native backend. If the renderer is not recognized, the plugin maps it to Renderer::Unknown and cannot create native textures.

    Fallback Mechanism: When native texture creation or external-texture wrapping fails (due to an unsupported renderer or transient initialization failure), the plugin automatically falls back to a managed BGRA Texture2D.

    Important Notes on Fallback:

    • Fallback mode uses Texture2D.Apply() and will emit a warning identifying the renderer or wrapper failure.
    • Fallback mode does not enable native-upload capabilities; it remains a managed-upload process.
    • Legacy APIs like Direct3D 9, legacy desktop OpenGL, and PlayStation Vita GXM are no longer supported and are not targets for the plugin.
  4. Use Marker Atlases and Shared Frame Caches for scaling

    dev

    To scale animations across many visual instances without creating a native renderer for every instance, the plugin provides two reusable patterns:

    1. Marker / clip atlas: A single Lottie JSON document containing multiple named animation clips defined by standard Lottie markers. This allows one asset to drive various states (e.g., idle, walk, celebrate).
    2. Shared rasterized frame cache: An optional pre-rasterization strategy where selected marker clips are baked into immutable frames. This allows hundreds of visual instances to share the same frames, significantly reducing the number of active rlottie renderers required.
  5. How LottieAnimation and native texture uploads work

    dev

    The LottieAnimation component is the primary abstraction for live animations. It is designed to automatically select optimized native GPU upload backends (such as D3D, Metal, Android GLES, or Vulkan) when supported, avoiding the performance overhead of Texture2D.Apply().

    When a native backend is active, the plugin uses a render-mailbox architecture:

    1. The plugin acquires a plugin-owned cacheable CPU mailbox slot.
    2. rlottie rasterizes the animation frame into this slot.
    3. The plugin performs a native render-thread upload to a Unity-owned or plugin-owned GPU texture.

    For unsupported graphics APIs or specific configurations (like WebGL), the plugin falls back to a managed upload path. To ensure safety, the managed path must not retain a native pointer into Unity texture storage across unsafe Unity operations. Developers should avoid manually forcing UseManagedTextureUpload = true unless specifically required for fallback or CPU-side frame baking.

  6. How managed upload fallback works

    dev

    When a native upload path is unavailable (e.g., macOS OpenGL Core or when a WebGL managed upload is requested), the plugin uses a managed fallback mechanism:

    1. Storage: The plugin rasterizes into a persistent, plugin-wrapper-owned NativeArray<byte>.
    2. Upload Process: It uses Texture2D.LoadRawTextureData(bytes) followed by Texture2D.Apply(false, false).
    3. Memory Safety: This method does not retain a pointer into Unity's texture raw storage, ensuring stability.
    4. WebGL Shader Mode: In WebGL shader mode, Apply() is called on the intermediate source Texture2D, not on the exposed RenderTexture.
  7. Understand Lottie marker and frame index behavior

    dev

    When working with Lottie markers and frame indices, be aware of the following technical nuances to avoid synchronization issues:

    • Frame Indexing: The rlottie public render call receives a zero-based animation frame index and internally adds the composition start frame.
    • Marker Values: Lottie marker fields (tm for start frame, ip for in-point, op for out-point) are composition-timeline values. When using markers, you must distinguish these timeline values from render indices by subtracting the parsed/rounded ip (in-point) consistently.
    • Boundary Handling: The Lottie op (out-point) is an exclusive boundary. Because the underlying rlottie engine rounds composition bounds and reports its own TotalFramesCount, you should always clamp derived render indices to the range [0, TotalFramesCount - 1] rather than assuming the JSON op - ip matches the engine's frame count exactly.
  8. Understand the texture upload architecture and performance model

    dev

    The plugin uses a two-slot CPU render mailbox system to manage texture uploads efficiently. Instead of rasterizing directly into GPU-mapped memory (which causes massive performance drops on D3D12 and Vulkan due to write-combined memory access), rlottie always rasterizes into normal CPU memory.

    Key behaviors:

    • Slot Lifecycle: Slots move through Free -> Rendering -> Ready -> Uploading -> Free.
    • Concurrency: If both CPU slots are busy, the plugin skips a frame rather than allocating more memory or blocking the main thread.
    • Coalescing: If multiple frames are ready, the newest frame is uploaded and older ready frames are coalesced.
    • Explicit APIs (D3D12/Vulkan): These use separate upload rings (a three-region heap for D3D12 and a three-slot transfer-buffer ring for Vulkan). The render thread performs a sequential copy from the CPU slot to these rings, allowing the CPU slot to be released immediately.
    • Fallback: If an explicit API cannot find an available upload region, the CPU slot returns to Ready and the upload is retried during a later render event.
  9. Understand WebGL native upload implementation

    dev

    For WebGL player builds, the plugin implements a native upload path that avoids per-frame Texture2D.Apply() calls to improve performance.

    How it works:

    1. Managed code creates a Unity-owned RGBA Texture2D with a single mip level.
    2. Apply() is called once to allocate the GL texture object.
    3. The texture's GetNativeTexturePtr() is cached as its WebGL name.
    4. rlottie renders into the texture's raw-data view. The native routine performs an in-place BGRA to RGBA conversion.
    5. Each completed frame is copied into a per-instance upload snapshot.
    6. A render-thread callback (via GL.IssuePluginEvent) uploads the snapshot using glTexSubImage2D.

    Capabilities and Fallbacks:

    • This path is only attempted if managed upload was not explicitly requested and the renderer is identified as OpenGLES2 or OpenGLES3 (WebGL 1/2).
    • If registration fails or the native side reports unavailability, the plugin falls back to the standard Texture2D.Apply() method.
    • Diagnostic Messages:
      • [LottiePlugin] Unity-owned WebGL native upload enabled
      • [LottiePlugin] WebGL native texture upload unavailable (<reason>); using Texture2D.Apply fallback
      • Valid reasons include: texture registration, native upload failure, and upload request rejected.
  10. Authoring Lottie files for runtime color overrides

    dev

    To enable semantic color overriding, you must structure your Lottie file using a predictable hierarchy.

    1. Create a shape group in your Lottie authoring tool and name it palette.
    2. Name the individual fill or stroke paints within that group using semantic names (e.g., base, shade, light, ink).
    3. Access these paints using dot-separated keypaths. For example, a paint named base inside the palette group is addressed as **.palette.base.

    Important: Do not name a single paint palette.base. The system interprets dots as hierarchy separators. Using a dot in a single object name will prevent the keypath from matching correctly.

  11. Vulkan validation test criteria

    dev

    The rendered-player smoke test validates the following components:

    • Hardware Identity: Records graphics device name, vendor, PCI-style vendor/device IDs, driver/API version, and operating system.
    • Visual Accuracy:
      • Visible and changing pixels from AnimatedImage and AnimatedButton samples.
      • Exact RGBA values for eight white/RGB/CMY/black calibration bars.
      • Eight grayscale steps (including sRGB-to-linear conversion in Linear projects).
    • Lifecycle Stability: 12 alternating synchronous/asynchronous cycles of create, draw, readback, and dispose across four texture sizes.
    • Backend Verification: Validates native Vulkan upload when the runner is invoked with the required backend.
  12. Choose between LottieAnimation and LottieFrameCache

    dev

    The runtime provides two distinct rendering models based on your performance and scale requirements:

    • LottieAnimation: Best for a small number of live animations (e.g., a hero character). It uses an optimized native texture-upload backend on supported graphics APIs.
    • LottieFrameCache: Best for many consumers showing the same source animation (e.g., 200 flowers sharing one 'idle' and 'grow' animation). It rasterizes selected marker clips once and allows multiple consumers to reference the same immutable Texture2D frames, significantly reducing overhead.