美文网首页
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