着色器实例 代码+注释 更新中【描边、卡通渲染、法线颜色、贴图动画等等】

描边着色器
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unlit/NewUnlitShader"
{
    Properties
    {
		//定义与unity通信的变量名
		_MainColor("Main Color", Color) = (0.5,0.5,0.5,1)
		_OutlineColor("Outline Color",Color) = (0,0,0,1)   //轮廓颜色
		_Outline("Outline width",Range(0.0,10)) = 0.005    //轮廓线宽度
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" }
        LOD 100

		//固定管线渲染器。背面剔除,并在深度缓冲区中留下背面剔除的深度值
        Pass{
			Name "BASE"
			//剔除背面
			Cull Back
			//保存缓冲区
			Blend Zero One

			SetTexture[_OutlineColor]
			{
				ConstantColor(1,0,0,0)
				Combine constant
			}
        }

		//顶点/片段着色器。正面剔除,那些经过法线伸展后的点会因为与深度剔除的缓存值比较后无法通过而被剔除
		//也就是说仅仅剩下正面与背面的边缘处因为伸展的原因保留了下来,  于是轮廓就出现了,这就是大体过程了
		Pass{
			Name"OUTLINE"
			Tags{"LightMode" = "Always"}
			Cull Front

			Blend One OneMinusDstColor

			//顶点片元着色器代码
			CGPROGRAM
				#pragma vertex vert 
				#pragma fragment frag 
				//引入unitycg库
				#include "UnityCG.cginc"
				
				//定义从应用到顶点着色器的数据,此处用于获取顶点位置信息和法线信息
				struct appdata{
					float4 vertex : POSITION;
					float3 normal : NORMAL;
				};
				
				//定义顶点着色器输出给片元着色器的数据,此处输出片元位置,及颜色
				struct v2f{
					float4 pos :POSITION;
					float4 color : COLOR;
				};

				uniform float _Outline;
				uniform float4 _OutlineColor;

				//顶点着色器程序块
				v2f vert(appdata v){
					v2f o;
					o.pos = UnityObjectToClipPos(v.vertex);

					float3 norm = mul((float3x3)UNITY_MATRIX_IT_MV,v.normal);
					float2 offset = TransformViewToProjection(norm.xy);

					o.pos.xy += offset * o.pos.z* _Outline;
					o.color = _OutlineColor;

					return o;
				}
				//片段着色器代码块
				half4 frag(v2f i) :COLOR{
					return i.color;
				}
			ENDCG
		}
    }
}
穿透描边
Shader "Custom/Catoon" {
	Properties{
		_MainTex("Base (RGB)", 2D) = "white" {}
		_OutlineColor("Outline Color", Color) = (1,1,0,1) //描边颜色
		_Outline("Outline width", Range(0.0, 0.5)) = 0.03 // 描边宽度
	}
	CGINCLUDE
		#include "UnityCG.cginc"
		//获取顶点、法线、纹理坐标
		struct appdata_t {
			float4 vertex : POSITION;
			float2 texcoord : TEXCOORD0;
			float3 normal : NORMAL;
		};
		//
		struct v2f {
			float4 vertex : SV_POSITION;
			half2 texcoord : TEXCOORD0;
		};

		sampler2D _MainTex;
		float4 _MainTex_ST;
		float _Outline;
		float4 _OutlineColor;

		v2f vert(appdata_t v)
		{
			v2f o;
			o.vertex = UnityObjectToClipPos(v.vertex);
			o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);

			return o;
		}

		v2f vert_outline(appdata_t v)
		{
			v2f o;
			// 方式一,观察空间 下往法线偏移顶点
			float4 viewPos = mul(UNITY_MATRIX_MV, v.vertex);
			//float3 viewNorm = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
			float3 viewNorm = mul(v.normal, (float3x3)UNITY_MATRIX_T_MV);
			float3 offset = normalize(viewNorm) * _Outline;
			viewPos.xyz += offset;
			o.vertex = mul(UNITY_MATRIX_P, viewPos);

			//方式二,世界空间 下往法线偏移顶点
			//float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
			//float3 worldNormal = UnityObjectToWorldNormal(v.normal);
			//float3 offset = normalize(worldNormal) * _Outline;
			//worldPos.xyz += offset;
			//o.vertex = mul(UNITY_MATRIX_VP, worldPos);
			return o;
		}
		ENDCG

		SubShader{
			Tags{ "Queue" = "Transparent" "RenderType" = "Opaque" }

			Pass{ // 正常绘制
					Stencil
					{
						Ref 1
						Comp Always
						Pass Replace
						ZFail Replace
					}

					ZTest LEqual
					CGPROGRAM
					#pragma vertex vert
					#pragma fragment frag

					fixed4 frag(v2f i) : SV_Target
					{
						fixed4 col = tex2D(_MainTex, i.texcoord);
						return col;
					}

					ENDCG
				}

				Pass{ // 遮挡部分绘制描边
					ZTest Greater
					ZWrite Off
						//Blend DstAlpha OneMinusDstAlpha

						Stencil{
							Ref 1
							Comp NotEqual

						}
						CGPROGRAM
						#pragma vertex vert_outline
						#pragma fragment frag
						half4 frag(v2f i) :COLOR
						{
							return _OutlineColor;
						}
						ENDCG
					}
		}
}
卡通渲染

Shader "Custom/Cartoon" {
	Properties{
		//主贴图
		_MainTex("MainTex",2D) = "white"{}
		//主颜色
		_Color("Color",Color) = (1,1,1,1)
		//漫反射色调纹理
		_RampTex("Ramp",2D) = "white"{}
		//描边宽度
		_Outline("Outline",Range(0,1)) = 0.1
		//描边颜色
		_OutlineColor("OutlineColor",Color) = (0,0,0,1)
		//高光反射颜色
		_Specular("SpecularColor",Color) = (1,1,1,1)
		//高光阈值
		_SpecularScale("Specular Scale",Range(0,0.1)) = 0.01
	}
		SubShader{
			//该段pass 的作用是描边
			Pass{
				NAME "OUTLINE"
				Cull Front
				CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
				#include "UnityCG.cginc"

				//定义与unity通信的变量
				fixed _Outline;
				fixed4 _OutlineColor;
				//定义应用到顶点阶段用的结构
				struct a2v {
					float4 vertex:POSITION;
					float3 normal:NORMAL;
				};
				//定义顶点到片元阶段用的结构
				struct v2f {
					float4 pos:SV_POSITION;
				};
				//定点找色器
				v2f vert(a2v v) {
					v2f o;
					//当前的模型观察矩阵,  用于将顶点/方向数据从模型空间变换到观察空间
					float4 pos = mul(UNITY_MATRIX_MV,v.vertex);
					//UNITY_MATRIX_MV的逆转置矩阵,用于将法线从模型空间变换到观察空间,也可以用于得到UNITY_MATRIX_MV的逆矩阵
					float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV,v.normal);
					normal.z = -0.5;
					pos = pos + float4(normalize(normal),0)*_Outline;

					o.pos = mul(UNITY_MATRIX_P,pos);
					return o;
				}

				fixed4 frag(v2f i) :SV_Target{
					return fixed4(_OutlineColor.rgb,1);
				}
				ENDCG
			}
			//该段作用时上色
			Pass{
				Tags{"LightMode" = "ForwardBase"}
				//裁剪后方
				Cull Back
				CGPROGRAM
					#pragma vertex   vert
					#pragma fragment  frag
					#pragma multi_compile_fwdbase
					#include "Lighting.cginc"
					#include "UnityCG.cginc"
					#include "AutoLight.cginc" 

					sampler2D _MainTex;
					float4 _MainTex_ST;
					fixed4 _Color;
					sampler2D _RampTex;
					fixed4 _Specular;
					fixed _SpecularScale;

					//应用到顶点着色器的数据
					struct a2v {
						//顶点位置,法线与贴图
						float4 vertex:POSITION;
						float3 normal:NORMAL;
						float2 texcoord:TEXCOORD0;
					};
					//顶点到片段着色器的数据
					struct v2f {
						//顶点信息、uv信息、世界坐标法线信息和世界坐标信息。
						float4 pos:SV_POSITION;
						float2 uv:TEXCOORD0;
						float3 worldNormal:TEXCOORD1;
						float3 worldPos:TEXCOORD2;
						SHADOW_COORDS(3)
					};
					//顶点着色器正文
					v2f vert(a2v v) {
						v2f o;

						//将模型坐标转换为裁剪坐标
						o.pos = UnityObjectToClipPos(v.vertex);
						o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
						o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);
						o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;

						TRANSFER_SHADOW(o);

						return o;
					}
					//片段着色器 指定输出为SV_Target
					fixed4 frag(v2f i) :SV_Target{
						//获取模型在世界空间的法线向量  计算与输入向量方向相同的单位向量
						fixed3 worldNormal = normalize(i.worldNormal);
						//仅用于向前渲染中,输入一个世界空间中的顶点位置, 返回世界空间中从该点到光源的光照方向。没有被归一化
						fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
						//输入一个世界空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向
						fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
						//计算与输入向量方向相同的单位向量
						fixed3 worldHalf = normalize(worldLightDir + worldViewDir);

						fixed4 c = tex2D(_MainTex,i.uv);
						fixed3 albedo = c.rgb*_Color.rgb;

						fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;

						UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);
						fixed diff = dot(worldNormal,worldLightDir);
						diff = (diff*0.5 + 0.5)*atten;

						fixed3 diffuse = _LightColor0.rgb*albedo*tex2D(_RampTex,float2(diff,diff)).rgb;

						fixed spec = dot(worldNormal,worldHalf);
						fixed w = fwidth(spec)*2.0;
						fixed3 specular = _Specular.rgb*lerp(0,1,smoothstep(-w,w,spec + _SpecularScale - 1))*step(0.0001,_SpecularScale);
						//最后添加的step(0.0001,_SpecularScale);是为了控制当Specular为0时,不出现高光效果

						return fixed4(ambient + diffuse + specular,1.0);
					}
				ENDCG
			}
		}
		FallBack "Diffuse"
		//这里的回调需要注意包含能够处理阴影的特殊Pass
}
外发光着色器
遮挡轮廓显示着色器
water 水着色器
火焰 fire着色器
沿x轴y轴方向移动贴图动画的 shader
Shader "Custom/ScrollSurfaceShader"
{
	Properties{
		//叠加颜色
		_Color("Color", Color) = (1,1,1,1)
		//指定贴图
		_MainTex("Albedo (RGB)", 2D) = "white" {}
		//光泽
		_Glossiness("Smoothness", Range(0,1)) = 0.5
		//金属度
		_Metallic("Metallic", Range(0,1)) = 0.0
		//x轴滚动
		_ScrollXSpeed("X Scroll Speed", Range(0, 10)) = 0.2
		//y轴滚动
		_ScrollYSpeed("Y Scroll Speed", Range(0, 10)) = 0.2
	}
		SubShader{
			Tags { "RenderType" = "Opaque" }
			LOD 200

			//没在pass中,因为时表面着色器
			CGPROGRAM

			//声明表面着色器
			#pragma surface surf Standard fullforwardshadows // Physically based Standard lighting model, and enable shadows on all light types
			#pragma target 3.0 // Use shader model 3.0 target, to get nicer looking lighting

			sampler2D _MainTex;
			//定义输入结构
			struct Input {
				float2 uv_MainTex;
			};

			half _Glossiness;
			half _Metallic;
			fixed4 _Color;
			fixed _ScrollXSpeed;
			fixed _ScrollYSpeed;

			//表面着色器正文 第一个参数为输入,第二个参数为输出
			void surf(Input IN, inout SurfaceOutputStandard o)
			{
				//输入的速度值 * 时间
				fixed2 scrollValue = fixed2(_ScrollXSpeed * _Time.y, _ScrollYSpeed * _Time.y);
				//uv = 当前的uv值+根据时间变动的值
				float2 scrolledUV = IN.uv_MainTex + scrollValue;
				//返回小数部分   这是i因为uv 的满值是1,要接受1以内的小数
				scrolledUV = frac(scrolledUV);
				//镜像播放
				//scrolledUV = sin(scrolledUV);

				// 设置主色,由贴图颜色 * color设置颜色
				fixed4 c = tex2D(_MainTex, scrolledUV) * _Color;
				o.Albedo = c.rgb;
				//金属
				o.Metallic = _Metallic;
				//平滑
				o.Smoothness = _Glossiness;
				//透明度
				o.Alpha = c.a;
			}
			ENDCG
		}
			//默认效果
			FallBack "Diffuse"
}
根据法线着色的着色器,某些创意小手游,使用该着色器
Shader "Custom/SurfaceShader"
{
	SubShader
	{
		Tags { "RenderType" = "Opaque" "ForceNoShadowCasting" = "True" "IgnoreProjector" = "True"}
		LOD 130

		Pass
		{
			//CG代码块
			CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
				//引入unityCG处理库
				#include "UnityCG.cginc"

				//定义一个数据结构,该结构包含一个4维向量,一个三维向量
				struct v2f
				{
					//获取位置
					float4 pos : SV_POSITION;
					//获取颜色
					float2 color : COLOR0;
				};
	
				//顶点程序代码,用于计算位置和颜色。   v2f是刚才新建的数据结构,vert是在cgprogram注册的用于顶点计算的程序名
				//该方法输入值appdata_base v是与模型关联后自动输入的       
				//该方法输入值appdata_base v是与模型关联后自动输入的,他的输出值会自动传入到片段代码块。所以相关联的顶点和片段方法的输出和输入类型一定要一致       
				v2f vert(appdata_base v)
				{
					//创建v2f数据 o
					v2f o;
					//计算位置
					o.pos = UnityObjectToClipPos(v.vertex);
					//计算颜色
					o.color = v.normal* 0.5 + 0.5;
					//返回该v2f数据
					return o;
				}
				//片段程序代码
				//该代码块会自动接受顶点着色器的输出值,而他的输出值会交给像素着色器最终显示在屏幕上
				half4 frag(v2f i) : COLOR
				{
					//返回输入的颜色,并设置透明度为1
					return half4(i.color,0.5,0.1);
				}
			ENDCG
		}
	}
	Fallback "VertexLit"
}
调整贴图的 亮度、对比度、饱和度
Shader "Custom/duibidu"
{
	Properties
	{
		_MainTex("Albedo (RGB)", 2D) = "white" {}
		_Brightness("Brightness", Float) = 1    //调整亮度
		_Saturation("Saturation", Float) = 1    //调整饱和度
		_Contrast("Contrast", Float) = 1        //调整对比度
	}
		SubShader
		{
			Pass
				{
			ZTest Always
			Cull Off
			ZWrite Off
			Blend SrcAlpha OneMinusSrcAlpha
			CGPROGRAM
			sampler2D _MainTex;
			half _Brightness;
			half _Saturation;
			half _Contrast;

			//vert和frag函数
			#pragma vertex vert
			#pragma fragment frag
			#include "Lighting.cginc"


			struct appdata_t
			{
				float4 vertex : POSITION;
				half4 color : COLOR;
				float2 texcoord : TEXCOORD0;
			};
			//从vertex shader传入pixel shader的参数
			struct v2f
			{
				float4 pos : SV_POSITION; //顶点位置
				half2  uv : TEXCOORD0;    //UV坐标
				half4 color : COLOR;
			};

			//vertex shader
			v2f vert(appdata_t v)
			{
				v2f o;
				//从自身空间转向投影空间
				o.pos = UnityObjectToClipPos(v.vertex);
				o.color = v.color;
				//uv坐标赋值给output
				o.uv = v.texcoord;
				return o;
			}

			//fragment shader
			fixed4 frag(v2f i) : COLOR
			{
				//从_MainTex中根据uv坐标进行采样
				fixed4 renderTex = tex2D(_MainTex, i.uv)*i.color;
				//brigtness亮度直接乘以一个系数,也就是RGB整体缩放,调整亮度
				fixed3 finalColor = renderTex * _Brightness;
				//saturation饱和度:首先根据公式计算同等亮度情况下饱和度最低的值:
				fixed gray = 0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b;
				fixed3 grayColor = fixed3(gray, gray, gray);
				//根据Saturation在饱和度最低的图像和原图之间差值
				finalColor = lerp(grayColor, finalColor, _Saturation);
				//contrast对比度:首先计算对比度最低的值
				fixed3 avgColor = fixed3(0.5, 0.5, 0.5);
				//根据Contrast在对比度最低的图像和原图之间差值
				finalColor = lerp(avgColor, finalColor, _Contrast);
				//返回结果,alpha通道不变
				return fixed4(finalColor, renderTex.a);
			}
			ENDCG
}
		}
			//防止shader失效的保障措施
			FallBack Off
}

溶解效果

Shader"Alphatest"
{
  Properties
  {
    _MainTex("Base(RGB)",2D)="white"{}
    _Cutoff("Value",Range(0,1))=0.5
  }

  SubShader
  {
    CGPROGRAM
    #pragma surface surf Lambert alphatest:_Cutoff//(1)

    sampler2D _MainTex;

    struct Input
    {
      float2 uv_MainTex;
    };

    void surf (Input IN,inout SurfaceOutput o)
    {
      half4 c =tex2D(_MainTex,IN.uv_MainTex);
      o.Albedo=c.rgb;
      o.Alpha = c.r;//(2)
    }
    ENDCG
  }
  FallBack"Diffuse"
}

替换颜色的着色器
Shader "Custom/MiniMap_s_new"
{
    Properties
    {
        //当然就是材质啦
        _MainTex ("Texture", 2D) = "white" {}
        //要被替换的目标颜色
        _TargetColor ("Target Color", Color) = (1, 1, 1, 1) 
        //要被替换的颜色范围
        _TargetRange ("Target Color Range", Range(0, 1)) = 0.01
        //替换成什么颜色
        _ReplaceColor ("Replace Color", Color) = (1, 1, 1, 1) 
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            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;
            }

            sampler2D _MainTex;
            fixed4 _TargetColor;
            fixed _TargetRange;
            fixed4 _ReplaceColor;

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                //替换颜色
                 _TargetColor = _TargetColor + _TargetRange;
                if(col.r < abs(_TargetColor.r) && col.g < abs(_TargetColor.g) && col.b < abs(_TargetColor.b)){
                    col = _ReplaceColor;
                    //如果透明度小于等于0.就不显示
                    if(col.a <= 0){
                        discard;
                    }
                }
                return col;
            }
            ENDCG
        }
    }
}

参考文章
https://blog.csdn.net/qq_38572472/article/category/7364961 这个老兄的十篇shader入门文章写的都很好,帮推一下。
https://blog.csdn.net/sdqq1234/article/details/61437045

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
边 Shader 一般是通过将物体的轮廓线提取出来,然后在轮廓线周围绘制一层边缘线,从而实现边的效果。对于法线外拓的边 Shader,一般是通过向模型表面法线方向推进一定的距离,然后在推进后的表面上绘制边缘线。 下面是一个简单的法线外拓边 Shader 的实现示例: 首先,在 Vertex Shader 需要计算出顶点在表面上被推进后的位置。这里可以通过将顶点沿着法线方向推进一定的距离来实现。具体的计算方法如下: ```glsl varying vec3 vNormal; void main() { // 计算法线 vNormal = normalize(normalMatrix * normal); // 将顶点沿法线方向推进一定距离 float offset = 0.1; vec3 newPosition = position + vNormal * offset; // 转换为世界坐标系 gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0); } ``` 注意这里的 `normalMatrix` 是将世界坐标系法线转换到了视图坐标系,这样才能保证法线方向是正确的。 然后,在 Fragment Shader 需要根据深度和法线信息来确定哪些像素是边缘像素。这里可以通过计算相邻像素深度差和法线差来判断当前像素是否处于轮廓线上。具体的计算方法如下: ```glsl uniform float edgeWidth; varying vec3 vNormal; void main() { // 计算相邻像素深度差和法线差 float depth1 = texture2D(depthTexture, gl_FragCoord.xy / screenSize).r; float depth2 = texture2D(depthTexture, gl_FragCoord.xy + vec2(1.0, 0.0) / screenSize).r; float depthDiff = abs(depth2 - depth1); vec3 normal1 = vNormal; vec3 normal2 = normalize(texture2D(normalTexture, gl_FragCoord.xy + vec2(1.0, 0.0) / screenSize).xyz * 2.0 - 1.0); float normalDiff = dot(normal1, normal2); // 如果深度差和法线差都超过了一定的阈值,则当前像素为边缘像素 if (depthDiff > edgeWidth && normalDiff < 0.5) { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); } else { discard; } } ``` 注意这里的 `depthTexture` 和 `normalTexture` 分别是渲染到纹理的深度和法线信息,需要在使用 Shader 前先渲染一遍到纹理。 最后,将推进后的表面和边合并即可得到最终的法线外拓边效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

千年奇葩

从来没受过打赏,这玩意好吃吗?

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

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

打赏作者

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

抵扣说明:

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

余额充值