角色shader小练习

跟着庄懂老师的思路做的Dota角色材质

1.1处理好贴图

里面的贴图是有上下颠倒或者左右相反的问题,所以需要先用把图片处理成与颜色贴图和法线贴图一样的位置,然后其他的RampTexture要把WrapMode设置为Clamp模式。

未处理会出现黑色斑点

处理后RampTexture会呈现正常的效果

1.2 查看设计文档,分析光照模型和贴图作用

因为考虑到金属和非金属的漫反射和高光反射所反射出来的颜色是不一样的,所以先计算出镜面反射和高光反射所产生的不同颜色,后面将该颜色分别乘入所计算出来的光照模型中。

 float3 diffuseColor = lerp(var_MainTexture,float3(0.0,0.0,0.0), var_Metellic); 
 float3 specularColor = lerp(var_MainTexture, float3(0.4, 0.4, 0.4), var_TintMaskTexture) * var_SpecIntTexture; 

1.3 光照模型

1.3.1 漫反射

//主光源漫反射
float halfLambert =ldotn * 0.5 + 0.5;  
float3 lambertColor = tex2D(_DiffuseColor,float2(halfLambert,0.5));
float3 lightDiffuseColor = _LightColor * lambertColor * diffuseColor * _LightDiffuseStrength;

//环境光漫反射
float maskUp = max(0,nDirWS.g);
float maskDown = max(0, -nDirWS.g) ;
float maskMiddle = 1 - maskUp - maskDown;
float3 ambiendDiffuseColor =( maskUp * _AmbientDiffuseColor_Up + maskDown * _AmbientDiffuseColor_Down + _AmbientDiffuseColor_Middle * maskMiddle ) * diffuseColor * _AmbientDiffuseStrength;

 主光源的漫反射

 

环境光的漫反射

 1.3.2 高光反射

//主光源高光反射
float Phong = pow(max(0, lrdotv), var_SpecPowTexture * _LightSpecularPow);
float specular = Phong * halfLambert;
float FresnelSpecular = lerp(var_FresnelSpecular,0.0, var_Metellic);
//float specular_Fresnel = tex2D(_FresnelSpecular, float2(specular, 0.5));//好像不太能那么采样,出现很神奇的效果
float specular_Fresnel = max(specular, FresnelSpecular) * _LightSpecularStrength;
float3 lightSpecularColor = _LightColor * specular_Fresnel * specularColor;

//环境光高光反射
float reflect = max(var_Metellic, FresnelSpecular) * var_SpecIntTexture;
float3 envSpecularColor = reflect * specularColor * var_CubeMap * _EnvSpecularStength;

 主光源的高光反射

 环境光的高光反射

 如果用ramptexture用高光作为采样,会产生类似于整体都是金属的效果

 因为菲涅尔效果通常是一些比较光滑的材质才会出现,所以要用金属范围遮罩来对该菲涅尔的ramptexture进行lerp一下

var_FresnelRim没有lerp一下

 处理后

 1.3.3 轮廓光和自发光

//轮廓光
float FresnelRim = lerp(var_FresnelRim, 0.0, var_Metellic);
float3 rimLight = var_RimIntTexture * FresnelRim * max(0, nDirWS.g) * _RimStrength * _RimColor;

//自发光
float3 emission = diffuseColor * var_EmissionTexture * _EmissionStrength;

  1.3.4 混合光照和输出

1.4代码

注:因为是为了比较直观和可以不用思考参数之间的转换,所以没有把多张贴图合成一张贴图,可以看到后面是对各贴图都进行了一次采样,然后所有的参数类型都统一使用了float,有些是可以用half或者fixed来代替的。

Shader "Unlit/Body Shader"
{
    Properties{
        //开放属性控制
        [Header(Texture)]
        _MainTexture("主贴图",2D) = "white"{}
        _OpacityTexture("透明贴图",2D) = "white"{}
        _NormalTexture("法线贴图",2D) = "bump"{}
        _SpecIntTexture("高光强度贴图",2D) = "white"{}
        _RimIntTexture("边缘光强度贴图",2D) = "white"{}
        _TintMaskTexture("染色遮罩贴图",2D) = "white"{}
        _SpecPowTexture("高光次幂贴图",2D) = "white"{}
        _CubeMap("环境球",cube) = "_skybox"{}
        _DiffuseColor("漫反射颜色贴图",2D) = "grey"{}
        _FresnelRim("菲尼尔边缘光贴图",2D) = "white"{}
        _FresnelSpecular("菲尼尔高光贴图",2D) = "white"{}
        _Metellic("金属范围遮罩",2D) = "grey"{}
        _EmissionTexture("发光贴图",2D) = "white"{}
        [Header(Slider)]
        _Cutoff("透明贴图阈值",Range(0,1)) = 0.5
        _LightDiffuseStrength("主光漫反射强度",Range(0,5)) = 2
        _LightSpecularStrength("主光高光反射强度", Range(0,5)) = 2
        _LightSpecularPow("主光高光次幂", Range(0,10)) = 5
        _AmbientDiffuseStrength("环境光漫反射强度",Range(0,1)) = 0.8
        _EnvSpecularStength("环境光高光反射强度",Range(1,10)) = 5
        _RimStrength("边缘光强度",Range(0,5)) = 2
        _EmissionStrength("自发光强度",Range(0,5)) = 2
        [Header(Color)]
        _LightColor("灯光颜色", color) = (1.0,1.0,1.0,1.0)
        _AmbientDiffuseColor_Up("环境光漫反射上部光",color) = (1.0,1.0,1.0,1.0)
        _AmbientDiffuseColor_Middle("环境光漫反射中部光",color) = (1.0,1.0,1.0,1.0)
        _AmbientDiffuseColor_Down("环境光漫反射下部光",color) = (1.0,1.0,1.0,1.0)
        _RimColor("边缘光颜色",color) = (1.0,1.0,0.0,1.0)
    }
    SubShader{
        Tags {
            "RenderType" = "Opaque"
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode" = "ForwardBase"
            }
            Cull Off
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "AutoLight.cginc"
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0
            //定义属性
            uniform sampler2D _MainTexture;
            uniform sampler2D _OpacityTexture;
            uniform float _Cutoff;
            uniform sampler2D _NormalTexture;
            uniform float _LightDiffuseStrength;
            uniform sampler2D _SpecIntTexture;
            uniform sampler2D _RimIntTexture;
            uniform sampler2D _TintMaskTexture;
            uniform sampler2D _SpecPowTexture;
            uniform samplerCUBE _CubeMap;
            uniform sampler2D _FresnelRim;
            uniform sampler2D _FresnelSpecular;
            uniform sampler2D _Metellic;
            uniform sampler2D _DiffuseColor;
            uniform float3 _LightColor;
            uniform float3  _AmbientDiffuseColor_Up;
            uniform float3  _AmbientDiffuseColor_Middle;
            uniform float3  _AmbientDiffuseColor_Down;
            uniform float  _AmbientDiffuseStrength;
            uniform float _LightSpecularPow;
            uniform float _LightSpecularStrength;
            uniform float _EnvSpecularStength;
            uniform float3 _RimColor;
            uniform float _RimStrength;
            uniform sampler2D _EmissionTexture;
            uniform float _EmissionStrength;

            //输入结构
            struct VertexInput {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 tangent : TANGENT;
                float2 uv0 : TEXCOORD0;
            };
            //输出结构
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float3 posWS : TEXCOORD0;
                float2 uv0 : TEXCOORD1;
                float3 nDirWS : TEXCOORD2;
                float3 tDirWS : TEXCOORD3;
                float3 bDirWS : TEXCOORD4;
                LIGHTING_COORDS(5, 6)
            };
            //像素shader
            VertexOutput vert(VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.posWS = mul(unity_ObjectToWorld, v.vertex);
                o.uv0 = v.uv0;
                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;
            }
            //顶点shader
            float4 frag(VertexOutput i) : COLOR {
                //向量准备
                float3 nDirTS = UnpackNormal(tex2D(_NormalTexture,i.uv0)).rgb;  //得到法线信息
                float3x3 TBN = float3x3(i.tDirWS,i.bDirWS,i.nDirWS);
                float3 nDirWS = normalize(mul(nDirTS, TBN));
                float3 lDirWS = _WorldSpaceLightPos0.xyz;
                float3 lrDirWS = reflect(lDirWS,nDirWS);
                float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
                float3 vrDirWS = normalize(reflect(-vDirWS, nDirWS));

                //中间量准备
                float ldotn = dot(lDirWS,nDirWS);   //半兰伯特需要的点乘量
                float lrdotv = dot(lrDirWS, vDirWS);    //Phong需要的点乘量
                float ndotv = (nDirWS,vDirWS);      //轮廓光需要的点乘量

                //纹理采样
                float3 var_MainTexture = tex2D(_MainTexture, i.uv0); //采样颜色纹理
                float var_OpacityTexture = tex2D(_OpacityTexture, i.uv0);//透明贴图采样
                float var_SpecIntTexture = tex2D(_SpecIntTexture, i.uv0);    //采样高光纹理,作为高光需要增加的强度
                float var_RimIntTexture = tex2D(_RimIntTexture, i.uv0); //边缘光纹理,作为遮罩判断要高光的地方
                float var_TintMaskTexture = tex2D(_TintMaskTexture, i.uv0); //染色遮罩纹理,作为
                float var_SpecPowTexture = tex2D(_SpecPowTexture, i.uv0);   //采样高光次幂,将其作为模板控制粗糙度
                float var_FresnelRim = tex2D(_FresnelRim, i.uv0);   //菲涅尔边缘光的ramptexture
                float var_FresnelSpecular = tex2D(_FresnelSpecular, i.uv0);     //菲涅尔高光的ramptexture
                float3 var_CubeMap = texCUBElod(_CubeMap, float4(vrDirWS, lerp(7.0, 0.0, var_SpecIntTexture))).rgb;
                float var_Metellic = tex2D(_Metellic, i.uv0);
                float var_EmissionTexture = tex2D(_EmissionTexture, i.uv0);

                // 阴影
                float shadow = LIGHT_ATTENUATION(i);

                //光照模型
                 //因为镜面反射和漫反射的颜色增加了不同,镜面反射中金属会呈现其本色,非金属会呈现黑白灰;漫反射中则是金属漫反射少,贴图较黑
                float3 diffuseColor = lerp(var_MainTexture,float3(0.0,0.0,0.0), var_Metellic); //用lerp进行插值,如果matellic为0的地方则会反映出其原色,如果是1则反应为黑,matellic=0.5嚯其他小数则是进行插值计算其偏移的权重
                float3 specularColor = lerp(var_MainTexture, float3(0.4, 0.4, 0.4), var_TintMaskTexture) * var_SpecIntTexture;  //通过金属会反光的遮罩进行插值计算,并且与带有高光强度的贴图进行相乘,从而模仿其在带有光源下的反射颜色
                
                //主光源漫反射
                float halfLambert =ldotn * 0.5 + 0.5;   //半兰伯特效果比兰伯特效果好很多,兰伯特效果有点可怕
                float3 lambertColor = tex2D(_DiffuseColor,float2(halfLambert,0.5));
                float3 lightDiffuseColor = _LightColor * lambertColor * diffuseColor * _LightDiffuseStrength;

                //环境光漫反射
                float maskUp = max(0,nDirWS.g);
                float maskDown = max(0, -nDirWS.g) ;
                float maskMiddle = 1 - maskUp - maskDown;
                float3 ambiendDiffuseColor =( maskUp * _AmbientDiffuseColor_Up + maskDown * _AmbientDiffuseColor_Down + _AmbientDiffuseColor_Middle * maskMiddle ) * diffuseColor * _AmbientDiffuseStrength;
                
                //主光源高光反射
                float Phong = pow(max(0, lrdotv), var_SpecPowTexture * _LightSpecularPow);
                float specular = Phong * halfLambert;
                float FresnelSpecular = lerp(var_FresnelSpecular,0.0, var_Metellic);
                //float specular_Fresnel = tex2D(_FresnelSpecular, float2(specular, 0.5));//好像不太能那么采样,出现很神奇的效果
                float specular_Fresnel = max(specular, FresnelSpecular) * _LightSpecularStrength;
                float3 lightSpecularColor = _LightColor * specular_Fresnel * specularColor;

                //环境光高光反射
                float reflect = max(var_Metellic, FresnelSpecular) * var_SpecIntTexture;
                float3 envSpecularColor = reflect * specularColor * var_CubeMap * _EnvSpecularStength;
    
                //轮廓光
                float FresnelRim = lerp(var_FresnelRim, 0.0, var_Metellic);
                float3 rimLight = var_RimIntTexture * FresnelRim * max(0, nDirWS.g) * _RimStrength * _RimColor;

                //自发光
                float3 emission = diffuseColor * var_EmissionTexture * _EmissionStrength;

                //混合光源
                float3 finalColor = (lightDiffuseColor + lightSpecularColor) * shadow + envSpecularColor + envSpecularColor + rimLight + emission;

                //透明剪切
                clip(var_OpacityTexture - _Cutoff);

                   return fixed4(finalColor,1);

            }
                            ENDCG
                        }
    }
        FallBack "Legacy Shaders/Transparent/Cutout/VertexLit"
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值