返回

Unity 中场景强制更新/重新绘制的解决方案:解决性能延迟问题

Android

Unity 中强制更新/重新绘制场景的解决方案

问题陈述

在从原生 Android 相机获取纹理并渲染到 Unity 场景时,我们遇到了性能问题,Unity 的额外延迟令人困惑。我们分析了渲染过程,并排除了线程切换、OES 到 FBO 转换等因素,这表明 Unity 中可能存在内部延迟或它没有立即使用最新的外部纹理重新绘制。

解决方案

我们探索了几种在 Unity 中强制更新/重新绘制场景的方法:

1. 使用 GL.IssuePluginEvent()

GL.IssuePluginEvent() 可立即触发 Unity 重绘。我们可以在 nativeFboTextureId 更改时使用它,强制 Unity 使用最新的外部纹理重新绘制场景。

2. 更新渲染纹理

另一种方法是更新 ExternalTexture 的渲染纹理。每次 nativeFboTextureId 更改时,我们可以创建一个新的 ExternalTexture 并将其应用于着色器。

3. 调用 RenderTexture.DiscardContents()

RenderTexture.DiscardContents() 可丢弃渲染纹理的内容。在 nativeFboTextureId 更改后使用它,可以确保 Unity 在使用新纹理重新绘制之前清理渲染缓冲区。

示例代码

using UnityEngine;
using System;
using System.Runtime.InteropServices;

public class NativeCamera : MonoBehaviour
{
    private int nativeFboTextureId;

    void Update()
    {
        // 如果 nativeFboTextureId 已更改,则强制 Unity 重新绘制
        if (nativeFboTextureId != lastNativeFboTextureId)
        {
            GL.IssuePluginEvent(nativeFboTextureId);

            // 更新渲染纹理
            ExternalTexture newTexture = new ExternalTexture(nativeFboTextureId);
            material.SetTexture("_MainTex", newTexture);

            // 清理渲染缓冲区
            RenderTexture.active.DiscardContents();

            lastNativeFboTextureId = nativeFboTextureId;
        }
    }

    private int lastNativeFboTextureId;

    [DllImport("YourNativePlugin")]
    private static extern void OnFrameAvailable(int textureId);
}

注意

  • 频繁使用这些方法会影响性能。仅在需要时使用它们。
  • 如果这些方法无效,请检查是否有其他因素导致延迟,例如脚本开销或复杂着色器。
  • Unity 2020.3 之后不再支持 GL.IssuePluginEvent(),可以使用 GL.IssuePluginEventKHR() 代替。

常见问题解答

1. 为什么 Unity 可能会有内部延迟?

Unity 可能会在渲染管线中执行某些内部处理,导致延迟,例如图像效果或后期处理。

2. 我应该在何时使用这些方法?

当从外部源接收纹理并希望立即更新场景时,使用这些方法非常有用,例如原生相机、流媒体视频或 AR 设备。

3. 这些方法有性能影响吗?

是的,频繁使用这些方法会影响性能。避免在不必要时使用它们。

4. 是否有其他强制重新绘制的方法?

在一些情况下,您可以使用 Graphics.DrawMeshNow() 或 Graphics.Blit() 来强制重新绘制特定网格或纹理。

5. 我在原生端做了所有必要的设置,为什么这些方法不起作用?

请确保在原生端正确设置纹理格式、大小和其他参数,并与 Unity 侧匹配。此外,检查是否存在其他因素,例如原生线程与 Unity 主线程之间的通信问题。