Unity3d 着色器饱和()在不应该时创建渐变';T

Unity3d 着色器饱和()在不应该时创建渐变';T,unity3d,shader,hlsl,vertex-shader,shaderlab,Unity3d,Shader,Hlsl,Vertex Shader,Shaderlab,为Unity编写着色器,我不明白这里发生了什么。我有一个球体,上面有一个材料。材质附加了一个着色器。着色器非常简单,它生成一些单纯形噪波,然后将其用作球体的颜色 着色器代码: Shader "SimplexTest" { Properties { _SimplexScale("Simplex Scale", Vector) = (4.0,4.0,4.0,1.0) } SubShader { Tags { "RenderType"

为Unity编写着色器,我不明白这里发生了什么。我有一个球体,上面有一个材料。材质附加了一个着色器。着色器非常简单,它生成一些单纯形噪波,然后将其用作球体的颜色

着色器代码:

Shader "SimplexTest"
{
    Properties
    {
      _SimplexScale("Simplex Scale", Vector) = (4.0,4.0,4.0,1.0)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue"="Geometry" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "SimplexNoise3D.hlsl"

            float3 _SimplexScale;

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 position : SV_POSITION;
                float4 color : COLOR0;
            };

            v2f vert (appdata v)
            {
                v2f o;
                float4 worldPosition = mul(unity_ObjectToWorld, v.vertex);
                o.position = UnityObjectToClipPos(v.vertex);

                float small = snoise(_SimplexScale * worldPosition);
                // o.color = small * 10; // Non-Saturated (A) Version
                o.color = saturate(small * 10); // Saturated (B) Version

                return o;
            }


            fixed4 frag (v2f i) : SV_Target
            {
                return i.color;
            }
            ENDCG
        }
    }
}
单纯形噪声函数来自

非饱和(A)版本:

饱和(B)版本:

非饱和版本(版本A)与预期一致。通过将单纯形噪声乘以系数10,结果是一系列白色和黑色斑点。饱和(版本B)理论上应该只在1处切掉所有白色斑点,在0处切掉黑色斑点。但它似乎创造了一个全新的梯度,我不知道为什么


我假设我遗漏了一些关键假设,但我不清楚这是什么,因为数学似乎正确。

在灰色区域中,片段着色器的像素位于颜色0和1的顶点之间。这意味着在这些值之间插入输入,创建灰色
i.color


一种解决方案是首先将网格更改为每个三角形具有单独的顶点,以便每个三角形的所有顶点都具有相同的法线

然后,一旦每个三角形的所有顶点共享同一法线,就可以基于顶点着色器中的
SV_normal
值而不是变换的
位置
值生成颜色

大致如下:

struct appdata
{
    float4 vertex : POSITION;
    float4 normal : NORMAL;
};

然后,它应该像预期的那样工作


另一种有助于实现这一点的方法(如果希望在版本A中保留一点点插值)是让插值继续,但只需在片段着色器中执行饱和度:

v2f vert (appdata v)
{
    v2f o;
    float4 worldPosition = mul(unity_ObjectToWorld, v.vertex);
    o.position = UnityObjectToClipPos(v.vertex);

    float small = snoise(_SimplexScale * worldPosition);
    o.color = small * 10;

    return o;
}


fixed4 frag (v2f i) : SV_Target
{
    return saturate(i.color);
}


在示例a中,问题在很大程度上没有发生的原因是,它是在小于或等于零的值和一个大的正数之间插值。由于在一个非常大的数字和零附近的值之间插值的值通常会大于1,因此会得到许多渲染为白色的像素。

使用法线没有帮助,因为我无法确定如何更改网格,但是将饱和代码移到片段着色器而不是顶点着色器中解决了这个问题。谢谢你的真知灼见。很高兴我能帮上忙!我在答案中添加了这个解决方案:)
v2f vert (appdata v)
{
    v2f o;
    float4 worldPosition = mul(unity_ObjectToWorld, v.vertex);
    o.position = UnityObjectToClipPos(v.vertex);

    float small = snoise(_SimplexScale * worldPosition);
    o.color = small * 10;

    return o;
}


fixed4 frag (v2f i) : SV_Target
{
    return saturate(i.color);
}