unity3d shader缔造金属各向异性效果

各向异性有两种类型,先截个图看看效果
一种是 径向各向异性



一种是 线性各向异性




这个shader就类似金属拉丝或者头发上的高光。(线性各向异性)
它能基于法线贴图的蓝色通道混合各向异性与粗糙程度。
支持漫反射(diffuse)、法线(normal)、反射(specular)、光泽贴图(gloss)和透明(transparency)着色器

光泽与反射值也应用于各向异性高光。
高光能增大或减小表面的各向异性高光的偏移值(Offset)。
各向异性高光表面的方向是被一个像下面的方向贴图定义的。
和切线空间的法线贴图效果相同,在表面定义高光。然而他们不应该在unity中转换法线贴图。
也就是这些图不用再转化成法线贴图了(我是这么理解的)。


成员:
各向异性的方向:就是表面高光的方向,和法线贴图的切线空间方向相同。
反射:反射强度是贴图的红色通道定义的。控制了反射高光的亮度。
光泽:光泽强度是贴图的绿色通道定义的。绿色越多反射高光越细越锐利,绿色越少反射高光越宽越模糊。最好把这个值设为一个非零值。
各向异性遮罩:贴图的蓝色通道定义各向异性与blinn高光的混合,蓝色越多各向异性比重越大,蓝色越少blinn比重越大。
各向异性的偏移:能使各向异性离中心点远或近




以下是本次shader需要的贴图:
径向各向异性效果:



线性各向异性效果:




建立一个shader:

先浏览一下变量:

_SpecularColor      高光颜色
_SpecPower           高光强度    
_Specular               高光各向异性的数目        
_AnisoDir               各向异性方向贴图   
_AnisoOffset          各向异性的偏移


	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_MainTint ("Diffuse Tint", Color) = (1,1,1,1)
		_SpecularColor ("Specular Color", Color) = (1,1,1,1)//高光颜色
		_SpecPower ("Specular Power", Range(0,30)) = 2//高光强度
		_Specular ("Specular Amount", Range(0, 1)) = 0.5
		_AnisoDir ("Anisotropic Direction", 2D) = ""{}//各向异性方向法线贴图
		_AnisoOffset("Anisotropic Offset", Range(-1,1)) = -0.2//_AnisoOffset的作用偏移
	}


让着色器加载我们定义的新的函数不是以前的Lambert
#pragma surface surf Anisotropic

告诉使用shader model3.0的渲染模式
#pragma target 3.0


建立一个新的结构体SurfaceAnisoOutput 传值用
Albedo                 对光源的反射率
Normal                 法线方向
Emission             自发光
AnisoDirection   各向异性方向
Specular              高光反射中的指数部分的系数
Gloss                   高光反射中的强度系数
Alpha                   透明度

		struct SurfaceAnisoOutput
		{
			fixed3 Albedo;//对光源的反射率
			fixed3 Normal;//法线方向
			fixed3 Emission;//自发光
			fixed3 AnisoDirection;//各向异性方向
			half Specular;//高光反射中的指数部分的系数
			fixed Gloss;//高光反射中的强度系数
			fixed Alpha;//透明度
		};


重要的执行函数 LightingAnisotropic

先求出半角向量halfVector
再求法线方向与光照方向的点积NdotL
半角向量与各向异性方向点积HdotA
求出各向异性:
sin((半角向量与各向异性方向点积+偏移值)的弧度值 * 180)
再根据各向异性求出反光强度spec
最后与光照颜色等进行整合

		inline fixed4 LightingAnisotropic (SurfaceAnisoOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
		{
			fixed3 halfVector = normalize(normalize(lightDir) + normalize(viewDir));//normalize()函数把向量转化成单位向量

			float NdotL = saturate(dot(s.Normal, lightDir));

			fixed HdotA = dot(normalize(s.Normal + s.AnisoDirection), halfVector);
			float aniso = max(0, sin(radians((HdotA + _AnisoOffset) * 180f)));//radians()函数将角度值转换为弧度值 

			float spec = saturate(pow(aniso, s.Gloss * 128) * s.Specular);//saturate(x)函数	如果x小于0返回 0;如果x大于1返回1;否则返回x;把x限制在0-1


			fixed4 c;
			c.rgb = ((s.Albedo * _LightColor0.rgb * NdotL) + (_LightColor0.rgb * _SpecularColor.rgb * spec)) * (atten * 2);
			c.a = 1.0;
			return c;

		}



在surf函数中接受各向异性法线贴图
转化为输出的各向异性方向
然后就ok了


<span style="font-size:14px;">		void surf (Input IN, inout SurfaceAnisoOutput o) {
			half4 c = tex2D (_MainTex, IN.uv_MainTex) * _MainTint;
			float3 anisoTex = UnpackNormal(tex2D(_AnisoDir, IN.uv_AnisoDir));

			o.AnisoDirection = anisoTex;
			o.Specular = _Specular;
			o.Gloss = _SpecPower;
			o.Albedo = c.rgb;
			o.Alpha = c.a;

		}</span>


这是径向的效果:






这是线性的效果:








全部代码如下:

Shader "Custom/textShader" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_MainTint ("Diffuse Tint", Color) = (1,1,1,1)
		_SpecularColor ("Specular Color", Color) = (1,1,1,1)//高光颜色
		_SpecPower ("Specular Power", Range(0,30)) = 2//高光强度
		_Specular ("Specular Amount", Range(0, 1)) = 0.5
		_AnisoDir ("Anisotropic Direction", 2D) = ""{}//各向异性方向法线贴图
		_AnisoOffset("Anisotropic Offset", Range(-1,1)) = -0.2//_AnisoOffset的作用偏移
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200

			CGPROGRAM
#pragma surface surf Anisotropic
#pragma target 3.0

			sampler2D _MainTex;
		sampler2D _AnisoDir;//各向异性的
		float4 _MainTint;
		float4 _SpecularColor;
		float _AnisoOffset;
		float _Specular;
		float _SpecPower;
		struct SurfaceAnisoOutput
		{
			fixed3 Albedo;//对光源的反射率
			fixed3 Normal;//法线方向
			fixed3 Emission;//自发光
			fixed3 AnisoDirection;//各向异性方向
			half Specular;//高光反射中的指数部分的系数
			fixed Gloss;//高光反射中的强度系数
			fixed Alpha;//透明度
		};


		inline fixed4 LightingAnisotropic (SurfaceAnisoOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
		{
			fixed3 halfVector = normalize(normalize(lightDir) + normalize(viewDir));//normalize()函数把向量转化成单位向量

			float NdotL = saturate(dot(s.Normal, lightDir));

			fixed HdotA = dot(normalize(s.Normal + s.AnisoDirection), halfVector);
			float aniso = max(0, sin(radians((HdotA + _AnisoOffset) * 180f)));//radians()函数将角度值转换为弧度值 

			float spec = saturate(pow(aniso, s.Gloss * 128) * s.Specular);//saturate(x)函数	如果x小于0返回 0;如果x大于1返回1;否则返回x;把x限制在0-1


			fixed4 c;
			c.rgb = ((s.Albedo * _LightColor0.rgb * NdotL) + (_LightColor0.rgb * _SpecularColor.rgb * spec)) * (atten * 2);
			c.a = 1.0;
			return c;

		}

		struct Input {
			float2 uv_MainTex;
			float2 uv_AnisoDir;
		};

		void surf (Input IN, inout SurfaceAnisoOutput o) {
			half4 c = tex2D (_MainTex, IN.uv_MainTex) * _MainTint;
			float3 anisoTex = UnpackNormal(tex2D(_AnisoDir, IN.uv_AnisoDir));

			o.AnisoDirection = anisoTex;
			o.Specular = _Specular;
			o.Gloss = _SpecPower;
			o.Albedo = c.rgb;
			o.Alpha = c.a;

		}
		ENDCG
	} 
	FallBack "Diffuse"
}


                                                                                                                  




                                                                                                               ---------  by wolf96

头发各向异性渲染Shader 这个是04年的一个ppt,主要介绍了头发的渲染,其追到源头还是要看这个原理。 各向异性的主要计算公式: 主要代码如下: 切线混合扰动部分(这部分也可以用T+k*N,来对切线进行扰动): float3x3 tangentTransform = float3x3(i.tangentDir, i.bitangentDir, i.normalDir); float3 _T_var = UnpackNormal(tex2D(_Tangent, TRANSFORM_TEX(i.uv0, _Tangent))); float3 temp = lerp(_TangentParam.xyz, _T_var, _BlenfTangent); float3 T = normalize(mul(float3(temp.xy,0), tangentTransform)); 主要是通过改变切线的xy值来造成头发高光部分的多样性。 高光部分,按公式计算即可: float StrandSpecular(float3 T, float3 V, float3 L, float exponent) { float3 H = normalize(L + V); float dotTH = dot(T, H); float sinTH = sqrt(1 - dotTH*dotTH); float dirAtten = smoothstep(-1, 0, dotTH); return dirAtten*pow(sinTH, exponent); } 注意,为了模拟的更贴近真实性,应用两层高光,第一层高光代表直射光直接反射出去,第二层代表次表面散射现象具体看代码。 最终渲染部分: float4 HairLighting(float3 T, float3 N, float3 L, float3 V, float2 uv, float3 lightColor) { float diffuse = saturate(lerp(0.25, 1.0, dot(N, L)))*lightColor; float3 indirectDiffuse = float3(0, 0, 0); indirectDiffuse += UNITY_LIGHTMODEL_AMBIENT.rgb; // Ambient Light float3 H = normalize(L + V); float LdotH = saturate(dot(L, H)); float3 specular = _Specular*StrandSpecular(T, V, L, exp2(lerp(1, 11, _Gloss))); //float specMask = tex2D(_SpecMask, TRANSFORM_TEX(uv, _SpecMask)); specular += /*specMask*/_SubColor*StrandSpecular(T, V, L, exp2(lerp(1, 11, _ScatterFactor))); float4 final; float4 base = tex2D(_MainTex, TRANSFORM_TEX(uv, _MainTex)); float3 diffuseColor = (_Color.rgb*base.rgb); //float ao = tex2D(_AO, TRANSFORM_TEX(uv, _AO)).g; final.rgb = (diffuse + indirectDiffuse)*diffuseColor + specular*lightColor* FresnelTerm(_Specular, LdotH); //final.rgb *= ao; final.a = base.a; clip(final.a - _CutOff); return final; } 这里我注释掉了AO和高光遮罩,需要的同学可以加上。 最后一点为了不让头发的边经过clip之后太硬,需要进行两个通道的belnd。 第二个pass使用以下指令: Blend SrcAlpha OneMinusSrcAlpha ZWrite Off 注意第二个通道无需再进行clip操作。 至此,头发渲染完毕。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值