我的着色器忽略了我的世界高度

问题描述

我对着色器非常陌生,请耐心等待。我有一个网格,我想在世界空间位置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;
}

还有没有一种方法可以轻松调试某些值?

解决方法

请注意,OP发现其特定问题不是由问题中的代码引起的,而是其几何函数中的错误,此答案仅与问题“是否有调试方法着色器值”,因为该调试方法有助于OP找到问题


调试着色器代码可能是一项艰巨的任务,具体取决于您需要调试的内容,并且可以采用多种方法。我个人最喜欢的方法是使用颜色。

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

  • input.positionWS.y的值
  • if语句(input.positionWS.y < _SandStart)
  • 恢复纹理return tex2D(_MainTex,input.uv)* mainLight.shadowAttenuation;

让我们从列表中走下来并分别进行测试。

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

现在,如果input.positionWS.y不是规范化值(也就是0到1的值),则几乎可以保证仅将纹理返回为完全红色。为了对其进行归一化,我们将其值除以最大值,让max = 100作为示例。

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

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

  1. if语句。您的语句(input.positionWS.y < _SandStart)可能总是返回truefalse,这意味着它永远不会拆分。通过注释掉当前的返回纹理,我们可以很容易地进行测试,而只需返回如下的纯色即可:
if(input.positionWS.y < _SandStart)
{
    return float4(1,1);
}
else
{
    return float4(0,1,1);
}

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

  1. 如果以上两个步骤均产生预期结果,则 return tex2D(_MainTex,input.uv)* mainLight.shadowAttenuation;可能是罪魁祸首。要对此进行调试,我们可以返回不带if语句和shadowAttenuation的纹理之一,看看它是否应用了纹理,然后通过更改注释的行来返回另一个纹理。
return tex2D(_MainTex,input.uv);
//return tex2D(_SandTex,input.uv);

如果分别正确地应用了这些纹理中的每一个,则可能不是您的原因,而是留下了shadowAttenutation(只需将乘积添加到上面的测试中)或其他完全未被您的代码覆盖的东西问题。

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

可以使用C#从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)