钢铁侠材质制作——5、多种效果过渡的制作

钢铁侠Unlit光照Shader,三种效果变化

返回目录

在这里插入图片描述

大家好,我是阿赵。这里是钢铁侠材质制作的第五部分,多种效果过渡的制作。
通过了之前的步骤,我已经基本实现完了整个shader的效果,它包括了3部分的效果:
1、光线轮廓模型
在这里插入图片描述

2、固有色模型
在这里插入图片描述

3、添加完整光照模型的效果
在这里插入图片描述

接下来要做最后一步,通过一个值的控制,实现这三种效果的切换。
在这里插入图片描述

在这里插入图片描述

先整理一下之前的代码:

float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
				float NdotV = dot(i.worldNormal, worldViewDir);
				float fresnelVal = pow((1 - NdotV)*_RimBias, _RimPow);
				

				float2 noiseUV = i.worldPos.xy *_NoiseTiling.xy + _NoiseTiling.zw;
				noiseUV.y += frac(_Time.y)*_NoiseSpeed;
				float4 noiseCol = tex2D(_NoiseMap, noiseUV);
				//第一种效果,光线轮廓
				half4 RimLineRGBA = _RimlCol * (fresnelVal+noiseCol.r);
				
				half4 RimRGBA = _RimlCol * fresnelVal*_RimAddStength;
				
				//第二种效果,固有色
				half4 baseCol = tex2D(_MainTex,i.uv);

				half4 normalCol = tex2D(_NormalMap, i.uv);
				//得到切线空间的法线方向
				half3 normalVal = UnpackScaleNormal(normalCol, _NormalScale).rgb;

				//构建TBN矩阵
				float3 tanToWorld0 = float3(i.worldTangent.x, i.worldBitangent.x, i.worldNormal.x);
				float3 tanToWorld1 = float3(i.worldTangent.y, i.worldBitangent.y, i.worldNormal.y);
				float3 tanToWorld2 = float3(i.worldTangent.z, i.worldBitangent.z, i.worldNormal.z);

				//通过切线空间的法线方向和TBN矩阵,得出法线贴图代表的物体世界空间的法线方向
				float3 worldNormal = float3(dot(tanToWorld0, normalVal), dot(tanToWorld1, normalVal), dot(tanToWorld2, normalVal));


				

				float diffuseVal = GetHalfLambertDiffuse(i.worldPos, worldNormal);
				float4 specMaskVal = tex2D(_SpecMask, i.uv);
				float specVal = GetBlinnPhongSpec(i.worldPos, worldNormal, _Shininess)*specMaskVal.r*_SpecStength;
				float2 MatCapUV = GetMatCapUV(worldNormal);
				float4 MatCapCol = pow(tex2D(_MatCapTex, MatCapUV)*_MatCapStength*specMaskVal.g, _MatCapPow);
				//第三种效果,完整光照模型
				half3 modelRGB = UNITY_LIGHTMODEL_AMBIENT * _AmbientStength + baseCol.rgb*diffuseVal+ _SpecCol.rgb*specVal + MatCapCol+ RimRGBA.rgb;

可以看出,实际上三种效果都已经计算出来了,分别是:
1.RimLineRGBA
2.baseCol
3.modelRGB
所以直接插值就行。这里我使用了2个技巧:
1.要混合1和2需要一个插值,然后把1和2的结果混合3又要一个插值,本来应该是需要2个值的,但我不想这么做,我希望用一个0到1的值,在0到0.5的阶段,显示1和2的混合,然后在0.5到1的阶段,显示1和2 的结果与3的混合。
2.如果直接插值,过渡位置的效果要么会很硬,要么会很软,所以我加了一个smoothstep来控制过渡位置的范围。

这个混合的值我们决定是使用模型的高度来控制,所以我们需要先指定模型的高度,然后通过顶点坐标的y坐标减去模型脚底的坐标,求出实际的高度。根据这个要求,所以我们做模型的时候就有一个要求了,必须把模型的中心点定在模型的脚底下。
在这里插入图片描述

如果不这么做,就不能直接计算模型顶点坐标和原点在世界空间的差值作为高度,必须再定义多一个模型脚下的坐标,那样就有点麻烦了。
有了以上需要的数据之后,就可以计算插值了:

float3 centerPos = mul(unity_ObjectToWorld, float3(0,0,0));
				float offsetH = i.worldPos.y - centerPos.y;
				float h1 = saturate(_ShowHeigh * 2)*_ModelHeigh;
				h1 = h1 - offsetH;
				h1 = smoothstep(_ShowHeighMin, _ShowHeighMax, h1);
				h1 = clamp(h1, 0, 1);
				float h2 = saturate(_ShowHeigh * 2-1)*_ModelHeigh;
				h2 = h2 - offsetH;
				h2 = smoothstep(_ShowHeighMin, _ShowHeighMax, h2);
				h2 = clamp(h2, 0, 1);				
				float3 finalRGB = (RimLineRGBA * (1 - h1) + baseCol.rgb*h1)*(1-h2)+ modelRGB*h2;

最后得到的finalRGB,就是插值计算之后最终需要显示的颜色了。

完整Shader:

Shader "azhao/IronManBodyCode"
{
    Properties
    {
		_RimBias("RimBias", Float) = 1
		_RimPow("RimlPow", Float) = 2
		_RimlCol("RimCol", Color) = (0,0,0,0)
		_NoiseMap("NoiseMap",2D) = "black"{}
		_NoiseTiling("NoiseTiling",Vector) = (1,1,0,0)
		_NoiseSpeed("NoiseSpeed",float) = 0

		_AmbientStength("AmbientStength",float) = 1
		_MainTex("BaseCol",2D) = "white"{}
		_NormalMap("NormalMap",2D) = "black"{}
		_NormalScale("NormalScale",float) = 1
		_SpecCol("SpecCol",Color) = (1,1,1,1)
		_Shininess("_Shininess",float) = 1
		_SpecStength("SpecStength",float) = 1
		_SpecMask("SpecMask",2D) = "white"{}

		_MatCapTex("_MatCapTex",2D) = "black"{}
		_MatCapStength("MatCapStength",float) = 1
		_MatCapPow("MatCapPow",float) = 2
		_RimAddStength("RimAddStength",float) = 1

		_ModelHeigh("ModelHeigh",float) = 2
		_ShowHeigh("ShowHeigh",Range(0,1)) = 0

		_ShowHeighMin("ShowHeighMin",Range(0,1)) = 0
		_ShowHeighMax("ShowHeighMax",Range(0,1)) = 1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag


            #include "UnityCG.cginc"

			//简化版的转换法线并缩放的方法
			half3 UnpackScaleNormal(half4 packednormal, half bumpScale)
			{
				half3 normal;
				//由于法线贴图代表的颜色是0到1,而法线向量的范围是-1到1
				//所以通过*2-1,把色值范围转换到-1到1
				normal = packednormal * 2 - 1;
				//对法线进行缩放
				normal.xy *= bumpScale;
				//向量标准化
				normal = normalize(normal);
				return normal;
			}


			//获取HalfLambert漫反射值
			float GetHalfLambertDiffuse(float3 worldPos, float3 worldNormal)
			{
				float3 lightDir = UnityWorldSpaceLightDir(worldPos);
				float NDotL = saturate(dot(worldNormal, lightDir));
				float halfVal = NDotL * 0.5 + 0.5;
				return halfVal;
			}

			//获取BlinnPhong高光
			float GetBlinnPhongSpec(float3 worldPos, float3 worldNormal,float shininess)
			{
				float3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
				float3 halfDir = normalize((viewDir + _WorldSpaceLightPos0.xyz));
				float specDir = max(dot(normalize(worldNormal), halfDir),0);
				float specVal = pow(specDir, shininess);
				return specVal;
			}

			float2 GetMatCapUV(float3 normalWorld)
			{
				float3 normalView = mul(UNITY_MATRIX_IT_MV, normalWorld);
				return normalView.xy*0.5 + 0.5;
			}



            struct appdata
            {
                float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
				float3 normal : NORMAL;
				float4 tangent : TANGENT;

            };

            struct v2f
            {
                float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
				float3 worldPos :TEXCOORD1;
				float3 worldNormal : TEXCOORD2;
				float3 worldTangent :TEXCOORD3;
				float3 worldBitangent : TEXCOORD4;
				
            };

			float _RimBias;
			float _RimPow;
			float4 _RimlCol;
			sampler2D _NoiseMap;
			float4 _NoiseTiling;
			float _NoiseSpeed;

			sampler2D _MainTex;
			sampler2D _NormalMap;
			float _NormalScale;
			float _AmbientStength;
			float4 _SpecCol;
			float _Shininess;
			float _SpecStength;
			sampler2D _SpecMask;

			sampler2D _MatCapTex;
			float _MatCapStength;
			float _MatCapPow;
			float _RimAddStength;

			float _ModelHeigh;
			float _ShowHeigh;

			float _ShowHeighMin;
			float _ShowHeighMax;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldTangent = UnityObjectToWorldDir(v.tangent);
				o.worldBitangent = cross(o.worldNormal, o.worldTangent);
                return o;
            }

            half4 frag (v2f i) : SV_Target
            {

				float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
				float NdotV = dot(i.worldNormal, worldViewDir);
				float fresnelVal = pow((1 - NdotV)*_RimBias, _RimPow);
				

				float2 noiseUV = i.worldPos.xy *_NoiseTiling.xy + _NoiseTiling.zw;
				noiseUV.y += frac(_Time.y)*_NoiseSpeed;
				float4 noiseCol = tex2D(_NoiseMap, noiseUV);
				//第一种效果,光线轮廓
				half4 RimLineRGBA = _RimlCol * (fresnelVal+noiseCol.r);
				
				half4 RimRGBA = _RimlCol * fresnelVal*_RimAddStength;
				
				//第二种效果,固有色
				half4 baseCol = tex2D(_MainTex,i.uv);

				half4 normalCol = tex2D(_NormalMap, i.uv);
				//得到切线空间的法线方向
				half3 normalVal = UnpackScaleNormal(normalCol, _NormalScale).rgb;

				//构建TBN矩阵
				float3 tanToWorld0 = float3(i.worldTangent.x, i.worldBitangent.x, i.worldNormal.x);
				float3 tanToWorld1 = float3(i.worldTangent.y, i.worldBitangent.y, i.worldNormal.y);
				float3 tanToWorld2 = float3(i.worldTangent.z, i.worldBitangent.z, i.worldNormal.z);

				//通过切线空间的法线方向和TBN矩阵,得出法线贴图代表的物体世界空间的法线方向
				float3 worldNormal = float3(dot(tanToWorld0, normalVal), dot(tanToWorld1, normalVal), dot(tanToWorld2, normalVal));


				

				float diffuseVal = GetHalfLambertDiffuse(i.worldPos, worldNormal);
				float4 specMaskVal = tex2D(_SpecMask, i.uv);
				float specVal = GetBlinnPhongSpec(i.worldPos, worldNormal, _Shininess)*specMaskVal.r*_SpecStength;
				float2 MatCapUV = GetMatCapUV(worldNormal);
				float4 MatCapCol = pow(tex2D(_MatCapTex, MatCapUV)*_MatCapStength*specMaskVal.g, _MatCapPow);
				//第三种效果,完整光照模型
				half3 modelRGB = UNITY_LIGHTMODEL_AMBIENT * _AmbientStength + baseCol.rgb*diffuseVal+ _SpecCol.rgb*specVal + MatCapCol+ RimRGBA.rgb;

				float3 centerPos = mul(unity_ObjectToWorld, float3(0,0,0));
				float offsetH = i.worldPos.y - centerPos.y;
				float h1 = saturate(_ShowHeigh * 2)*_ModelHeigh;
				h1 = h1 - offsetH;
				h1 = smoothstep(_ShowHeighMin, _ShowHeighMax, h1);
				h1 = clamp(h1, 0, 1);
				float h2 = saturate(_ShowHeigh * 2-1)*_ModelHeigh;
				h2 = h2 - offsetH;
				h2 = smoothstep(_ShowHeighMin, _ShowHeighMax, h2);
				h2 = clamp(h2, 0, 1);				
				float3 finalRGB = (RimLineRGBA * (1 - h1) + baseCol.rgb*h1)*(1-h2)+ modelRGB*h2;
				return half4(finalRGB,1);
            }
            ENDCG
        }
    }
}

猜你喜欢

转载自blog.csdn.net/liweizhao/article/details/130032138