【问题标题】:my shader is ignoring my worldspace height我的着色器忽略了我的世界空间高度
【发布时间】:2020-08-21 19:40:01
【问题描述】:

我对着色器非常陌生,所以请多多包涵。我有一个网格,我想在世界空间位置 y 下方放置沙子纹理,例如 10,否则它应该是草纹理。显然,它似乎忽略了我放入的任何东西,只选择了草纹理。发生了一些事情,因为与我只返回相同的纹理相比,我的 vert 和 tris 计数使用此函数爆炸。无论我的 sandStart 值是多少,我都看不到任何东西

这是在我的 frag 函数中:

if (input.positionWS.y < _SandStart) {
return tex2D(_MainTex, input.uv)* mainLight.shadowAttenuation;
} else {
return tex2D(_SandTex, input.uv) * mainLight.shadowAttenuation;
}

还有什么方法可以让我轻松调试一些值吗?

【问题讨论】:

  • 在着色器中调试值很痛苦,颜色几乎是你最安全的选择。我建议您尝试一下,看看是不是 input.positionWS.y&lt; _SandStartreturn tex2D 部分有问题。 1)如果您将 y 位置返回为其红色值,它会是什么样子? return float4 (input.positionWS.y, 0,0,1)(确保标准化或除以某个值,使其落在 0 > 1 范围内)。通过这种方式,您可以将当前的.y 值视为红色强度。 2) 将return tex2D 替换为return float4(1,0,0,1)return float4(0,1,01) 之类的纯色(检查if)
  • 谢谢 - 使用颜色是个好主意 :) 我试试吧
  • 非常感谢,调试方法很棒,只是在我的几何函数中分配了错误的数字。抛出一个调试的答案并且不接受它:)

标签: unity3d fragment-shader


【解决方案1】:

请注意,OP发现他们的具体问题不是由问题中的代码引起的,而是他们的几何函数错误,这个答案只是关于“有没有办法调试着色器值”,因为这种调试方法帮助 OP 找到了问题


调试着色器代码可能是一项相当具有挑战性的任务,具体取决于您需要调试的内容,并且有多种方法可以解决此问题。我个人最喜欢的方法是使用颜色。

如果我们将其分解,您的代码中可能存在三个方面的问题:

  • input.positionWS.y的值
  • if 语句(input.positionWS.y &lt; _SandStart)
  • 返回你的纹理return tex2D(_MainTex, input.uv)* mainLight.shadowAttenuation;

让我们逐个列出并单独测试。

  1. 检查input.positionWS.y 是否真的包含我们期望它包含的值。为此,我们可以将任何 RGB 通道设置为其值,然后直接返回该值。
return float4(input.positionWS.y, 0, 0, 1);

现在,如果input.positionWS.y 不是标准化值(也就是范围从 0 到 1 的值),这几乎可以保证将您的纹理返回为完全红色。为了规范化它,我们将值除以其最大值,我们以max = 100 为例。

return float4(input.positionWS.y / 100, 0, 0, 1);

现在应该使纹理在顶部(input.positionWS.y / 100 为 1)为全红色,在底部为黑色(input.positionWS.y / 100 为 0),以及从黑色到全红色的渐变。 (请注意,由于它在世界空间中的位置,您可能需要向上/向下移动纹理以查看颜色变化)。如果这没有发生,例如它始终保持黑色或全红色,那么您的问题很可能是 input.positionWS.y

  1. if 语句。可能您的语句(input.positionWS.y &lt; _SandStart) 总是返回truefalse,这意味着它永远不会分裂。我们可以通过注释掉当前返回的纹理来很容易地测试这一点,而不是像这样返回一个平面颜色:
if(input.positionWS.y < _SandStart)
{
    return float4(1,0,0,1);
}
else
{
    return float4(0,0,1,1);
}

如果我们在步骤 1 中测试了 input.positionWS.y 是正确的,并且 _SandStart 设置正确,我们应该看到纹理被分为红色部分(如果为真)和另一部分蓝色(如果为假)(再次因为我们基于世界位置,我们可能需要稍微改变材质的高度才能看到它)。如果这种颜色划分没有发生,那么可能的原因是_SandStart 设置不正确,或者设置了不正确的值。 (假设这是一个属性,您可以在材质编辑器中检查其值)

  1. 如果上述两个步骤都产生了预期的结果,那么 return tex2D(_MainTex, input.uv)* mainLight.shadowAttenuation; 可能是罪魁祸首。为了调试这一点,我们可以在不使用 if 语句和 shadowAttenuation 的情况下返回其中一个纹理,查看它是否应用了该纹理,然后通过更改注释的行返回另一个纹理。
return tex2D(_MainTex, input.uv);
//return tex2D(_SandTex, input.uv);

如果这些纹理中的每一个都被分别正确应用,那么这不太可能是您的原因,留下 shadowAttenutation(只需将乘法添加到上述测试中)或完全不同的东西,您的代码中没有涵盖问题。

  1. 奖金回合。如果你有一个想要调试的着色器property,你实际上可以从 C# 中执行此操作,也可以使用 material.Get&lt;type&gt; 函数(支持的类型可以在 docs here 中找到,并包括数组变体以及GetSet)。一个小例子:
Properties 
{
_Foo ("Foo", Float) = 2
_Bar ("Bar", Color) = (1,1,1,1)
}

可以使用 C# 进行调试

Material mat = getComponent<Material>();
Debug.LogFormat("_Foo value: {0}",  mat.GetFloat("_Foo"); //prints 2
Debug.LogFormat("_Bar value: {0}",  mat.GetFloat("_Bar"); //prints (1,1,1,1)

【讨论】:

    猜你喜欢
    • 2018-02-04
    • 1970-01-01
    • 1970-01-01
    • 2015-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多