美文网首页
Unity3D Shader教程九 Color Interpol

Unity3D Shader教程九 Color Interpol

作者: UnityAsk | 来源:发表于2019-08-12 19:25 被阅读0次

    通常情况下有多个颜色需要输出到屏幕上,通常情况下我们可以利用参数对它们进行插值来融合这些颜色。

    下面的脚本基于我们前面的教程 simple textured shader。

    颜色插值

    作为开始,我们仅仅使用两种纯色,因为这样我们不需要考虑uv坐标信息或者贴图信息。我们添加一个 _SecondaryColor 属性 代表第二种颜色,添加一个 _Blend 参数来 控制输出第一个颜色还是第二个颜色,我们声明 _Blend 的属性为Range,这样可以在Inspector上按滑动条的形式显示它。

    //...
    
    //show values to edit in inspector
        Properties{
            _Color ("Color", Color) = (0, 0, 0, 1) //the base color
            _SecondaryColor ("Secondary Color", Color) = (1,1,1,1) //the color to blend to
            _Blend ("Blend Value", Range(0,1)) = 0 //0 is the first color, 1 the second
    }
    
    //...
    
    //the value that's used to blend between the colors
    float _Blend;
    
    //the colors to blend between
    fixed4 _Color;
    fixed4 _SecondaryColor;
    
    

    除了删除和uv信息相关的代码之外,我们保留vertex shader 部分,然后修改fragment shader ,作为第一个版本我们只是通过 blend 的值添加第二个颜色到第一个颜色上。

    //the fragment shader
    fixed4 frag(v2f i) : SV_TARGET{
        fixed4 col = _Color + _SecondaryColor * _Blend;
        return col;
    }
    
    
    Blend Between two colors in a wrong way

    我们已经可以改变颜色了,但是还不能只显示第二种颜色。这是因为第二种颜第二种颜色是被加在第一种颜色之上的。(类似于将两个不同颜色的灯光照射到同一个区域)。

    我们改进一下,可以随着 blend 的值增加将第一个颜色的值减弱。当blend 的值为0时,我们看不到任何第二种颜色,全部显示第一种颜色。当blend 的值为1时,全部显示第二种颜色,而不显示第一种颜色。我们通过第一种颜色乘上 1 - _Blend 来实现。

    //the fragment shader
    fixed4 frag(v2f i) : SV_TARGET{
        fixed4 col = _Color * (1 - _Blend) + _SecondaryColor * _Blend;
        return col;
    }
    
    
    Blend Between two colors correctly

    这种方式也被称为 线性插值,unity也为我们提供了这样一个函数 lerp。

    //the fragment shader
    fixed4 frag(v2f i) : SV_TARGET{
        fixed4 col = lerp(_Color, _SecondaryColor, _Blend);
        return col;
    }
    
    

    完整的两种颜色插值融合 shader 代码如下:

    Shader "Tutorial/009_Color_Blending/Plain"{
        //show values to edit in inspector
        Properties{
            _Color ("Color", Color) = (0, 0, 0, 1) //the base color
            _SecondaryColor ("Secondary Color", Color) = (1,1,1,1) //the color to blend to
            _Blend ("Blend Value", Range(0,1)) = 0 //0 is the first color, 1 the second
        }
    
        SubShader{
            //the material is completely non-transparent and is rendered at the same time as the other opaque geometry
            Tags{ "RenderType"="Opaque" "Queue"="Geometry"}
    
            Pass{
                CGPROGRAM
    
                //include useful shader functions
                #include "UnityCG.cginc"
    
                //define vertex and fragment shader
                #pragma vertex vert
                #pragma fragment frag
    
                //the value that's used to blend between the colors
                float _Blend;
    
                //the colors to blend between
                fixed4 _Color;
                fixed4 _SecondaryColor;
    
                //the object data that's put into the vertex shader
                struct appdata{
                    float4 vertex : POSITION;
                };
    
                //the data that's used to generate fragments and can be read by the fragment shader
                struct v2f{
                    float4 position : SV_POSITION;
                };
    
                //the vertex shader
                v2f vert(appdata v){
                    v2f o;
                    //convert the vertex positions from object space to clip space so they can be rendered
                    o.position = UnityObjectToClipPos(v.vertex);
                    return o;
                }
    
                //the fragment shader
                fixed4 frag(v2f i) : SV_TARGET{
                    fixed4 col = lerp(_Color, _SecondaryColor, _Blend);
                    return col;
                }
    
                ENDCG
            }
        }
    }
    
    

    贴图插值

    接下来 我们 将 插值 从贴图读取出来的颜色。我们首先删除颜色相关的属性和变量,同时添加贴图相关的属性和变量。我们同时添加 uv 坐标信息,但是我们不在vertex shader 部分添加 tiling 和 offset。因为我们的多个贴图使用了同样的uv坐标信息。

    //...
    
    //show values to edit in inspector
    Properties{
        _MainTex ("Texture", 2D) = "white" {} //the base texture
        _SecondaryTex ("Secondary Texture", 2D) = "black" {} //the texture to blend to
        _Blend ("Blend Value", Range(0,1)) = 0 //0 is the first color, 1 the second
    }
    
    //...
    
    //the object data that's put into the vertex shader
    struct appdata{
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };
    
    //the data that's used to generate fragments and can be read by the fragment shader
    struct v2f{
        float4 position : SV_POSITION;
        float2 uv : TEXCOORD0;
    };
    
    //the vertex shader
    v2f vert(appdata v){
        v2f o;
        //convert the vertex positions from object space to clip space so they can be rendered
        o.position = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        return o;
    }
    
    //...
    
    

    然后在 fragment shader 部分,我们可以分别对两张贴图添加 添加 tiling 和 offset。我们使用这些坐标信息从两个贴图读取颜色信息,并对他们进行插值操作输出最终颜色。

    //the fragment shader
    fixed4 frag(v2f i) : SV_TARGET{
        //calculate UV coordinates including tiling and offset
        float2 main_uv = TRANSFORM_TEX(i.uv, _MainTex);
        float2 secondary_uv = TRANSFORM_TEX(i.uv, _SecondaryTex);
    
        //read colors from textures
        fixed4 main_color = tex2D(_MainTex, main_uv);
        fixed4 secondary_color = tex2D(_SecondaryTex, secondary_uv);
    
        //interpolate between the colors
        fixed4 col = lerp(main_color, secondary_color, _Blend);
        return col;
    }
    
    
    Blend Between two Textures

    对两张贴图进行插值的完整 shader 代码如下:

    Shader "Tutorial/009_Color_Blending/Texture"{
        //show values to edit in inspector
        Properties{
            _MainTex ("Texture", 2D) = "white" {} //the base texture
            _SecondaryTex ("Secondary Texture", 2D) = "black" {} //the texture to blend to
            _Blend ("Blend Value", Range(0,1)) = 0 //0 is the first color, 1 the second
        }
    
        SubShader{
            //the material is completely non-transparent and is rendered at the same time as the other opaque geometry
            Tags{ "RenderType"="Opaque" "Queue"="Geometry"}
    
            Pass{
                CGPROGRAM
    
                //include useful shader functions
                #include "UnityCG.cginc"
    
                //define vertex and fragment shader
                #pragma vertex vert
                #pragma fragment frag
    
                //the value that's used to blend between the colors
                float _Blend;
    
                //the colors to blend between
                sampler2D _MainTex;
                float4 _MainTex_ST;
    
                sampler2D _SecondaryTex;
                float4 _SecondaryTex_ST;
    
                //the object data that's put into the vertex shader
                struct appdata{
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                };
    
                //the data that's used to generate fragments and can be read by the fragment shader
                struct v2f{
                    float4 position : SV_POSITION;
                    float2 uv : TEXCOORD0;
                };
    
                //the vertex shader
                v2f vert(appdata v){
                    v2f o;
                    //convert the vertex positions from object space to clip space so they can be rendered
                    o.position = UnityObjectToClipPos(v.vertex);
                    o.uv = v.uv;
                    return o;
                }
    
                //the fragment shader
                fixed4 frag(v2f i) : SV_TARGET{
                    //calculate UV coordinates including tiling and offset
                    float2 main_uv = TRANSFORM_TEX(i.uv, _MainTex);
                    float2 secondary_uv = TRANSFORM_TEX(i.uv, _SecondaryTex);
    
                    //read colors from textures
                    fixed4 main_color = tex2D(_MainTex, main_uv);
                    fixed4 secondary_color = tex2D(_SecondaryTex, secondary_uv);
    
                    //interpolate between the colors
                    fixed4 col = lerp(main_color, secondary_color, _Blend);
                    return col;
                }
    
                ENDCG
            }
        }
    }
    
    

    基于贴图的插值

    最后我们来看下如何通过一张贴图作为参数来插值,而不是像上面那样通过一个单一的数值 (_blend) 插值。

    我们将 _blend 相关代码改为_BlendTex,它是一张贴图。

    //...
    
    //show values to edit in inspector
    Properties{
        _MainTex ("Texture", 2D) = "white" {} //the base texture
        _SecondaryTex ("Secondary Texture", 2D) = "black" {} //the texture to blend to
        _BlendTex ("Blend Texture", 2D) = "grey" //black is the first color, white the second
    }
    
    //...
    
    //the texture that's used to blend between the colors
    sampler2D _BlendTex;
    float4 _BlendTex_ST;
    
    //the colors to blend between
    sampler2D _MainTex;
    float4 _MainTex_ST;
    
    sampler2D _SecondaryTex;
    float4 _SecondaryTex_ST;
    
    //...
    
    

    我们同样对这张贴图进行 TRANSFORM_TEX 操作,并从贴图中读取颜色信息。然后我们使用其中的颜色信息中的 r 通道 ,也就是 红色 部分,作为插值参数。

    //the fragment shader
    fixed4 frag(v2f i) : SV_TARGET{
        //calculate UV coordinates including tiling and offset
        float2 main_uv = TRANSFORM_TEX(i.uv, _MainTex);
        float2 secondary_uv = TRANSFORM_TEX(i.uv, _SecondaryTex);
        float2 blend_uv = TRANSFORM_TEX(i.uv, _BlendTex);
    
        //read colors from textures
        fixed4 main_color = tex2D(_MainTex, main_uv);
        fixed4 secondary_color = tex2D(_SecondaryTex, secondary_uv);
        fixed4 blend_color = tex2D(_BlendTex, blend_uv);
    
        //take the red value of the color from the blend texture
        fixed blend_value = blend_color.r;
    
        //interpolate between the colors
        fixed4 col = lerp(main_color, secondary_color, blend_value);
        return col;
    }
    
    
    Blend Between two textures based on a texture

    完整的shader代码如下:

    Shader "Tutorial/009_Color_Blending/TextureBasedBlending"{
        //show values to edit in inspector
        Properties{
            _MainTex ("Texture", 2D) = "white" {} //the base texture
            _SecondaryTex ("Secondary Texture", 2D) = "black" {} //the texture to blend to
            _BlendTex ("Blend Texture", 2D) = "grey" //black is the first color, white the second
        }
    
        SubShader{
            //the material is completely non-transparent and is rendered at the same time as the other opaque geometry
            Tags{ "RenderType"="Opaque" "Queue"="Geometry"}
    
            Pass{
                CGPROGRAM
    
                //include useful shader functions
                #include "UnityCG.cginc"
    
                //define vertex and fragment shader
                #pragma vertex vert
                #pragma fragment frag
    
                //the texture that's used to blend between the colors
                sampler2D _BlendTex;
                float4 _BlendTex_ST;
    
                //the colors to blend between
                sampler2D _MainTex;
                float4 _MainTex_ST;
    
                sampler2D _SecondaryTex;
                float4 _SecondaryTex_ST;
    
                //the object data that's put into the vertex shader
                struct appdata{
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                };
    
                //the data that's used to generate fragments and can be read by the fragment shader
                struct v2f{
                    float4 position : SV_POSITION;
                    float2 uv : TEXCOORD0;
                };
    
                //the vertex shader
                v2f vert(appdata v){
                    v2f o;
                    //convert the vertex positions from object space to clip space so they can be rendered
                    o.position = UnityObjectToClipPos(v.vertex);
                    o.uv = v.uv;
                    return o;
                }
    
                //the fragment shader
                fixed4 frag(v2f i) : SV_TARGET{
                    //calculate UV coordinates including tiling and offset
                    float2 main_uv = TRANSFORM_TEX(i.uv, _MainTex);
                    float2 secondary_uv = TRANSFORM_TEX(i.uv, _SecondaryTex);
                    float2 blend_uv = TRANSFORM_TEX(i.uv, _BlendTex);
    
                    //read colors from textures
                    fixed4 main_color = tex2D(_MainTex, main_uv);
                    fixed4 secondary_color = tex2D(_SecondaryTex, secondary_uv);
                    fixed4 blend_color = tex2D(_BlendTex, blend_uv);
    
                    //take the red value of the color from the blend texture
                    fixed blend_value = blend_color.r;
    
                    //interpolate between the colors
                    fixed4 col = lerp(main_color, secondary_color, blend_value);
                    return col;
                }
    
                ENDCG
            }
        }
    }
    
    

    相关文章

      网友评论

          本文标题:Unity3D Shader教程九 Color Interpol

          本文链接:https://www.haomeiwen.com/subject/xjbzrctx.html