在合并之前删除tex2D的一部分

时间:2015-01-22 21:38:04

标签: unity3d shader cg

我编写一个统一表面着色器来慢慢应用这样的锈效果:

//Take 1 base color texture.
//Take 1 rust decal texture and 1 greyscale maps.
//Take 1 float range value.

然后:

//Use the range to remove from the grayscale map all the pixels that are darker than the value itself, then make theese greysclae map the rust alpha, then apply this composited rust layer over the color texture.

我设法做到了:

        void surf (Input IN, inout SurfaceOutputStandard o) {
            half4 C = tex2D (_MainTex, IN.uv_MainTex); //Color Texture
            half4 R = tex2D (_RustTex, IN.uv_RustTex); //Rust texture
            half4 RG = tex2D (_RustGuide, IN.uv_RustGuide); //Greyscale texture

            //Here i need to compose the rust layer
            half4 RustResult = //??? Maybe a Clip() function or what? and how?

            //Here i apply the previusly composed layer over the color texture. Already tested and working.
            half4 Final = lerp (C, RustResult, RustResult.a);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }

那我怎么能完成这个着色器呢? 我无法找到有关表面着色器中可用功能的详细文档。

编辑:我几乎得到了我需要的饱和度();功能如下

    Properties {
    _MainTex ("Base (RGB)", 2D) = "" {} //the color texture
    _RustTex ("Rust Texture (RGB)", 2D) = "" {} //the rust texture
    _RustGuide ("Rust Guide (A)", 2D) = "" {} //the rust greyscale texture
    _RustAmount ("Rust Amount", range(0.0, 1.0)) = 0.0 //the rust amount float value
    _RustMultiplier ("Rust Multiplier", float) = 2
}

SubShader {
    Tags { "RenderType"="Opaque" }
    LOD 200

    CGPROGRAM
    #pragma target 3.0
    #include "UnityPBSLighting.cginc"
    #pragma surface surf Standard

    sampler2D _MainTex;
    sampler2D _RustTex;
    sampler2D _RustGuide;
    float _RustAmount;
    float _RustMultiplier;

    struct Input {
        float2 uv_MainTex;
        float2 uv_RustTex;
        float2 uv_RustGuide;
    };

    void surf (Input IN, inout SurfaceOutputStandard o) {
        half4 M = tex2D (_MainTex, IN.uv_MainTex);
        half4 R = tex2D (_RustTex, IN.uv_RustTex);
        half4 RG = tex2D (_RustGuide, IN.uv_RustGuide);
        half4 RustResult;
        RustResult.rgb = R.rgb;

        if (_RustAmount > 0) {
        RustResult.a = trunc(saturate(RG.a * _RustAmount * _RustMultiplier);
        }

        half4 Final = lerp (M, RustResult, RustResult.a);
        o.Albedo = Final.rgb;
        o.Alpha = Final.a;
    }
    ENDCG
} 
FallBack Off

}

这会产生我需要的效果。现在唯一的问题是我如何模糊alpha的边缘?

1 个答案:

答案 0 :(得分:0)

  

使用该范围从灰度图中删除所有像素   比价值本身更暗

难道你不能简单地将_RustAmount浮动下面的值钳位吗?类似的东西:

float greyScaleMapValue = tex2D(_RustGuide, IN.uv_RustGuide).a; //assuming rust guide is stored as a single channel

float clampedMap = clamp(greyScaleMapValue , _RustAmount, 1); //clamped map stores a value clamped between _RustAmount and 1 -> every pixel darker than _RustAmount are 0

half3 albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
half3 rust = tex2D (_RustTex, IN.uv_RustTex).rgb;
float3 finalCol = lerp(albedo, rust, clampedMap); // all values in the map below _RustAmount will have plain albedo value, the other will be blended with rust using the map

return float4(finalCol,1);

请注意,上面的代码会产生从纹理到生锈的突然转换(更突然的更多_RustmAmount高于零)。您希望最终在[0,1]范围内的钳位后重新映射高于零的每个值。

如果您需要平滑过渡,可以将间隔[_RustAmount,1]重新映射到[0,1]

float clampedMapNormalized = (clampedMap - _RustAmount) / (1 - _RustAmount);

希望这有帮助

旁注:

  • 避免在着色器中分支(即使制服上的分支在现代硬件上不应该如此痛苦)
  • 如果地图使用其他2个纹理之一的相同uv坐标(和平铺)集合,则可以使用少一个纹理样本操作将其打包到相对Alpha通道内。
  • 由于你的着色器是不透明的,我猜最终的alpha值是不相关的,所以我只使用float3来最小化要被删除的值。