简介
PBR全称Physically Based Rendering
即基于物理的渲染
它包含很多技术,折射、反射、GI、PBS等
其中的重点就是PBS
PBS
PBS全称Physically Based Shadering
即基于物理的着色
这是PBR的核心
而PBS的核心有
1.物质的光学特性
主要根据反射率去分为金属和非金属
金属
1.具有很高的反射率(>=0.5)
2.会立即吸收折射光,因此金属不会出现任何次表面散射或是透明效果
3.所有颜色都来自反射
非金属
1.具有很低的反射率(<=0.06)
2.会产生高光反射和漫反射
3.高光反射为单色/灰色
2.微平面理论
3.能量守恒
因此,镜面反射+漫反射<=入射光
4.菲涅尔反射
菲涅尔效应是一种表示光线的反射率与视角相关的现象
即视角观察方向于平面法线的对应关系
夹角越大,反射率就越大,亮度也就越亮
夹角越小,反射率就越小,亮度也就越低
5.线性空间光照
与之相对有个伽马空间
对于线性的颜色变化
人眼看到的
显示器输出的
可以看出他们是一样的
因此sRGB图就是在此基础上的矫正,但这会让着色器在计算时出现误差
因此需要使用Linear空间
双向反射分布函数BRDF
渲染方程
描述了光能在场景中的流动,根据光的物理学原理,渲染方程可以完美模拟出符合物理光学的结果
那个积分就是来自其他片段的漫反射
迪士尼原则的BRDF
1.使用直观的参数,而不是晦涩的物理参数
2.参数尽可能的少
3.参数在其合理范围内应该为0-1
4.允许参数在有意义的情况下超出正常范围
5.所有参数组应该尽可能的独立与合理
BaseColor固有色:表面的颜色,通常由纹理提供
SubSurface次表面:使用次表面近似的控制漫反射形状
Metallic金属度:0=非金属,1=金属,这是两种不同模型之间的线性混合
Specular镜面反射强度:字面意思
SpecularTint镜面反射颜色:对美术控制的让步,用于对BaseColor的入射镜面反射进行颜色控制
Roughness粗糙度:表面粗糙度,控制漫反射和镜面反射
Anisotropic各向异性强度:0=各项同性,1=各向异性,用于控制镜面反射高光的纵横比
Sheen光泽度:一种额外的掠射分量,主要用于布料
SheenTint光泽颜色:对Sheen的颜色控制
ClearCoat清漆强度:特殊用途的第二个镜面波瓣
ClearCoatGloss清漆光泽度:控制透明涂层光泽度
Shader&Cginc实现
1.准备材料
在Unity商店下载了个模型
带基础色、金属度、AO、法线、粗糙度贴图
2.创建标准表面shader,并解码,我们修改解码后的shader
1685行代码,没关系,我们进行优化3.shader
1.属性部分
Properties
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Metallic ("Metallic", Range(0,1)) = 0.0
_MetallicTex ("MaterialTex", 2D) = "white" {}
_Smoothness ("Smoothness", Range(0,1)) = 0.5
_AO ("AO", Range(0,1)) = 1
_AOTex ("AOTex", 2D) = "white" {}
_NormalTex ("NormalTex", 2D) = "bump" {}
2.Pass部分
FORWARD
Name "FORWARD"
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#pragma multi_compile_fog
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#include "Lighting.cginc"//GI部分
#include "UnityPBSLighting.cginc"//PBS部分
//要么走下面这个,要么走上面两个
//#include "./MyPBS.cginc"//这是走自己的cginc
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
float3 tangent:TANGENT;
float2 uv:TEXCOORD0;
float4 texcoord1:TEXCOORD1;
};
struct v2f
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
float3 worldNormal:TEXCOORD1;
float3 worldPos:TEXCOORD2;
#if UNITY_SHOULD_SAMPLE_SH
half3 sh:TEXCOORD3;
#endif
UNITY_FOG_COORDS(4)
UNITY_SHADOW_COORDS(5)
float3 tSpace1:TEXCOORD6;
float3 tSpace2:TEXCOORD7;
float3 tSpace3:TEXCOORD8;
};
sampler2D _MainTex;fixed4 _MainTex_ST;
fixed4 _Color;
half _Smoothness;
half _Metallic;sampler2D _MetallicTex;
half _AO;sampler2D _AOTex;
sampler2D _NormalTex;
v2f vert(a2v v)
{
v2f o;
UNITY_INITIALIZE_OUTPUT(v2f,o);
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv,_MainTex);
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
fixed3 worldTangent = UnityObjectToWorldDir(v.tangent);
fixed3 worldBinormal = cross(worldNormal, worldTangent);
o.tSpace1 = fixed3(worldTangent.x, worldBinormal.x, worldNormal.x);
o.tSpace2 = fixed3(worldTangent.y, worldBinormal.y, worldNormal.y);
o.tSpace3 = fixed3(worldTangent.z, worldBinormal.z, worldNormal.z);
o.worldNormal = worldNormal;
o.worldPos = mul(unity_ObjectToWorld,v.vertex);
UNITY_TRANSFER_LIGHTING(o,v.texcoord1.xy);
UNITY_TRANSFER_FOG(o,o.pos);
return o;
}
fixed4 frag(v2f i):SV_Target
{
UNITY_EXTRACT_FOG(i);
float3 worldPos = i.worldPos.xyz;
float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));
SurfaceOutputStandard o;
UNITY_INITIALIZE_OUTPUT(SurfaceOutputStandard,o);
o.Albedo = tex2D(_MainTex,i.uv.xy) * _Color;
float3 norTex = UnpackNormal(tex2D(_NormalTex, i.uv));
o.Normal = fixed3(dot(i.tSpace1,norTex),dot(i.tSpace2,norTex),dot(i.tSpace3,norTex));
o.Emission = 0;
o.Metallic = tex2D(_MetallicTex,i.uv).r * _Metallic;
o.Smoothness = _Smoothness;
o.Occlusion = tex2D(_AOTex,i.uv).r * _AO;
o.Alpha = 1;
UNITY_LIGHT_ATTENUATION(atten, i, worldPos);
UnityGI gi;
UNITY_INITIALIZE_OUTPUT(UnityGI,gi);
gi.indirect.diffuse = 0;
gi.indirect.specular = 0;
gi.light.color = _LightColor0.rgb;
gi.light.dir = _WorldSpaceLightPos0;
UnityGIInput giInput;
UNITY_INITIALIZE_OUTPUT(UnityGIInput,giInput);
giInput.light = gi.light;
giInput.worldPos = worldPos;
giInput.worldViewDir = worldViewDir;
giInput.atten = atten;
#if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXED
giInput.ambient = i.sh;
#else
giInput.ambient = 0.0;
#endif
giInput.probeHDR[0] = unity_SpecCube0_HDR;
giInput.probeHDR[1] = unity_SpecCube1_HDR;
#if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
giInput.boxMin[0] = unity_SpecCube0_BoxMin;
#endif
LightingStandard_GI(o,giInput,gi);
fixed4 c = LightingStandard(o,worldViewDir,gi);
UNITY_APPLY_FOG(_unity_fogCoord,c);
return c;
}
ENDCG
CGInc-GI部分
主要是对LightingStandard_GI的解析
它就是去拿了全局烘焙贴图,当做漫反射
然后再去拿反射贴图(反射探针)烘焙出来的环境光贴图,当做高光反射
GI.cginc
#ifndef UNITY_SPECCUBE_LOD_STEPS
#define UNITY_SPECCUBE_LOD_STEPS (6)
#endif
#include "UnityLightingCommon.cginc"
//源自UnityPBSLighting.cginc
struct SurfaceOutputStandard
{
fixed3 Albedo;
float3 Normal;
half3 Emission;
half Metallic;
half Smoothness;
half Occlusion;
fixed Alpha;
};
//源自...不重要
struct Unity_GlossyEnvironmentData
{
half roughness;
half3 reflUVW;
};
//读取高光环境贴图
half3 Unity_GlossyEnvironment(UNITY_ARGS_TEXCUBE(tex), half4 hdr, Unity_GlossyEnvironmentData glossIn)
{
//计算粗糙度,0-1区间是个上凸曲线
half perceptualRoughness = glossIn.roughness;
perceptualRoughness = perceptualRoughness*(1.7 - 0.7*perceptualRoughness);
//根据粗糙度去决定读取哪个mipmap,及LOD
half mip = perceptualRoughness * UNITY_SPECCUBE_LOD_STEPS;
//反射方向
half3 R = glossIn.reflUVW;
//读取高光环境贴图
half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(tex, R, mip);
return DecodeHDR(rgbm, hdr);
}
//获取高光反射部分
half3 UnityGI_IndirectSpecular(UnityGIInput data, half occlusion, Unity_GlossyEnvironmentData glossIn)
{
half3 specular = Unity_GlossyEnvironment (UNITY_PASS_TEXCUBE(unity_SpecCube0), data.probeHDR[0], glossIn);
return specular * occlusion;
}
//获取漫反射部分
void UnityGI_Base(UnityGIInput data, half occlusion, half3 normalWorld, inout UnityGI gi)
{
//如果有烘焙光照,就去读Baked贴图
#if defined(LIGHTMAP_ON)
half4 bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, data.lightmapUV.xy);
half3 bakedColor = DecodeLightmap(bakedColorTex);
#ifdef DIRLIGHTMAP_COMBINED
fixed4 bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER (unity_LightmapInd, unity_Lightmap, data.lightmapUV.xy);
gi.indirect.diffuse += DecodeDirectionalLightmap (bakedColor, bakedDirTex, normalWorld);
#endif
#endif
//将衰减应用于灯光颜色在
gi.light.color *= data.atten;
//环境光遮蔽
gi.indirect.diffuse *= occlusion;
}
//获取全局光照
void UnityGlobalIllumination(SurfaceOutputStandard s, UnityGIInput data, inout UnityGI gi)
{
//获取漫反射部分
UnityGI_Base(data, s.Occlusion, s.Normal, gi);
//获得一个粗糙度和反射方向
Unity_GlossyEnvironmentData glossIn;
glossIn.roughness = 1 - s.Smoothness;
glossIn.reflUVW = reflect(-data.worldViewDir, s.Normal);
//获取高光反射
gi.indirect.specular = UnityGI_IndirectSpecular(data, s.Occlusion, glossIn);
}
//套一层,主要这是Unity内置方法的魔改
void LightingStandard_GI(SurfaceOutputStandard s, UnityGIInput data, inout UnityGI gi)
{
//将数据传入
UnityGlobalIllumination(s, data, gi);
}
标签:PBR,UNITY,half,float3,data,gi,giInput From: https://www.cnblogs.com/LateUpdate/p/17974061