iOS游戏中不一致的抖动

8
我正在为Unity iOS制作一个非常简单的垂直滚动游戏。我的游戏出现了不一致的抖动问题。我已经在网上搜索了很多解决方案,但没有找到合适的。我使用的是Unity版本5.3.4 f1。 游戏

Gameplay screenshot

  • 角色正在下落。我们使用Unity的角色控制器在Update()中移动角色(乘以Time.deltaTime)。
  • 相机在LateUpdate()中跟随角色(使用Vector3.Lerp()进行跟随)。
  • 由于角色正在下落,障碍物似乎向屏幕上方移动。
  • 场景中有1个定向光,用于实时阴影设置。阴影质量为高和硬阴影。
  • 场景中没有刚体。分析器中没有主要的峰值。
  • 我们拥有非常简单的几何形状和非常少的绘制调用/设置传递调用(平均7个设置传递调用)。
  • 我们保持了恒定的60 fps。
  • 由于我们正在运行iOS,vSync默认为On,无法禁用。

问题

  • 背景元素/障碍物(树木、岩石等)开始无缘无故地抖动。这种行为是不一致的,有时会抖动,有时不会。
  • 即使它不抖动,当用户通过触摸输入时,我们也会经历小的卡顿。

我们尝试过的

  • 我们已经尝试了所有的Update()LateUpdate()FixedUpdate()Time.deltaTimeTime.smoothDeltaTime,Lerp,将场景减少到几个立方体并删除所有碰撞器和触发器的组合。
  • 我们已经研究了以下主题:链接1链接2链接3和无数其他主题。
  • 最初,我们的游戏以默认的30 fps运行。但经过一些研究,似乎我们的问题是由于“帧速率”和“屏幕刷新率”的差异造成的。(要了解此问题,请参见以下链接)。由于iOS设备的刷新率为60Hz,因此我们将目标帧速率设置为60,我们的游戏保持恒定的60 fps。
  • 将目标帧速率设置为60后,抖动已经改善,但现在不稳定。

我已经没有任何想法了,非常感谢任何帮助或指引。

提前致谢。


场景中有多少实时灯光?能否分享相机移动的代码? - Umair M
楚苏兄弟,这里只有一个方向光。我正在使用 Vector3.Lerp() 移动相机。我已经测试了相机的移动,它不是问题所在。我还会更新帖子并添加这些信息。 - Anas iqbal
欢迎来到StackOverflow!如果您能添加一些代码,那将更有帮助。如果您还没有阅读,文档上说:请注意,设置targetFrameRate并不能保证帧率稳定。由于平台的特殊性或计算机速度过慢,可能会出现波动或无法达到目标帧率。此外,您是否愿意分享启用深度配置文件且未限制目标fps的Profiler截图? - Umair M
我遇到了完全相同的问题;它似乎发生在非常简单(或几乎为空)的场景中。我创建了一个非常非常基本的粒子系统场景,只是为了看到一些运动,项目中没有任何自定义脚本。 - Lea Hayes
3个回答

1

感谢大家抽出时间。

  1. 不,这不是浮点精度误差。
  2. 我们正在运行时实例化对象,但当问题发生时,我们切换到对象池,但没有帮助。
  3. 我进行了彻底的分析,甚至在设备上进行了远程分析,垃圾回收器也不是问题所在。

经过进一步研究,我发现了一个BLOG POST,这些人面临着几乎相似的问题,并且解决方案适用于我的情况。

简而言之,问题在于Unity框架与设备的帧绘制率不同步。当Unity需要更长时间来渲染其帧时,设备渲染循环将不会等待Unity完成并绘制一个空帧,这会导致抖动。但是,正如我在文章标题中所说的“不一致的抖动”,该博客也报告了同样的问题,因此并不总是发生。

你怎么知道这是同一个问题?好吧,你会在分析器中看到Render峰值(尽管我们的几何形状非常简单)。它看起来更像是渲染出了问题。
虽然博客更多地涉及输入延迟问题,但它也对我的情况有所帮助。有些人可能不太明白如何解决这个问题,我建议他们阅读POST,该文章提供了更清晰的解决方案。
为了进一步学习,可以从用户"cgJames"加入CONVERSATION开始阅读。
希望这也能帮助其他人。

1
这可能是由很多不同的原因引起的,没有看到任何代码,我只能提出一些想到的建议:
1. 浮点精度误差
- 角色是否不断下落? - 错误是否在角色下落一段时间后发生?
这将指向浮点精度错误。不要让角色掉落,而是将物体从屏幕视图下方移动到屏幕视图上方,使所有内容都在原点附近发生。
2. 经常实例化或其他卡顿
- 您是否正在实例化对象或对其进行池化? - 是否执行任何长时间的计算? - 是否有许多for/foreach/while循环?
实例化会导致卡顿并创建垃圾,这将导致垃圾收集器更频繁地运行。由于帧速率是固定的,当出现缓慢的操作时,您会看到一些抖动。

与其在玩家走过一段距离时实例化和销毁对象,你应该在场景加载后使用Instantiate创建一个游戏对象池,并使用gameObject.SetActive(false)将它们设置为非活动状态,并将它们存储在列表、数组等中。当需要Instantiate新对象时,只需从池中获取一个对象,并在需要时更改其Transform.positiongameObject.SetActive(true)

3. 垃圾收集器经常运行

这可能不是一个问题,但还是要提一下。看这个示例代码:

void Update()
{
    Vector3 someVector = new Vector3(0,0,0);
    float distance = someVector.magnitude;
    if (distance > 5.0f)
        Vector3 someNewVector = someVector + transform.position;
    else
        Vector3 someNewVector = Vector3.zero;
}

每次Update运行时,它都会创建新的变量并为其分配内存。下一次Update运行时,它会创建新的变量,并分配更多的内存。最终,内存使用量会触发垃圾回收器,该回收器会遍历并释放所有之前Update函数使用的内存。相反,您应该在开始时分配内存,然后重复使用变量。
void Start()
{
    Vector3 someVector = new Vector3(0,0,0);
    Vector3 someNewVector = new Vector3(0,0,0);
    float distance = 0f;
}
void Update()
{
    someVector = Vector3.zero;
    float distance = someVector.magnitude;
    if (distance > 5.0f)
        Vector3 someVector += transform.position;
    else
        Vector3 someVector = Vector3.zero;
}

要诊断这个问题,您需要连接剖析器并观察,看抖动是否与垃圾回收器一致。
希望这里的内容对您有所帮助。找到抖动源的最佳方法是使用剖析器。以下是 iOS 的说明:
将您的 iOS 设备连接到 WiFi 网络(本地/自组 WiFi 网络用于从设备向 Unity 编辑器发送剖析数据)。在 Unity 的构建设置对话框中选中“自动连接剖析器”复选框。通过电缆将您的设备连接到 Mac,选中 Unity 构建设置对话框中的“开发构建”复选框,并在 Unity 编辑器中点击“构建并运行”。当应用程序在设备上启动时,在 Unity 编辑器中打开剖析器窗口(Window->Profiler)。
更多信息:剖析器窗口

0

我最近也遇到了同样的问题。在Unity中使用垂直滚动条,图形简单,在iOS设备上经历了不一致的帧速率,有时可能与输入有关,也可能与输入无关。

无论如何,我最终找到了问题所在。尝试将iOS上的渲染引擎从Metal更改为OpenGL ES 2或3。

希望这也能解决你的问题。


谢谢你的回答。我一定会尝试这个方法,如果有效的话,我会再联系你的。 - Anas iqbal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接