Unity Shader学习(九)物体边缘实现

根据前面的学习,我们了解到除了可以对点的颜色进行处理,还可以对点本身进行操作,例如我们可以改变点的位置,这样就可以实现对模型渲染的操控。物体边缘效果是我们常用的一种效果,要实现物体边缘,原理也很简单。
首先我们要了解到,模型在渲染时,有正面和背面之分,背面一般是不渲染,进行剔除,我们看到的模型往往是正常渲染正面,如下图所示:
在这里插入图片描述
了解到这,因此我们可以控制是否显示正面或者背面。进一步了解物体轮廓,物体轮廓其实就是物体在显示的屏幕上最外侧的边缘部分,因此要对模型最外部的边缘部分进行处理,如上图的边缘部分就是立方体的几条边,如下图所示,红色所在范围即为边缘部分。为了获取到边缘部分,需要将点转换到裁切空间进行处理。
在这里插入图片描述
关于裁剪空间,参考裁剪空间这篇文章
说明白点,裁剪空间就是摄像机视野范围内的一个矩阵转换空间,在该空间内可以进行点处理。首先,我们把边缘处理的流程分为两个pass,一个处理剔除正面的渲染,一个处理正面的正常渲染。
第一个pass:

 Pass
        {
    
    
            //剔除正面   只看背面
            Cull Front
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            float _Outline;
            float4 _OutlineColor;

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

            struct v2f
            {
    
    
                float4 pos : SV_POSITION;
            };

            v2f vert (appdata v)
            {
    
    
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex + normalize(v.vertex) * _Outline);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
    
    
                return _OutlineColor;
            }

            ENDCG
        }

使用UnityObjectToClipPos函数,可以将模型空间的点转换到裁剪空间,下面这行在原来点的基础上,乘以法线点和轮廓值,向外延伸,如下图所示。

 o.pos = UnityObjectToClipPos(v.vertex + normalize(v.vertex) * _Outline);

在这里插入图片描述
完成背面处理的pass后,进行正常的pass处理,不需要添加cull,默认渲染只正面,代码如下:

 Pass
        {
    
    
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            sampler2D _MainTex;

            struct appdata
            {
    
    
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
    
    
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
    
    
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
    
    
                return tex2D(_MainTex, i.uv);
            }
            ENDCG
        }

整体的效果如下:
在这里插入图片描述
完整code:

Shader "Custom/Study/Simple Outline"
{
    
    
    Properties
    {
    
    
        _MainTex ("Texture", 2D) = "white" {
    
    }

        _Outline ("Outline", Range(0, 1)) = 0.1
        _OutlineColor ("Outline Color", Color) = (1,1,1,1)
    }

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

        Pass
        {
    
    
            //剔除正面   只看背面
            Cull Front

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            float _Outline;
            float4 _OutlineColor;

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

            struct v2f
            {
    
    
                float4 pos : SV_POSITION;
            };

            v2f vert (appdata v)
            {
    
    
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex + normalize(v.vertex) * _Outline);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
    
    
                return _OutlineColor;
            }

            ENDCG
        }

        Pass
        {
    
    
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            sampler2D _MainTex;

            struct appdata
            {
    
    
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
    
    
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
    
    
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
    
    
                return tex2D(_MainTex, i.uv);
            }
            ENDCG
        }

    }
}

猜你喜欢

转载自blog.csdn.net/qq_14942529/article/details/126336885