学习Shader的目的就在于在游戏中实现精美的模型效果,提升整体美术质量并优化性能。此处进行第一次人物模型的Shader编写,使用的模型与贴图为来自Dota2的石麟剑士。
资源下载地址:https://www.dota2.com/workshop/requirements/
资源处理
第一步首先分析官方给的渲染文档,大致确定好会用到的贴图以及这些贴图的作用。
在获得的文件中,模型包含了4个部分:Base、Armor、Head、Weapon。Armor的贴图有如下资源:
可以看到实际文件与文档还是有些出入,此时应该按照自己的理解尽量对贴图进行划分:
CubeMapSeparateMask:天空盒影响强度遮罩 TintByBaseMask:根据基底色对高光进行染色的强度遮罩
剔除不使用的贴图,找出公共贴图(所有部件使用的该部分贴图完全一致),然后分离出可选贴图。
划分好后,需要将贴图进行一些处理,进行通道混合,减少采样次数。私有的贴图可以混合到一个贴图里;可选的贴图不混合,公共的贴图混合到一个贴图里。
最后这8张贴图就是需要导入到引擎当中的:
根据给定的贴图搭配渲染文档构思一套适合的光照模型
开始编写Shader:
首先将所有贴图输入到Shader中并提供接口调用,在片元着色中准备向量、点积结果、贴图采样、拆分并获取贴图数值这几个步骤。将贴图数值依次输出到模型上检查是否出现错误。
Properties
{
[Header(Texture)]
_MainTex ("RGB:基底色 A:透贴", 2D) = "white" {
}
_Mask ("R:镜面反射遮罩 G:镜面反射强度 B:天空盒影响 A:基底色染色", 2D) = "white"{
}
[Normal] _Normal ("RGB:法线贴图", 2D) = "bump" {
}
_FresnelRamp ("R:颜色采样 G:轮廓光采样 B:镜面反射采样", 2D) = "white" {
}
_MetalMask ("金属度遮罩", 2D) = "white" {
}
_RimMask ("轮廓光遮罩", 2D) = "white" {
}
_Skybox ("天空盒", Cube) = "_Skybox" {
}
[Header(Color)]
_LightCol ("光色",COLOR) = (1.0, 1.0, 1.0, 1.0)
[Header(Value)]
_Mip ("Mip等级", Range(0,8)) = 0
}
...
// Texture
uniform sampler2D _MainTex;
uniform sampler2D _Mask;
uniform sampler2D _Normal;
uniform sampler2D _FresnelRamp;
uniform sampler2D _MetalMask;
uniform sampler2D _RimMask;
uniform samplerCUBE _Skybox;
// Color
uniform float4 _LightCol;
// Value
uniform float _Mip;
...
float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS);
float3 nDirWS = normalize(mul(UnpackNormal(tex2D(_Normal, i.uv0)), TBN));
float3 lDirWS = _WorldSpaceLightPos0.xyz;
float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS);
float3 vrDirWS = normalize(reflect(-vDirWS, nDirWS));
// 点积结果
float nDotl = dot(nDirWS, lDirWS);
float nDotv = dot(nDirWS, vDirWS);
float vrDotl = dot(vrDirWS, lDirWS);
// 贴图采样
float4 var_MainTex = tex2D(_MainTex, i.uv0);
float4 var_Mask = tex2D