BlueRoseNote/07-Other/Unity/《UnityShader入门》NPR部分学习.md
2023-06-29 11:55:02 +08:00

5.3 KiB
Raw Blame History

ToonShader

书中案例使用了2个Pass来实现效果。

OutlinePass

模型外面边

Pass {
		NAME "OUTLINE"
		
		Cull Front
		
		CGPROGRAM
		
		#pragma vertex vert
		#pragma fragment frag
		
		#include "UnityCG.cginc"
		
		float _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); 
			//IT_MV rotates normals from object to eye space
			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;
		}
		
		float4 frag(v2f i) : SV_Target { 
			return float4(_OutlineColor.rgb, 1);               
		}
		
		ENDCG
	}

ToonShader

颜色计算: Ramp颜色=tex2D(_Ramp, float2(dot(worldNormal, worldLightDir))).rgb diffuse=贴图颜色*指定颜色*灯光颜色*(Ramp贴图)

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 =  ;
diff = (diff * 0.5 + 0.5) * atten;

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

高光计算: 使用fwidth与smooth主要是用于抗锯齿。https://blog.csdn.net/candycat1992/article/details/44673819

fixed spec = dot(worldNormal, worldHalfDir);
fixed w = fwidth(spec) * 2.0;
fixed3 specular = _Specular.rgb * lerp(0, 1, smoothstep(-w, w, spec + _SpecularScale - 1)) * step(0.0001, _SpecularScale);

Pass代码

Pass {
		Tags { "LightMode"="ForwardBase" }
		
		Cull Back
	
		CGPROGRAM
	
		#pragma vertex vert
		#pragma fragment frag
		
		#pragma multi_compile_fwdbase
	
		#include "UnityCG.cginc"
		#include "Lighting.cginc"
		#include "AutoLight.cginc"
		#include "UnityShaderVariables.cginc"
		
		fixed4 _Color;
		sampler2D _MainTex;
		float4 _MainTex_ST;
		sampler2D _Ramp;
		fixed4 _Specular;
		fixed _SpecularScale;
	
		struct a2v {
			float4 vertex : POSITION;
			float3 normal : NORMAL;
			float4 texcoord : TEXCOORD0;
			float4 tangent : TANGENT;
		}; 
	
		struct v2f {
			float4 pos : POSITION;
			float2 uv : TEXCOORD0;
			float3 worldNormal : TEXCOORD1;
			float3 worldPos : TEXCOORD2;
			SHADOW_COORDS(3)
		};
		
		v2f vert (a2v v) {
			v2f o;
			
			o.pos = mul( UNITY_MATRIX_MVP, v.vertex);
			o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
			o.worldNormal  = UnityObjectToWorldNormal(v.normal);
			o.worldPos = mul(_Object2World, v.vertex).xyz;
			
			TRANSFER_SHADOW(o);
			
			return o;
		}
		
		float4 frag(v2f i) : SV_Target { 
			fixed3 worldNormal = normalize(i.worldNormal);
			fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
			fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
			fixed3 worldHalfDir = 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(_Ramp, float2(diff, diff)).rgb;
			
			fixed spec = dot(worldNormal, worldHalfDir);
			fixed w = fwidth(spec) * 2.0;
			fixed3 specular = _Specular.rgb * lerp(0, 1, smoothstep(-w, w, spec + _SpecularScale - 1)) * step(0.0001, _SpecularScale);
			
			return fixed4(ambient + diffuse + specular, 1.0);
		}
	
		ENDCG
	}

素描风格

通过hatchFactor=max(0,dot(worldLightDir,worldNormal))*7获取因子。之后计算各个图层的混合因子:

if (hatchFactor > 6.0) {
	// Pure white, do nothing
} else if (hatchFactor > 5.0) {
	o.hatchWeights0.x = hatchFactor - 5.0;
} else if (hatchFactor > 4.0) {
	o.hatchWeights0.x = hatchFactor - 4.0;
	o.hatchWeights0.y = 1.0 - o.hatchWeights0.x;
} else if (hatchFactor > 3.0) {
	o.hatchWeights0.y = hatchFactor - 3.0;
	o.hatchWeights0.z = 1.0 - o.hatchWeights0.y;
} else if (hatchFactor > 2.0) {
	o.hatchWeights0.z = hatchFactor - 2.0;
	o.hatchWeights1.x = 1.0 - o.hatchWeights0.z;
} else if (hatchFactor > 1.0) {
	o.hatchWeights1.x = hatchFactor - 1.0;
	o.hatchWeights1.y = 1.0 - o.hatchWeights1.x;
} else {
	o.hatchWeights1.y = hatchFactor;
	o.hatchWeights1.z = 1.0 - o.hatchWeights1.y;
}

之后在片元着色器中将因子与6张素描贴图的采样结果相乘以及计算白色区域光照最后相加

fixed4 hatchTex0 = tex2D(_Hatch0, i.uv) * i.hatchWeights0.x;
fixed4 hatchTex1 = tex2D(_Hatch1, i.uv) * i.hatchWeights0.y;
fixed4 hatchTex2 = tex2D(_Hatch2, i.uv) * i.hatchWeights0.z;
fixed4 hatchTex3 = tex2D(_Hatch3, i.uv) * i.hatchWeights1.x;
fixed4 hatchTex4 = tex2D(_Hatch4, i.uv) * i.hatchWeights1.y;
fixed4 hatchTex5 = tex2D(_Hatch5, i.uv) * i.hatchWeights1.z;
fixed4 whiteColor = fixed4(1, 1, 1, 1) * (1 - i.hatchWeights0.x - i.hatchWeights0.y - i.hatchWeights0.z - 
			i.hatchWeights1.x - i.hatchWeights1.y - i.hatchWeights1.z);

fixed4 hatchColor = hatchTex0 + hatchTex1 + hatchTex2 + hatchTex3 + hatchTex4 + hatchTex5 + whiteColor;

UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
				
return fixed4(hatchColor.rgb * _Color.rgb * atten, 1.0);