缓慢移动精灵时出现“咯咯笑”的效果

44
我该如何消除精灵缓慢移动时的“咯咯笑声”效果?
我已经尝试在Unity编辑器中调整QualitySettings中的抗锯齿值和ImportSettings中的过滤模式,但这并没有改变任何东西。

enter image description here

理想情况下,我希望将过滤模式保持为“点(无过滤器)”,并将抗锯齿打开至2x。

enter image description here

精灵位于GameObject的Sprite Renderer组件内。

我在这里上传了我的Unity项目:http://www.filedropper.com/sprite

我真的不知道如何解决这个问题...有人能帮助我的个人项目吗?


1
通常情况下,您需要将坐标夹紧到最近的非分数像素坐标,并将分数部分单独处理。我不确定Unity是否有自动处理此问题的方法。 - Collin Dauphinee
精灵上是否附加了刚体? - Ageonix
还有,您是在Update还是FixedUpdate中移动它? - Ageonix
你是在从IDE运行的Windows上还是设备上注意到这个问题的?所有这些因素都可能是影响因素。 - Ageonix
2
我的好天啊,在这个评论区里有很多错误信息。不,这与FixedUpdate没有任何关系(对于某些功能确实有使用的充分理由),也不涉及到双缓冲。这是在使用缩放纹理时相当常见的采样伪影。 - DMGregory
显示剩余6条评论
4个回答

81
我为了演示这里发生的情况制作了一个简单的动画:

Animation demonstrating source of ripple

网格代表您的显示器输出像素。我在其上方叠加了我们想要采样的滑动精灵,如果我们能用无限次子像素分辨率呈现它的话。
每个网格单元中心的点代表它们的采样点。因为我们使用最近邻/点过滤,那是纹理中唯一的点它们关注。当新颜色的边缘穿过该采样点时,整个像素会立即改变颜色。
问题出现在源纹理网格与我们的输出像素不对齐时。在上面的示例中,精灵是16x16个像素,但我将其缩放以占据17x17个像素。这意味着在每个帧中,某些像素必须被重复。随着我们移动精灵,这种情况发生的位置也会发生变化。
因为每个像素渲染的比一个像素略大,所以有一个时刻它完全跨越了相邻两个像素的采样点。两个采样点都落在同一个放大的像素内,所以两个像素都将该像素视为最近的采样点,并且该像素在屏幕上的两个位置输出。
在这种情况下,由于只有1/16的比例差异,每个纹素仅在一个或两个帧中处于这种奇怪的状态,然后它就会移动到其相邻的纹素,创建一个双倍像素的涟漪,似乎滑过图像。
有人可能认为这是一种莫尔纹样,因为当纹理网格和采样网格不同时发生互动时会产生这种情况)
修正方法是确保缩放像素艺术作品,使得每个纹素以整数倍的像素大小显示
要么是1:1。

Animation showing ripple-free rendering at 1:1 scale

或者2:1,3:1 ...

Animation showing ripple-free rendering at 3:1 scale

使用更高的倍数可以让精灵以比其自身像素尺寸更短的增量移动,而不会产生影响艺术预期外观的局部拉伸。
因此,请密切关注输出分辨率和应用于资产的缩放,以确保它们之间保持整数倍关系。CAD97链接的博客文章提供了实际步骤,可帮助您实现此目标。
编辑:为了在您上传的Unity项目中演示这一点,我修改了相机设置以匹配您的像素到单位设置,并布置了以下测试。顶部的Mario具有略微非整数的像素对纹理比率(1.01:1),而底部的Mario则是1:1。您可以看到只有顶部的Mario展现了波纹伪影。

Two Marios, one exhibiting artifacts


谢谢你的回答!所以,简单来说:原始图像的尺寸越大,结果就越好? - user5655032
2
并不完全正确。如果我将我的精灵放大到3.5倍正常比例,那么它就比上面的3:1示例更大,但它仍然会产生涟漪效应,因为我们再次有一个纹理覆盖了非整数像素。因此,为避免涟漪效应,请坚持使用整数大小。现在,您的对象将每次移动一个完整的屏幕像素。如果您的图像更大,则1个屏幕像素将是图像总大小的较小分数,但在屏幕上仍然具有相同的物理大小,因此通过继续将图像放大来获得精度或平滑度是没有意义的,除非从相对角度考虑。 - DMGregory
所以,解决这个问题只需要:将相机设置修改为与每单位像素设置相匹配的值? - user5655032
1
@Alex 实际上是这样的。源像素大小 * 每单位像素数 * 对象缩放 = 世界大小 如果我们考虑垂直轴,世界大小 / (相机大小 * 2) = 垂直屏幕分数(即对象占据屏幕总垂直大小的比例)。最后 垂直屏幕分数 * 垂直屏幕大小 = 垂直像素大小 - 它实际呈现的像素高度。您需要根据屏幕大小调整缩放或相机大小,以确保输出像素的显示像素数量为整数。 - DMGregory
3
感谢您提供的出色答案,这些动态图真的非常棒。它们让我停下来阅读和理解发生了什么,即使我对这个领域没有兴趣!+1 - Ian
显示剩余8条评论

9

您可能会对这篇关于在Unity中制作“像素完美”的2D游戏的博客文章感兴趣。

以下是一些相关摘录:

如果您使用Unity的所有默认设置开始制作像素游戏,它看起来会很糟糕!

让您的像素化游戏看起来好看的秘密是确保您的精灵在漂亮的像素边界上呈现。换句话说,确保您的每个精灵像素都呈现在一个屏幕像素上。

这些其他设置对于使事物尽可能清晰至关重要。

在精灵上:

  • 确保您的精灵使用无损压缩,例如True Color
  • 关闭mipmapping
  • 使用点采样

在渲染质量设置中:

  • 关闭各向异性过滤
  • 关闭抗锯齿

通过创建使用Sprite/Default着色器的自定义材质并将其附加到SpriteRenderer中,在精灵着色器中打开像素捕捉。

另外,我只想指出,除非你正在应用物理学,永远不要使用FixedUpdate。此外,如果您的精灵具有Collider并且正在移动,则即使您永远不会使用物理学,它也应该附加Kinematic RigidBody以告诉引擎Collider将会移动。


1
在这里为Unity2D投票支持一个专门的像素完美模式。https://feedback.unity3d.com/suggestions/pixelperfect-2d-mode - CAD97
非常好的回答。不幸的是,我已经尝试了上面所有的方法,但仍然没有成功。因此,我在这里上传了我的Unity项目:http://www.filedropper.com/sprite 我还附上了一个使精灵移动的脚本。 - user5655032
我真的不知道出了什么问题。有人能帮忙看看我的项目吗? - user5655032
1
我对“永远不要使用FixedUpdate”的建议非常谨慎。即使不使用物理引擎,如果您希望游戏在渲染帧率不同的情况下表现一致,FixedUpdate也很重要。如果您在Update()中应用任何类型的非线性状态更改,则结果往往会在高帧率运行游戏的设备和低帧率运行游戏的设备之间发散。链接的线程反对增加FixedUpdate速率以期将其用作某种高性能计时器,因为它不是这样的,但仍然建议在核心游戏中使用FixedUpdate。 - DMGregory
大多数情况下,在Update * Time.deltaTime中进行工作已经足够准确。FixedUpdate仅应用于像物理系统这样需要在落后时追赶的系统。有些情况适用于非物理工作,但大多数情况下都有一个内置组件来处理它。除非是熟悉系统并且知道如何不滥用FixedUpdate的人,否则很少出现剩余的情况。我的默认建议是避免使用FixedUpdate,因为那些不了解的人会过度使用它。但这不是问题的重点,所以让我们离开它。 - CAD97
我已经升级到LWRP/URP,这样我就可以在我的项目中使用2D灯光了。然而问题是,当你从'Sprite/Default'升级到这些渲染管线时,你必须将你的材质更新为'Sprite-Lit-Default'。在新的材质中,没有"Pixel Snap"选项。我在这里链接了一个相关的问题:https://stackoverflow.com/questions/62764718/no-pixel-snap-option-in-sprite-lit-default-material-causing-some-sprites-to你能帮我解决这个吗? - Dran Dev

0

我也遇到了同样的问题。我注意到相机设置和比例也很重要,可以解决波纹问题。


0
这是我的解决方案: 进入项目设置>质量
  • 在质量下,将默认质量设置为高。
  • 将各向异性纹理设置为“禁用”。 完成,问题已解决。

图像参考: 输入图像描述


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