Article Directory
character base model
- Here is the homework assigned by the teacher. It is required to combine all the models learned before to form a basic character material model.
- During the homework class here, the teacher used several stickers, which are useless for me, and my art skills are not enough (damn it!) Later, I still need to find some tutorials to learn more about art, at least to learn how to draw stickers.
Unity practice to see the realization
Let’s take a look at the Lianliankan of unity:
the first is the processing of the normal map, which will be used as the subsequent normal:
Then there is the diffuse reflection and specular reflection part of the light source part, and the projection part needs to be added:
- Here we need to explain, in fact, ambient light does not have light attenuation. We use shader forge to see that the material looks shadowed. It should be because the code generated by shader forge has written two passes. One pass is our material realization, and the other pass is purely for realizing the shadow of the model.
- After reading lesson 12, I said that it seems to be because of the fallback added in the second pass, and at present, only the double pass method can add projection to the object illuminated by direct light.
Then there is the diffuse reflection part of the ambient light, that is, the three-color ambient light model:
then there is the specular reflection part of the ambient light, which is the cubemap part learned before, and the fresnel part needs to be added:
Finally, the Lianliankan processing of the two parts of lighting and environment:
Code
Code implemented by myself:
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"
}
final effect
Transparent effects
- AC : Alpha Test(Alpha Cutout)
- AB : Alpha Blend
- AD : Additive
- Custom blending methods: List the blending methods on the property panel, allowing users to choose and experiment with the effect.
AC
- Transparent cut, alpha cutout, also called alpha test, is also AC. On the left side, we can see that the edge is softer, and on the right side there are more sawtooth, the front and back of alpha blend are disordered, and the front and back of alpha test are correct, and the use of AC is shown in the PPT.
- Alpha Test is very straightforward. It is to judge whether the Alpha value of a fragment meets our given threshold. If the condition is not met, the fragment will be directly discarded and will not participate in subsequent tests. The result of the Alpha Test is that a fragment is either completely opaque, or discarded so that it cannot be seen at all.
- So it is actually not a serious transparency effect, it just discards the fragments that do not meet the conditions, resulting in the effect of only displaying a part of the fragments.
Code:
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
}
}
}
Show results
AB
- In contrast, ab, although it has a sorting problem (as shown in the figure, is disordered), is often used for objects that do not consider intermediate details and have complex outlines.
- It is very commonly used in special effects as a base. A common routine is to use ab to make a base layer, and then use ad to brighten a layer.
Code:
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
}
}
}
Show results
- Comparing it with the AC above, you will find that the edges of this model will be softer.
AD
- AD is the soul of special effects. It often expresses illuminants. Special effects often use multiple transparent sheets to superimpose, so that each pixel needs to be calculated several times, which will cause a performance gap.
- Pay attention to prevent the superimposition of multi-layer transparent films, and AD can also be gradually replaced by post-processing + bloom.
Code:
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
}
}
}
Show results
- One and one are superimposed, and it becomes brighter directly.
custom blend mode
- This time we want to achieve what the left side of the picture above looks like.
- [Enum (enumeration type)], this line of definition means to draw a drop-down list in the property panel, and the content in the list is the content in the enumeration type.
- The result calculated in this shader is the source src.
- The background before this shader starts to calculate is the target src.
Code:
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
}
}
}
Show results
The property panel made by the code:
Model display:
- The operators are srcalpha and OneMinusSrcAlpha:
- The operators are One and OneMinusSrcAalpha:
- Operators are One and One: