![a3e0bcafac5494b0972687d455216507.png](https://img-blog.csdnimg.cn/img_convert/a3e0bcafac5494b0972687d455216507.png)
此篇文章为系列文章,如果需要观看前篇请点击
雨轩:Unity PBR StandardShader 实现详解(一)PBR的简单介绍及美术原理zhuanlan.zhihu.com![11d6db2ebeeecdf8b97cf3182e72320e.png](https://img-blog.csdnimg.cn/img_convert/11d6db2ebeeecdf8b97cf3182e72320e.png)
这一篇文章将依据Unity的StandardShader进行逐行的分析,并在需要引入原理讲解的时候适当解释原理。在阅读之前可能需要shader的相关经验,以及一些Untiy引擎使用的基础知识。假如你会写一点简单的shader,但觉得standarShader的学习曲线过于陡峭,那么朋友你找到你的登山车了。
撸完本文,你将获得一个自己的PBRshader,同时了解到使用Unity内置PBS或BRDF方法前,需要做的数据准备。
话不多说,点赞上车
1.shader基本框架的准备(属性及结构体部分):
我们先确认一下shader内需要的功能:因为只是搭建一个PBR实现的测试Shader,所以只添加如下的功能:阴影,雾效等一些简单的效果。不考虑烘焙和合批等内容。
以下代码的侧重详细解释的在PBR阶段,一些基础的内容可以参考冯乐乐小姐姐的书,需要注释的我尽量注释一下
我们先需要搭建一个顶点片段着色器的框架
Shader "yuxuan/PBR_test"
{
Properties
{
}
SubShader
{
pass
{
CGPROGRAM
ENDCG
}
}
}
然后我们在Properties里面准备一下输入的贴图们
Properties
{
_Color ("Color", Color) = (1, 1, 1, 1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_MetallicTex("Metallic(R),Smoothness(A)",2D) = "white"{}
//金属贴图最终只获取r分量和a分量
_Metallic ("Metallic", Range(0, 1)) = 1.0
_Glossiness("Smoothness",Range(0,1)) = 1.0
[Normal]_Normal("NormalMap",2D) = "bump"{}
_OcclussionTex("Occlusion",2D) = "white"{}
_AO("AO",Range(0,1)) = 1.0
_Emission("Emission",Color) = (0,0,0,1)
}
注意这里面我的金属度贴图混合了Metallic和Smoothness两个单通道图。这也是Unity默认的做法,假如自己的贴图效果不对的话,可以在ps或者painter里调换一下通道。
接下来是pass里面的标签和编译指令
Pass
{
//因为需要灯光设定和Unity配合,所以要加上前向渲染标签。
Tags {
"LightMode" = "ForwardBase" }
CGPROGRAM
//顶点片段着色器
#pragma vertex vert
#pragma fragment frag
//指定平台,也可以省略
#pragma target 3.0
//雾效和灯光的关键字
#pragma multi_compile_fog
#pragma multi_compile_fwdbase
//一些会用到的cginc文件
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "UnityPBSLighting.cginc"
#include "AutoLight.cginc"
//...
然后声明我们在材质球里输入的变量
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _MetallicTex;
fixed _Metallic;
fixed _Glossiness;
fixed _AO;
half3 _Emission;
sampler2D _Normal;
//...
输入定点着色器的appdata结构体部分,我们会直接用Unity内置的appdata_Full,来看看里面有啥
下面这段是看看用的,不需要写入shader
struct appdata_full {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
float4 texcoord1 : TEXCOORD1;
float4 texcoord2 : TEXCOORD2;
float4 texcoord3 : TEXCOORD3;
fixed4 color : COLOR;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
基本上我们需要的东西都有了
接下来自己写一个v2f,顶点着色器传入片段着色器的数据
struct v2f
{
float4 pos:SV_POSITION;//裁剪空间位置输出
float2 uv: TEXCOO