其他分享
首页 > 其他分享> > Unity Shader入门学习(6):常用效果

Unity Shader入门学习(6):常用效果

作者:互联网

1.卡通渲染

//卡通渲染
//轮廓线渲染原理:渲染物体背面后向外拓展
//轮廓线弃用方案:根据视线与物体法线的夹角大小判断轮廓。理由:应用于正方体等规整物体上时效果极差
Shader "MyToon/Toon-Fragment" {
	Properties {
        _MainTex ("MainTex", 2D) = "white" {}
        _Ramp ("Ramp Texture", 2D) = "white" {}
        _Tooniness ("Tooniness", Range(0.1,20)) = 4
        _Outline ("Outline", Range(0,0.1)) = 0.01
    }

    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
		
		//下面是渲染背面的pass
        Pass {
        	Tags { "LightMode"="ForwardBase" }
        	
            Cull Front//剔除正面
    		Lighting Off
    		ZWrite On
 
            CGPROGRAM
            
            #pragma vertex vert
            #pragma fragment frag
            
            #pragma multi_compile_fwdbase
 
           	#include "UnityCG.cginc"
           	
            float _Outline;
 
            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            }; 
 
            struct v2f
            {
                float4 pos : POSITION;
            };
 
            v2f vert (a2v v)
            {
                v2f o;
 
                float4 pos = mul( UNITY_MATRIX_MV, v.vertex); //顶点位置从模型空间转换到观察空间(摄像机空间)
				float3 normal = mul(v.normal, (float3x3)UNITY_MATRIX_T_MV);//将法线(向量)从模型空间变换到观察空间。
				normal.z = -0.5;//Z方向的值扁平化(使其是一个较小的定值),防止喧宾夺主,挡住正面的渲染结果(不能关闭深度写入来解决)
				//将法线与顶点转到观察空间也是为了这一步的扁平化。否则不需要(根据法线与视线夹角的那个方法)

				pos = pos + float4(normalize(normal),0) * _Outline;//v.vertex沿着v.normal的方向扩展_Outline倍
				o.pos = mul(UNITY_MATRIX_P, pos);//把新的位置转换到投影坐标系中
				
                return o;
            }
 
            float4 frag(v2f i) : COLOR  
            { 
            	return float4(0, 0, 0, 1);           //将背面渲染成黑色就返回    
            } 
 
            ENDCG
        }
        
        Pass {
			Tags { "LightMode"="ForwardBase" }
			
			Cull Back 
			Lighting On
 
			CGPROGRAM
 
			#pragma vertex vert
			#pragma fragment frag
			
			#pragma multi_compile_fwdbase
 
			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			#include "UnityShaderVariables.cginc"

			sampler2D _MainTex;
			sampler2D _Ramp;
 
			float4 _MainTex_ST;
 
			float _Tooniness;
 
struct a2v {
				float4 vertex : POSITION;//语义POSITION指模型空间下的顶点位置
				float3 normal :NORMAL;//语义指模型空间下法线
				float4 texcoord:TEXCOORD0;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;// SV_POSITION指裁剪空间下定点位置
				float3 WorldNormal:TEXCOORD0;
				float3 WorldPos : TEXCOORD1;
				float2 uv:TEXCOORD2;//用于存储纹理坐标
			};

			v2f vert(a2v v) {
				v2f f;

				f.WorldNormal= UnityObjectToWorldNormal(v.normal);//法线世界化
				//f.WorldNormal = normalize(mul(unity_ObjectToWorld, v.normal));

				f.WorldPos = mul(unity_ObjectToWorld, v.vertex);//点坐标世界化
				//点坐标世界化,是方便通过世界坐标下的点作为一些内置函数的参数,获取光照方向,视线方向等

				f.pos = UnityObjectToClipPos(v.vertex);//点坐标片元化

				f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
				//f.uv=v.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw;
				//_MainTex_ST.xy对纹理进行缩放,_MainTex_ST.zw对纹理偏移

				return f;
			}
			
			float4 frag(v2f f) : COLOR  
			{ 

				fixed3 lightDir = normalize(UnityWorldSpaceLightDir(f.WorldPos));

				fixed3 worldNormal=normalize(f.WorldNormal);

				fixed3 albedo =tex2D(_MainTex,f.uv).rgb;
				albedo.rgb = (floor(albedo.rgb*_Tooniness)/_Tooniness);//合并颜色
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;	

				fixed halfLambert =dot( worldNormal,lightDir)*0.5+0.5;//半兰伯特
				fixed3 diffuseColor=tex2D(_Ramp,fixed2(halfLambert,halfLambert)).rgb;
				//让半兰伯特的取值范围映射在(0,1),用其数值构建一套纹理坐标,并用这套坐标对渐变纹理采样。
				fixed3 diffuse=diffuseColor*_LightColor0.rgb;

				return fixed4(ambient + diffuse , 1);
 
			} 
 
			ENDCG
		}

		Pass {
			Tags { "LightMode"="ForwardAdd" }
			
			Cull Back 
			Lighting On
			Blend One One
 
			CGPROGRAM
 
			#pragma vertex vert
			#pragma fragment frag
			
			#pragma multi_compile_fwdadd
 
			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			#include "UnityShaderVariables.cginc"
			
 
			sampler2D _MainTex;
			sampler2D _Ramp;
 
			float4 _MainTex_ST;
 
			float _Tooniness;
 
 			struct a2v
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 texcoord : TEXCOORD0;
				float4 tangent : TANGENT;
			}; 
 
			struct v2f
			{
				float4 pos : POSITION;
				float2 uv : TEXCOORD0;
				float3 normal : TEXCOORD1;
				half3 lightDir : TEXCOORD2;
				LIGHTING_COORDS(3,4)
			};
			
			v2f vert (a2v v)
			{
				v2f o;
 
				//Transform the vertex to projection space
				o.pos = UnityObjectToClipPos( v.vertex); 
				o.normal  = mul((float3x3)unity_ObjectToWorld, SCALED_NORMAL);
  				o.lightDir = WorldSpaceLightDir( v.vertex );
				//Get the UV coordinates
				o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);  
				
				// pass lighting information to pixel shader
  				TRANSFER_VERTEX_TO_FRAGMENT(o);
				return o;
			}
			
			float4 frag(v2f i) : COLOR  
			{ 
				//Get the color of the pixel from the texture
				float4 c = tex2D (_MainTex, i.uv);  
				//Merge the colours
				c.rgb = (floor(c.rgb*_Tooniness)/_Tooniness);
 
				//Based on the ambient light
 				float3 lightColor = float3(0,0,0);
 
				//Work out this distance of the light
				float atten = LIGHT_ATTENUATION(i);
				//Angle to the light
				float diff =  dot (normalize(i.normal), normalize(i.lightDir));  
				diff = diff * 0.5 + 0.5; 
				//Perform our toon light mapping 
				diff = tex2D(_Ramp, float2(diff, 0.5));
				//Update the colour
				lightColor += _LightColor0.rgb * (diff * atten); 
				//Product the final color
				c.rgb = lightColor * c.rgb * 2;
				return c; 
			} 
 
			ENDCG
		}
    }
    FallBack "Diffuse"	    
}

 

2.溶解

Shader "Unlit/Melt"
{
	Properties{
		_MainTex("Base(rgb)", 2D) = "white"{}
		_NoiseMap("NoiseMap", 2D) = "white"{}//噪声贴图
		_MeltThreshold("MeltThreshold", Range(0, 1)) = 0//烧毁闸值

		_EdgeLength("EdgeLength",Range(0, 0.3))=0.1

		_EdgeColorStart("EdgeColorStart", Color) = (1,1,1,1)
		_EdgeColorEnd("EdgeColorEnd", Color) = (0,0,0,0)
		//_Erode("Erode", Range(0.0, 1.0)) = 0.98
		//_ErodeThreshold("ErodeThreshold", Range(0.0, 1.0)) = 0.71
	}
 
 
	SubShader{
 
		CGINCLUDE
 
			#include "Lighting.cginc"
			#include "UnityCG.cginc"
			#include "AutoLight.cginc"
 
			sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _NoiseMap;
			float _MeltThreshold;//消融阈值

			float _EdgeLength;	

			//消融边缘起始颜色
			fixed4 _EdgeColorStart;
			//最终颜色
			fixed4 _EdgeColorEnd;
			控制侵蚀程度
			//float _Erode;
            //控制侵蚀颜色阈值
			//float _ErodeThreshold;
 
			struct a2v{
				float4 vertex : POSITION;
    			float3 normal : NORMAL;
    			float4 texcoord : TEXCOORD0;
			};
 
			struct v2f{
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
				float2 uv : TEXCOORD2;
				SHADOW_COORDS(3)
			};
 
			v2f vert(a2v v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
				TRANSFER_SHADOW(o);
				return o;
			}
 
			fixed4 frag(v2f i) : SV_Target{
 
				fixed3 melt = tex2D(_NoiseMap, i.uv).rgb;//melt意味溶解
				//使用噪声图采样
 
				clip(melt.r - _MeltThreshold);
				//采样阈值与设定阈值比较,小于设定的阈值就裁剪掉该片元
				//如何理解:clip函数相当于返回一个裁剪后的部分可见模型。而哪些地方裁剪哪些不,完全取决于噪声贴图(与主图共用uv)与闸值的比较

				//常规光照计算部分
				fixed3 albedo = tex2D(_MainTex, i.uv).rgb;
				fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
				fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, -worldLightDir));
				fixed3 lightColor = diffuse + ambient;

				//下面处理边缘的烧融部分
				float result =1- (melt.r - _MeltThreshold);
				//melt.r - _MeltThreshold得到了未被裁剪的剩余部分。即半透明中(半黑)更可见的部分
				//注意剩余部分对应的噪声贴图不均。(白色为1,黑色为0.介于之间为半透明)
				//1-剩余部分 即得到透明值(噪声图黑色含量值)。0为不透明,反之更透明。

				if(result > (1-_EdgeLength)){//1-_EdgeLength是不会出现烧融的部分,即“内陆”。
				//result 大于1-_EdgeLength的部分即为烧融边界

					fixed4 edgeColor=lerp(_EdgeColorStart,_EdgeColorEnd,(result-(1-_EdgeLength))/_EdgeLength);
					//result-(1-_EdgeLength))/_EdgeLength是将烧融部分规范到(0,1)
					//lerp(a,b,f):线性插值函数,返回值为(1-f)*a+b*f

					return edgeColor;
				}

				//直接返回光照后颜色
				return fixed4(lightColor, 1);
			}
 
		ENDCG
 
	//为了看见整个模型的消融过程,我选择关闭了剔除
		Pass{
 
			Tags{ "RenderType" = "Opaque"}
			Cull off
			CGPROGRAM
			
			#pragma vertex vert
			#pragma fragment frag
 
			ENDCG
		}
	}
 
	FallBack Off
}

 

3.透视

 

标签:MainTex,normal,vertex,Shader,Unity,rgb,v2f,float4,入门
来源: https://blog.csdn.net/ljylmly/article/details/121705393