rive-app / rive-unity

MIT License
104 stars 11 forks source link

Rive animation stops playing if GameObject is disabled #58

Closed abethke closed 4 months ago

abethke commented 4 months ago

I have an animation playing using 0.179 of the plugin on a RawImage using a version of RiveTexture. I noticed that when I SetActive(false) on the parent GameObject and later re-enable it, the Rive animation stops playing.

The advance code is still running but nothing is updating. The references still all seem valid. In a test I tried redoing most of the setup from RiveTexture.Start() but that didn't resolve it. The animation stays stuck on the last rendered frame.

damzobridge commented 4 months ago

Hmm, are you able to provide the version of the RiveTexture script you're using?

abethke commented 4 months ago

Sure thing. It is slightly modified for testing purposes but I'm basically using it with a prebuilt RenderTexture

`using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; using Rive;

using LoadAction = UnityEngine.Rendering.RenderBufferLoadAction; using StoreAction = UnityEngine.Rendering.RenderBufferStoreAction;

[ExecuteInEditMode] public class RiveTexture : MonoBehaviour { private void Start() { if (_renderTexture == null) { Debug.Log("Creating"); _renderTexture = new RenderTexture(resolution, resolution, 32, RenderTextureFormat.ARGB32); _renderTexture.enableRandomWrite = true; _renderTexture.Create(); }

    m_renderQueue = new Rive.RenderQueue(_renderTexture);
    m_riveRenderer = m_renderQueue.Renderer();
    if (asset != null)
    {
        m_file = Rive.File.Load(asset);
        m_artboard = m_file.Artboard(0);
        m_stateMachine = m_artboard?.StateMachine();
    }

    if (m_artboard != null && _renderTexture != null)
    {
        Debug.Log("Loaded ");
        m_riveRenderer.Align(fit, alignment, m_artboard);
        m_riveRenderer.Draw(m_artboard);

        m_commandBuffer = m_riveRenderer.ToCommandBuffer();
        m_commandBuffer.SetRenderTarget(_renderTexture);
        m_commandBuffer.ClearRenderTarget(true, true, UnityEngine.Color.clear, 0.0f);
        m_riveRenderer.AddToCommandBuffer(m_commandBuffer);
        m_camera = Camera.main;
        if (m_camera != null)
        {
            Camera.main.AddCommandBuffer(CameraEvent.AfterEverything, m_commandBuffer);
        }
    }

    if (outputMode == OutputMode.RawImage)
    {
        RawImage img = GetComponent<RawImage>();
        img.texture = renderTexture;
    }

    SetViseme(0);
}
private void Update()
{
    HitTesting();

    if (m_stateMachine != null)
    {
        m_stateMachine.Advance(Time.deltaTime);
    }
}

void HitTesting()
{
    Camera camera = Camera.main;

    if (camera == null || _renderTexture == null || m_artboard == null) return;

    if (!Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out RaycastHit hit))
        return;

    UnityEngine.Renderer rend = hit.transform.GetComponent<UnityEngine.Renderer>();
    MeshCollider meshCollider = hit.collider as MeshCollider;

    if (rend == null || rend.sharedMaterial == null || rend.sharedMaterial.mainTexture == null || meshCollider == null)
        return;

    Vector2 pixelUV = hit.textureCoord;

    pixelUV.x *= _renderTexture.width;
    pixelUV.y *= _renderTexture.height;

    Vector3 mousePos = camera.ScreenToViewportPoint(Input.mousePosition);
    Vector2 mouseRiveScreenPos = new(mousePos.x * camera.pixelWidth, (1 - mousePos.y) * camera.pixelHeight);

    if (m_lastMousePosition != mouseRiveScreenPos || transform.hasChanged)
    {
        Vector2 local = m_artboard.LocalCoordinate(pixelUV, new Rect(0, 0, _renderTexture.width, _renderTexture.height), fit, alignment);
        m_stateMachine?.PointerMove(local);
        m_lastMousePosition = mouseRiveScreenPos;
    }
    if (Input.GetMouseButtonDown(0))
    {
        Vector2 local = m_artboard.LocalCoordinate(pixelUV, new Rect(0, 0, _renderTexture.width, _renderTexture.height), fit, alignment);
        m_stateMachine?.PointerDown(local);
        m_wasMouseDown = true;
    }
    else if (m_wasMouseDown)
    {
        m_wasMouseDown = false; Vector2 local = m_artboard.LocalCoordinate(mouseRiveScreenPos, new Rect(0, 0, _renderTexture.width, _renderTexture.height), fit, alignment);
        m_stateMachine?.PointerUp(local);
    }
}

private void OnDisable()
{
    if (m_camera != null && m_commandBuffer != null)
    {
        m_camera.RemoveCommandBuffer(CameraEvent.AfterEverything, m_commandBuffer);
    }
}

public RenderTexture renderTexture
{
    get
    {
        return _renderTexture;
    }
}

public void SetViseme(int in_viseme)
{
    SMINumber smiNumber = m_stateMachine.Inputs()[0] as SMINumber;
    smiNumber.Value = in_viseme;
}
public enum OutputMode
{
    RawImage
}

bool m_wasMouseDown = false;
private Vector2 m_lastMousePosition;

private Rive.RenderQueue m_renderQueue;
private Rive.Renderer m_riveRenderer;
private CommandBuffer m_commandBuffer;

private Rive.File m_file;
private Artboard m_artboard;
public StateMachine m_stateMachine;

private Camera m_camera;

[Tooltip("Optional, Dynamically created if not set")]
public RenderTexture _renderTexture;

public Rive.Asset asset;
public OutputMode outputMode = OutputMode.RawImage;
public Fit fit = Fit.contain;
public Alignment alignment = Alignment.Center;
public int resolution = 512;

} `

abethke commented 4 months ago

I figured out the solution and will post it shortly

abethke commented 4 months ago

RiveTexture.cs needs this addition to work.

private void OnEnable()
{
    if (m_camera != null && m_commandBuffer != null)
    {
        m_camera.AddCommandBuffer(CameraEvent.AfterEverything, m_commandBuffer);
    }
}
damzobridge commented 4 months ago

Awesome, thanks for sharing the code. Had a feeling it was related to the command buffer not being added back after the game object is re-enabled.