文章目录
- 人物材质基础模型
- unity练练看实现
- 代码实现
- 最后效果
- 透明特效
- AC
- 效果展示
- AB
- 效果展示
- AD
- 效果展示
- 自定义混合模式
- 效果展示
人物材质基础模型
- 这里是老师布置的作业,要求把之前学过的所有模型都组合起来,组成一个基本的人物材质模型。
- 这里在上作业课的时候,老师是用了好几张贴图,我这边没用,美术方面的能力还不够(可恶啊!) 后面还是得找些教程再深入学习一下美术方面的东西,至少画贴图这方面得学会。
unity练练看实现
下面放一下unity的连连看吧:
首先是法线贴图的处理,他要作为后续的法线使用:
然后是光源部分漫反射和镜面反射部分,需要加上投影部分:
- 这里需要解释一下,其实环境光是不会有光照衰减一说的,我们用shader forge练练看出来的材质看起来是有阴影的,应该是因为shader forge生成的代码写了两个pass,一个pass是我们的材质实现,另一个pass就是单纯为了实现模型的阴影。
- 看了12课,说好像是因为在第二个pass中加了fallback,并且目前也只有双pass的做法才能给直接光照射的物体加上投影。
然后是环境光的漫反射部分,也就是三色环境光模型:
然后是环境光的镜面反射部分,也就是之前学的cubemap部分,需要加上fresnel部分:
最后是光照和环境两个部分的连连看处理:
代码实现
自己实现的代码:
Shader "shader forge/L10_OldSchoolWithCubemap"
{
Properties
{
//_MainTex ("Base Texture", 2D) = "white" {}
[Header(Texture)]
_AO_Tex ("AO_Tex", 2D) = "white" {}
_normal ("normal", 2D) = "bump" {}
_cubemap ("cubemap", Cube) = "_Skybox" {}
[Header(Lighting)]
_L_Lambert_Color ("L_Lambert_Color", Color) = (0.5,0.5,0.5,1)
_L_Specular_Color ("L_Specular_Color", Color) = (0.5,0.5,0.5,1)
_Light_Color ("Light_Color", Color) = (0.5,0.5,0.5,1)
[Header(Diffuse)]
_E_Lambert_UpColor ("E_Lambert_UpColor", Color) = (0.8679245,0.5444998,0.5444998,1)
_E_Lambert_DownColor ("E_Lambert_DownColor", Color) = (0.4400143,0.6626909,0.9056604,1)
_E_Lambert_MidColor ("E_Lambert_MidColor", Color) = (0.4800081,0.8962264,0.4016109,1)
[Header(Specular)]
_mipmap_level ("mipmap_level", Range(0, 7)) = 0
_fresnel_exp ("fresnel_exp", Range(0, 90)) = 0.6956522
_Env_SpecInt ("Env_SpecInt", Range(0, 5)) = 0.7826087
_Phong_Int ("Phong_Int", Range(0, 90)) = 5
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#include "Lighting.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
struct appdata
{
float4 vertex : POSITION;
float2 uv0 : TEXCOORD0;
float3 normal : NORMAL;
float4 tangent : TANGENT;
};
struct v2f
{
float2 uv0 : TEXCOORD0;
float4 pos : SV_POSITION;
float4 posWorld : TEXCOORD1;
float3 nDirWS : TEXCOORD2;
float3 tDirWS : TEXCOORD3;
float3 biDirWS : TEXCOORD4;
LIGHTING_COORDS(5,6)
};
//Texture
uniform sampler2D _AO_Tex;
uniform sampler2D _normal;
uniform samplerCUBE _cubemap;
//Lighting
uniform float4 _L_Lambert_Color;
uniform float4 _L_Specular_Color;
uniform float4 _Light_Color;
//Diffuse
uniform float4 _E_Lambert_UpColor;
uniform float4 _E_Lambert_DownColor;
uniform float4 _E_Lambert_MidColor;
//Specular
uniform float _mipmap_level;
uniform float _fresnel_exp;
uniform float _Env_SpecInt;
uniform float _Phong_Int;
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv0 = v.uv0;
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
o.nDirWS = UnityObjectToWorldNormal(v.normal);
o.tDirWS = normalize(mul(unity_ObjectToWorld,float4(v.tangent.xyz,0.0)).xyz);
o.biDirWS = normalize(cross(o.nDirWS,o.tDirWS) * v.tangent.w);
TRANSFER_VERTEX_TO_FRAGMENT(o)
return o;
}
fixed4 frag (v2f i) : SV_Target
{
//贴图采样
float3 nDirTS = UnpackNormal(tex2D(_normal,i.uv0)).rgb;
float AO_R = tex2D(_AO_Tex,i.uv0);
//向量准备
float3x3 TBN_Matrix = float3x3(i.tDirWS,i.biDirWS,i.nDirWS);
float3 nDirWS_FT = normalize(mul(nDirTS, TBN_Matrix));
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
float3 halfDir = normalize(lightDir + viewDir);
float3 vrDir = normalize(reflect(-viewDir,nDirWS_FT));
//中间量准备
/*下面是光照的漫反射和镜面反射部分*/
//diffuse
float NoL = max(0.0,dot(lightDir,nDirWS_FT));
float3 L_diff = NoL * _L_Lambert_Color;
//specular
float NoH = max(0.0,dot(nDirWS_FT,halfDir));
float3 L_spec = pow(NoH * _L_Specular_Color,_Phong_Int);
//光衰部分
float attenuation = LIGHT_ATTENUATION(i);
//UNITY_LIGHT_ATTENUATION(attenuation, i, i.posWorld.xyz);
float3 attenColor = attenuation * _LightColor0.xyz;
/*下面是环境光的漫反射部分,也就是三色环境光*/
//上层光
float upNor = clamp(nDirWS_FT.g,0.0,1.0);
float3 upColor = upNor * _E_Lambert_UpColor;
//下层光
float downNor = clamp(nDirWS_FT.g * -1,0.0,1.0);
float3 downColor = downNor * _E_Lambert_DownColor;
//中层光
float midNor = clamp(1 - upNor - downNor,0.0,1.0);
float3 midColor = midNor * _E_Lambert_MidColor;
/*下面是环境镜面反射光部分*/
//cubemap
float3 cubemap_Dir = vrDir;
float3 cubemap_color = texCUBElod(_cubemap,float4(cubemap_Dir,_mipmap_level));
//fresnel
float NoV = max(0.0,dot(nDirWS_FT,viewDir));
float OneMinusNoV = 1 - NoV;
float fresnel = pow(OneMinusNoV,_fresnel_exp);
//光照模型
/*光照的漫反射和镜面反射*/
float3 light_all = (L_diff + L_spec) * _Light_Color * attenColor;
/*环境光的漫反射部分 三色环境光*/
float3 env_diff_all = clamp(upColor + downColor + midColor,0.0,1.0);
/*环境光的镜面反射部分 cubemap和fresnel部分*/
float3 env_spec_all = cubemap_color * fresnel * _Env_SpecInt;
/*环境光的漫反射和镜面反射的总和*/
float3 env_all = clamp(env_diff_all + env_spec_all,0.0,1.0) * AO_R;
float3 finalColor = clamp(env_all + light_all,0.0,1.0);
//后处理
//返回值
return float4(finalColor,1.0);
//return float4(0.0,1.0,0.0,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
最后效果
透明特效
- AC : Alpha Test(Alpha Cutout)
- AB : Alpha Blend
- AD : Additive
- 自定义混合方法:把混合方式都列在属性面板上,让使用者自己挑选并试验效果。
AC
- 透明剪切,alpha cutout,也叫做alpha test,也是AC。左边的我们看出边缘比较柔,右边的锯齿比较多,alpha blend前后是错乱的,alpha test前后是正确的,AC用途如PPT所示。
- Alpha Test非常直接,就是判断一个片元的Alpha值是否满足我们给定的阈值,不满足条件则直接discard这个片元,不参与后续的tests。Alpha Test的结果是一个片元要么完全不透明,要么被discard以至于完全看不到。
- 所以它的其实不算正经的透明效果,它只是把不符合条件的片元给舍弃掉,造成只显示一部分片元的效果。
代码实现:
Shader "shader forge/L13_AC"
{
Properties
{
_MainTex ("Base Color With A", 2D) = "white" {}
_CutOff ("CutOff",Range(0.0,1.0)) = 0.5 //透明度阈值
}
SubShader
{
Tags {
"RenderType"="TransparentCutout"
"ForceNoShadowCasting" = "True"
"IgnoreProjector" = "True"
}
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv0 : TEXCOORD0;
};
struct v2f
{
float2 uv0 : TEXCOORD0;
float4 vertex : SV_POSITION;
};
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST; //我们的贴图偏移选项
uniform float _CutOff;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv0 = TRANSFORM_TEX(v.uv0, _MainTex); //加上贴图偏移
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 var_MainTex = tex2D(_MainTex, i.uv0);
//这是我们要做的主要步骤,如果贴图的透明度不大于我们的阈值,就直接裁剪抛弃掉
clip(var_MainTex.a - _CutOff);
return var_MainTex;
}
ENDCG
}
}
}
效果展示
AB
- 与之对比的是ab,虽然是有排序问题(如图所示,是错乱的),经常用于不考虑中间细节并且有复杂轮廓的物体使用。
- 在特效上非常常用,作为打底。经常的一个套路,用ab打一层底,再用ad去提亮一层。
代码实现:
Shader "shader forge/L13_AB"
{
Properties
{
_MainTex ("Base Color With A", 2D) = "white" {}
}
SubShader
{
//主要做的
Tags {
"Queue"="Transparent"
"RenderType" = "Transparent"
"ForceNoShadowCasting" = "True"
"IgnoreProjector" = "True"
}
Blend SrcAlpha OneMinusSrcAlpha //主要做的
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv0 : TEXCOORD0;
};
struct v2f
{
float2 uv0 : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST; //我们的贴图偏移选项
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv0 = TRANSFORM_TEX(v.uv0, _MainTex); //加上贴图偏移
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 var_MainTex = tex2D(_MainTex, i.uv0);
return var_MainTex;
}
ENDCG
}
}
}
效果展示
- 跟上面的AC对比一下会发现这个模型的边缘会更加柔和。
AD
- AD是特效的灵魂,经常表达发光体,特效经常使用多个透明片叠加,这样每一个像素要进行好几次的计算,会造成性能的拉跨。
- 注意防止多层透明片叠加,同时AD也可以逐渐用后处理+bloom来替代。
代码实现:
Shader "shader forge/L13_AD"
{
Properties
{
_MainTex ("Base Color With A", 2D) = "white" {}
}
SubShader
{
//主要做的
Tags {
"RenderType"="Transparent"
"Queue" = "Transparent"
"ForceNoShadowCasting" = "True"
"IgnoreProjector" = "True"
}
Blend One One //主要做的
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST; //我们的贴图偏移选项
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex); //加上贴图偏移
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 var_MainTex = tex2D(_MainTex, i.uv);
return var_MainTex;
}
ENDCG
}
}
}
效果展示
- 一和一叠加,直接变得更亮了。
自定义混合模式
- 这次我们要实现的上图左边的样子。
- [Enum(枚举类型)],这行定义意思是在属性面板画出下拉列表,列表中的内容就是枚举类型中的内容。
- 在这个shader里算出来的结果,就是源src。
- 在这个shader开始算的之前的背景,就是目标src。
代码实现:
Shader "shader forge/L13_BlendMode"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
[Enum(UnityEngine.Rendering.BlendMode)]
_BlendSrc ("Blend source factor",int) = 0
[Enum(UnityEngine.Rendering.BlendMode)]
_BlendDst ("Blend destination factor",int) = 0
[Enum(UnityEngine.Rendering.BlendOp)]
_BlendOp ("Blend Operation", int) = 0
}
SubShader
{
//主要做的
Tags {
"RenderType"="Transparent"
"Queue" = "Transparent"
"ForceNoShadowCasting" = "True"
"IgnoreProjector" = "True"
}
//下面两行是主要做的
BlendOp [_BlendOp]
Blend [_BlendSrc] [_BlendDst]
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST; //我们的贴图偏移选项
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex); //加上贴图偏移
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 var_MainTex = tex2D(_MainTex, i.uv);
return var_MainTex;
}
ENDCG
}
}
}
效果展示
代码做出来的属性面板:
模型展示:
- 算子是srcalpha和OneMinusSrcAlpha:
- 算子是One和OneMinusSrcAalpha:
- 算子是One和One: