从0开始的技美实战(十)

本篇主要用于记录自己的实战操作,以及一些碎碎念(观后感),如果有什么好想法或者本篇出现什么错误,请多指教~

本篇的内容参考视频:庄懂的技术美术入门课(美术向)
使用软件:Unity 2019 3.6f1 ,ShaderForge

本篇内容主要包括:dota2食人魔的shader

上一期视频里留下来的是搞这么一个实战作业,然后花了一天时间根据给的官方文档提示做出效果如下,关于金属那张mask贴图的相关说明是属实没看懂要怎样配合其他的图去实现,为了看起来还行就直接让它和菲涅尔相乘去了,然后稍微还尝试了下自己写的库文件封装了一个法线贴图的处理以及兰伯特,Phong还有菲涅尔的运算,结果为了取遮罩,运算Phong的函数还没用上…
从0开始的技美实战(十)


1.相关的一些问题答疑
从0开始的技美实战(十)

2.分析与制作

从0开始的技美实战(十)

我自己在做的时候没有用到几个渐变图和Cubemap,就是简单的兰伯特加Phong加菲涅尔,然后根据文档对应位置使用lerp节点做遮罩处理;

从0开始的技美实战(十)因为这里我自己用的老师的资源,所以就没整合这一步…
从0开始的技美实战(十)根据图上应该明白金属度贴图应该与漫反射处理,而不是菲涅尔,这里的CubeMap我的考虑是如果放在游戏里的话,那一点反射应该是不容易看到的,所以就没加以减少消耗;

  • 按道理说金属度和自发光应是可选项,应该做个开关来控制,但没学到先略过
  • 关于Diffuse和BaseColor,两者有区别,非金属部分无区别,金属部分,Diffuse更黑,BaseColor则还是亮的
  • 关于颜色部分根据金属度做lerp,按PBR理论应该高光部分也用金属度做lerp但是没有为了加点人为主观因素,所以用了一个SpecTint去lerp;
  • 主光漫反射用Ramptexture进行处理;

关于透贴
从0开始的技美实战(十)从0开始的技美实战(十)
从0开始的技美实战(十)

最后效果和代码
从0开始的技美实战(十)

Shader "Unlit/dota2"
{
    Properties
    {
        _MainTex ("RGB:颜色 A:透贴", 2d)                               = "white"{}
        _MaskTex ("R:高光强度 G:边缘光强度 B:高光染色 A:高光次幂", 2d) = "black"{}
[Normal]_NormTex ("RGB:法线贴图", 2d)                                  = "bump"{}
        _MatelnessMask ("金属度遮罩", 2d)                              = "black"{}
        _EmissionMask ("自发光遮罩", 2d)                               = "black"{}
        _DiffWarpTex ("颜色Warp图", 2d)                                = "gray"{}
        _FresWarpTex ("菲涅尔Warp图", 2d)                              = "gray"{}
        _Cubemap ("环境球", cube)                                      = "_Skybox"{}
        _LightCol ("光颜色", color)                                    = (1.0, 1.0, 1.0, 1.0)
	    _SpecPow ("高光次幂", range(0.0, 90.0))                        = 5
        _SpecInt ("高光强度", range(0.0, 10.0))                        = 5
	    _EnvCol ("环境光颜色", color)                                  = (1.0, 1.0, 1.0, 1.0)
        _EnvDiffInt ("环境漫反射强度", range(0.0, 20.0))                = 0.5
	    _EnvSpecInt ("环境镜面反射强度", range(0.0, 10.0))             = 0.5
	    _RimCol ("轮廓光颜色", color)                                  = (1.0, 1.0, 1.0, 1.0)
        _RimInt ("轮廓光强度", range(0.0, 3.0))                        = 1.0
	    _EmitInt ("自发光强度", range(0.0, 10.0))                      = 1.0
[HideInInspector]_Cutoff ("Alpha cutoff", Range(0,1))                  = 0.5//必须叫这个
[HideInInspector]_Color ("Main Color", Color)                          = (1,1,1,1)
	}

    SubShader{
        Tags {"RenderType"="Opaque"}
          Pass {
           Tags {"LightMode"="ForwardBase"}

		   Cull Off  //开启双面显示
           CGPROGRAM
		   
           #pragma vertex vert
           #pragma fragment frag
           #include "UnityCG.cginc"
           #include "AutoLight.cginc"
           #include "Lighting.cginc"
           #pragma multi_compile_fwdbase_fullshadows

		   uniform sampler2D   _MainTex;
           uniform sampler2D   _MaskTex;
           uniform sampler2D   _NormTex;
           uniform sampler2D   _MatelnessMask;
           uniform sampler2D   _EmissionMask;
           uniform sampler2D   _DiffWarpTex;
           uniform sampler2D   _FresWarpTex;
           uniform samplerCUBE _Cubemap;
		   uniform half3       _LightCol;
		   uniform half        _SpecPow;
           uniform half        _SpecInt;
		   uniform half3       _EnvCol;
           uniform half        _EnvDiffInt;
		   uniform half        _EnvSpecInt;
		   uniform half3       _RimCol;
           uniform half        _RimInt;
		   uniform half        _EmitInt;
		   uniform half        _Cutoff;
		   uniform half3       _Color;

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

            struct v2f
            {
               float4 pos : SV_POSITION;
               float3 posWS : TEXCOORD0;
               float2 uv : TEXCOORD1;
               float3 nDirWS : TEXCOORD2;
               float3 tDirWS : TEXCOORD3;
               float3 bDirWS : TEXCOORD4;
               LIGHTING_COORDS(5, 6)
            };

            v2f vert (appdata v)
            {
			   v2f o; 
               o.pos    = UnityObjectToClipPos(v.vertex);
               o.posWS  = mul(unity_ObjectToWorld, v.vertex).xyz;
               o.uv     = v.uv;
               o.nDirWS = UnityObjectToWorldNormal(v.normal);
               o.tDirWS = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz);
               o.bDirWS = normalize(cross(o.nDirWS, o.tDirWS) * v.tangent.w);
			   TRANSFER_VERTEX_TO_FRAGMENT(o)
               return o;
			}

            fixed4 frag (v2f i) : SV_Target
            {
              // 向量准备
              half3 nDirTS  = UnpackNormal(tex2D(_NormTex, i.uv));
              half3x3 TBN   = half3x3(i.tDirWS, i.bDirWS, i.nDirWS);
              half3 nDirWS  = normalize(mul(nDirTS, TBN));
              half3 vDirWS  = normalize(_WorldSpaceCameraPos.xyz - i.posWS);
              half3 vrDirWS = reflect(-vDirWS, nDirWS);
              half3 lDirWS  = _WorldSpaceLightPos0.xyz;
              half3 lrDirWS = reflect(-lDirWS, nDirWS);

              half ndotl    = dot(nDirWS, lDirWS);
              half ndotv    = dot(nDirWS, vDirWS);
              half vdotr    = dot(vDirWS, lrDirWS);

			  half4 var_MainTex       = tex2D(_MainTex, i.uv);
              half4 var_MaskTex       = tex2D(_MaskTex, i.uv);
              half  var_MatelnessMask = tex2D(_MatelnessMask, i.uv).r;
              half  var_EmissionMask  = tex2D(_EmissionMask, i.uv).r;
              half3 var_FresWarpTex   = tex2D(_FresWarpTex, ndotv).rgb;
              half3 var_Cubemap       = texCUBElod(_Cubemap, float4(vrDirWS, lerp(8.0, 0.0, var_MaskTex.a))).rgb;
			  //这里多一步为了更好理解
			  half3 baseCol = var_MainTex.rgb;
              half opacity  = var_MainTex.a;
              half specInt  = var_MaskTex.r;
			  half rimInt   = var_MaskTex.g;
              half specTint = var_MaskTex.b;
              half specPow  = var_MaskTex.a;
              half matellic = var_MatelnessMask;
              half emitInt  = var_EmissionMask;
              half3 envCube = var_Cubemap;
              half shadow   = LIGHT_ATTENUATION(i);
			  
			  half3 diffCol = lerp(baseCol, half3(0.0, 0.0, 0.0), matellic);
              half3 specCol = lerp(baseCol, half3(0.3, 0.3, 0.3), specTint) * specInt;
			  half3 fresnel = lerp(var_FresWarpTex, 0.0, matellic);
              half fresnelCol  = fresnel.r; // 无实际用途
              half fresnelRim  = fresnel.g;
              half fresnelSpec = fresnel.b;
			  //漫反射
			  half halfLambert      = ndotl * 0.5 + 0.5;
              half3 var_DiffWarpTex = tex2D(_DiffWarpTex, half2(halfLambert, 0.2));//0.2无特殊意义
              half3 dirDiff         = diffCol * var_DiffWarpTex * _LightCol;

			  // 镜面反射
              half phong            = pow(max(0.0, vdotr), specPow * _SpecPow);//specPow是美术画的贴图里的,_SpecPow高光次幂
              half spec             = phong * max(0.0, ndotl);                 //乘以Lambert,在漫反射黑的地方镜面反射也减弱
              spec                  = max(spec, fresnelSpec);                  //混合也可以是加或别的操作
              spec                  = spec * _SpecInt;
              half3 dirSpec         = specCol * spec * _LightCol;
			  //环境漫反射
			  half3 envDiff         = diffCol * _EnvCol * _EnvDiffInt;
              //环境镜面反射
			  half reflectInt       = max(fresnelSpec, matellic) * specInt;     //计算ReflectInt反射率区别金属非金属
              half3 envSpec         = specCol * reflectInt * envCube * _EnvSpecInt;
			  // 轮廓光
              half3 rimLight        = _RimCol * fresnelRim * rimInt * max(0.0, nDirWS.g) * _RimInt;//可以直接换成HDR的颜色就不用加_RimInt
			  // 自发光
              half3 emission1        = diffCol * emitInt * _EmitInt;//emitInt是美术画的贴图里的,_EmitInt自定义
			  //结果
			  half3 finalRGB = (dirDiff + dirSpec) * shadow + envDiff + envSpec + rimLight + emission1;
			  clip(opacity - _Cutoff);//透明度-阈值=小于阈值减去,大于阈值保留
			  return float4(finalRGB, 1.0);
            
			}
            ENDCG
        }
    }
	FallBack "Legacy Shaders/Transparent/Cutout/VertexLit"
}

上一篇:LearnOpenGL 光照—基础光照—练习题


下一篇:OpenGL (UBO)Uniform Buffer Object统一缓冲区对象的实例