【问题标题】:Shader to warp or pinch specific areas of a texture in Unity3d在 Unity3d 中扭曲或收缩纹理的特定区域的着色器
【发布时间】:2019-11-25 16:19:24
【问题描述】:

我在下图中模拟了我想要完成的任务 - 尝试将像素捏向 AR 标记的中心,这样当我覆盖 AR 内容时,AR 标记就不那么明显了。

我正在寻找一些可以参考的示例或教程,以开始学习如何创建着色器以扭曲纹理,但我一无所获。

实现此目的的最佳方法是什么?

【问题讨论】:

  • 这可以做到(我有一个着色器在...某处),但我不确定它是否会使标记“不那么引人注目”。
  • 谢谢。我同意。这实际上是对我正在做的事情的过度简化,但了解上述工作原理将有助于我将其应用于其他用例。

标签: unity3d shader fragment-shader shaderlab


【解决方案1】:

这可以使用GrabPass来实现。

来自手册:

GrabPass 是一种特殊的传递类型——它在对象即将被绘制成纹理的位置抓取屏幕内容。此纹理可用于后续通道以执行基于图像的高级效果。

扭曲效果的工作方式基本上是在网格顶部渲染 GrabPass 纹理的内容,除了其 UV 扭曲。执行此操作的常用方法(用于热变形或冲击波等效果)是渲染带有法线贴图的广告牌平面,其中法线贴图控制背景样本的 UV 扭曲程度。这是通过将法线从世界空间转换到屏幕空间,将其与强度值相乘,并将其应用于 UV 来实现的。这种着色器有一个很好的例子here。您也可以在技术上使用任何网格并以类似的方式使用其顶点法线进行置换。

除了法线映射平面之外,实现此效果的另一种方法是使用Shader.SetGlobalVector 将跟踪器的屏幕空间位置传递到着色器中。然后,在着色器中,您可以计算片段和对象之间的向量,并使用它来偏移 UV,可能使用一些重映射函数(如平方距离)。例如,您可以使用float2 uv_displace = normalize(delta) * saturate(1 - length(delta))

如果您想准确控制应用此效果的方式和时间,请将 ZTest 和 ZWrite 设置为 Off,然后将渲染队列设置在背景之后但在跟踪器之前。

对于 AR 应用,可以通过使用相机背景纹理而不是 GrabPass 纹理来避免使用 GrabPass 的性能开销。您可以尝试查看您的相机背景脚本,看看它如何将相机纹理传递到着色器并尝试复制它。

这里有两个视频展示了 GrabPass 的工作原理:

https://www.youtube.com/watch?v=OgsdGhY-TWM

https://www.youtube.com/watch?v=aX7wIp-r48c

【讨论】:

  • 谢谢,这很有帮助。我被困在“计算片段和对象之间的向量”上,因为我不知道如何或在哪里使用 frag 函数中 SetGlobalVector("_PinchPoint",randomGameObject.transform.position) 中设置的 _PinchPointVector。
  • Shader.SetGlobalVector 在 Unity 的 C# 脚本中使用,您可以将其附加到跟踪器。您可以使用 Camera.WorldToScreenPoint(transform.position) 将跟踪器的位置转换为屏幕空间。您需要在着色器中定义float4 _PinchPoint,并使用ComputeScreenPos(o.vertex)(其中o.vertex 是剪辑空间顶点位置)来计算屏幕位置。减去位置得到你的位移向量。
  • “减去位置”是指从 i.screenPos 中减去 _PinchPoint(可以从顶点着色器传递)。然后你会得到一个从片段位置指向夹点的向量。结果向量的 X 和 Y 坐标是相对于屏幕的增量坐标,而 Z 是深度差。使用类似于我在答案中描述的公式将此增量转换为 UV 偏移量。
  • 我的 uv 偏移功能与上面的目的有点不同,但它似乎确实可以在固定点周围挤压或膨胀 uv。有没有更好的办法?下一步是让它针对更复杂的形状而不是折叠成一个点...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多