1

我有一个着色器函数,其功能类似于 Blender3D 中的“色带”节点。它将一个介于 0 和 1 之间的浮点数作为输入,并输出一种颜色,该颜色是按指定顺序混合了任意数量的颜色:

blender3D 颜色渐变
blender3D 颜色渐变

这是我的代码:

fixed4 ColorRamp(float factor){
            float positions[5] = {_Pos0, _Pos1, _Pos2, _Pos3, _Pos4}; 
            fixed4 colors[5] = {_Color0, _Color1, _Color2, _Color3, _Color4}; 

            fixed4 outColor = _Color0;

            for(int i = 0; i <4; i++){

                if(factor >= positions[i] && factor <positions[i+1]){
                    fixed localFactor = (factor - positions[i])/(positions[i+1] - positions[i]);
                    outColor =  lerp(colors[i], colors[i+1], localFactor);
                }else if (factor > positions [_NumColors-1]){
                    outColor = colors[_NumColors -1];
                }
            }
            return outColor;
        }

有用。但它很糟糕,有几个原因:

  1. 渐变中的颜色数量是硬编码的。在 Unity 编辑器中添加它们的列表会好得多。
  2. if/else 语句。我知道这些对性能很糟糕,应该避免。
  3. 颜色数组在函数中声明,这意味着必须为每个片段创建一个新数组(我认为)。

我的主要问题是第一个问题:如何在无需编辑硬编码值的情况下更改渐变中的颜色数量?

4

3 回答 3

1

布莱斯是对的。我可以直接告诉你——没有人将这种类型的渐变用于着色器,仅仅是因为它与仅使用 1x128px 色带纹理相比几乎没有任何优势。使用这样的查找纹理:

fixed4 col = tex2D(_MainTex, i.uv); // Sample the input texture
half lum = dot(col.rgb, fixed3(0.3, 0.59, 0.11)); // Color to luminosity
col = tex2D(_LookUpTex, float2(lum, 0)); // Get value from color ramp

如果您想为用户创建一个方便的检查器,只需从渐变生成查找纹理,然后通过 OnValidate() 处的脚本将其分配给着色器。只需为 0 到 127 之间的每个 x 评估 x/127.0 处的梯度,就可以轻松生成一个。Unity 有一个特殊的 Gradient 类,当暴露时,它会在检查器中为您提供一个渐变编辑器。

于 2018-12-28T01:20:04.767 回答
0

简单的答案是:将渐变烘焙成纹理

于 2017-11-10T14:36:06.067 回答
0
  1. 不可能。着色器将自动编译。并且编译器不支持循环。您的循环只是语法糖,在编译时将扩展为确定的迭代次数。
  2. if/else 对性能来说并不可怕。它仅对测试不利,因为它会增加圈复杂度。
  3. 您可以在“属性”块中声明数组。

抱歉,但您没有在属性块中使用数组。您将在方法之外声明它。

float positions[5]; 
fixed4 colors[5]; 

fixed4 ColorRamp(float factor){
    positions[0] = _Pos0;
    positions[0] = _Pos2;
    positions[0] = _Pos3;
    positions[0] = _Pos4;
    positions[0] = _Pos5;

    colors[0] = _Color0;
    colors[1] = _Color1;
    colors[2] = _Color2;
    colors[3] = _Color3;
    colors[4] = _Color4;

    fixed4 outColor = _Color0;

    for(int i = 0; i <4; i++)
    {
        if(factor >= positions[i] && factor <positions[i+1])
        {
            fixed localFactor = (factor - positions[i])/(positions[i+1] - positions[i]);
            outColor =  lerp(colors[i], colors[i+1], localFactor);
        }
        else if (factor > positions [_NumColors-1])
        {
            outColor = colors[_NumColors -1];
        }
    }
    return outColor;
}

但是您必须在统一脚本外部初始化数组。

float[] array = new float[] {1, 2, 3, 4, 5}
material.SetFloatArray("positions", array );
Vector4[] colors = new Vector4[] { new Vector4(), new Vector4(), new Vector4(), new Vector4(), new Vector4() };
material.SetVectorArray("colors", colors);
于 2017-10-16T14:33:51.963 回答