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

本文介绍如何在Unity中实现模型的轮廓效果。通过控制模型的正面和背面渲染,并利用UnityObjectToClipPos函数将顶点坐标转换到裁剪空间,从而突出模型边缘。文章详细展示了两个渲染通道的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

    }
}
要在Unity中创建一个简单的边缘高亮材质shader,你可以使用顶点颜色来实现。下面是一个基本的高光边缘着色器的片段部分,假设你已经有了一个正常的颜色通道(diffuseColor): ```glsl Shader "Custom/EdgeHighlight" { Properties { _BaseColor ("Base Color", Color) = (1,1,1,1) _EmissiveColor ("Edge Emissive", Color) = (1, 1, 1, 1) _EdgeIntensity ("Edge Intensity", Range(0, 1)) = 0.5 } SubShader { Tags {"RenderType"="Opaque"} LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag struct appdata { float4 vertex : POSITION; float4 diffuseColor : COLOR; }; struct v2f { float4 vertex : SV_POSITION; float4 color : COLOR; float2 edgeUV : TEXCOORD0; // 使用纹理坐标来表示边缘 }; sampler2D _MainTex; fixed4 _BaseColor; fixed4 _EmissiveColor; float _EdgeIntensity; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.color = lerp(_BaseColor, _EmissiveColor * _EdgeIntensity, v.diffuseColor.r); // 利用红通道作为边缘检测信号 o.edgeUV = v.vertex.xy; // 纹理坐标不变 return o; } fixed4 frag (v2f i) : SV_Target { // 这里可以根据i.edgeUV计算边缘,并添加额外的亮度或颜色效果 // 示例:float edgeDetect = smoothstep(0.9, 1.1, i.edgeUV.x); // 边缘检测 return i.color; } ENDCG } } FallBack "Diffuse" } // 使用此shader实例化游戏对象 { MeshFilter { SharedMesh = "YourMeshName" } MeshRenderer { Material = "_Main" } } ``` 这个shader会在物体表面的边缘位置添加一个高亮层,边缘强度由红通道的值控制。你可以根据实际需求调整边缘检测算法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ToDoNothing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值