UnrealEngine4 PBR Shading Model 概述
首先,PBR最大的特点还是引入了微平面概念








World Space BF Normals 24bpp + Glossiness 8bpp RT1
D24S8 Depth + Stencil bits for tagging indoor surfaces 8pp RT0





float3 ImportanceSampleGGX( float2 Xi, float Roughness , float3 N )
{
float a = Roughness * Roughness;
float Phi = * PI * Xi.x;
float CosTheta = sqrt( ( - Xi.y) / ( + (a*a - ) * Xi.y ) );
float SinTheta = sqrt( - CosTheta * CosTheta );
float3 H;
H.x = SinTheta * cos( Phi );
H.y = SinTheta * sin( Phi );
H.z = CosTheta;
float3 UpVector = abs(N.z) < 0.999 ? float3(,,) : float3(,,);
float3 TangentX = normalize( cross( UpVector , N ) );
float3 TangentY = cross( N, TangentX );
// Tangent to world space
return TangentX * H.x + TangentY * H.y + N * H.z;
}
float3 SpecularIBL( float3 SpecularColor , float Roughness , float3 N, float3 V )
{
float3 SpecularLighting = ;
const uint NumSamples = ;
for( uint i = ; i < NumSamples; i++ )
{
float2 Xi = Hammersley( i, NumSamples );
float3 H = ImportanceSampleGGX( Xi, Roughness , N );
float3 L = * dot( V, H ) * H - V;
float NoV = saturate( dot( N, V ) );
float NoL = saturate( dot( N, L ) );
float NoH = saturate( dot( N, H ) );
float VoH = saturate( dot( V, H ) );
if( NoL > )
{
float3 SampleColor = EnvMap.SampleLevel( EnvMapSampler , L, ).rgb;
float G = G_Smith( Roughness , NoV, NoL );
float Fc = pow( - VoH, );
float3 F = ( - Fc) * SpecularColor + Fc;
// Incident light = SampleColor * NoL
// Microfacet specular = D*G*F / (4*NoL*NoV)
// pdf = D * NoH / (4 * VoH)
SpecularLighting += SampleColor * F * G * VoH / (NoH * NoV);
}
}
return SpecularLighting / NumSamples;
}
上面是计算Specular间接光的shader 伪代码,1024次对实时的GPU来说还是很难的,需要对公式做拆分

float3 PrefilterEnvMap( float Roughness , float3 R )
{
float3 N = R;
float3 V = R;
float3 PrefilteredColor = ;
const uint NumSamples = ;
for( uint i = ; i < NumSamples; i++ )
{
float2 Xi = Hammersley( i, NumSamples );
float3 H = ImportanceSampleGGX( Xi, Roughness , N );
float3 L = * dot( V, H ) * H - V;
float NoL = saturate( dot( N, L ) );
if( NoL > )
{
PrefilteredColor += EnvMap.SampleLevel( EnvMapSampler , L, ).rgb * NoL;
TotalWeight += NoL;
}
}
return PrefilteredColor / TotalWeight;
}PrefilterEnvMap生成部分的shader代码。



float2 IntegrateBRDF( float Roughness , float NoV )
{
float3 V;
V.x = sqrt( 1.0f - NoV * NoV ); // sin
V.y = ;
V.z = NoV; // cos
float A = ;
float B = ;
const uint NumSamples = ;
for( uint i = ; i < NumSamples; i++ )
{
float2 Xi = Hammersley( i, NumSamples );
float3 H = ImportanceSampleGGX( Xi, Roughness , N );
float3 L = * dot( V, H ) * H - V;
float NoL = saturate( L.z );
float NoH = saturate( H.z );
float VoH = saturate( dot( V, H ) );
if( NoL > )
{
float G = G_Smith( Roughness , NoV, NoL );
float G_Vis = G * VoH / (NoH * NoV);
float Fc = pow( - VoH, );
A += ( - Fc) * G_Vis;
B += Fc * G_Vis;
}
}
return float2( A, B ) / NumSamples;
}
最后把第一部分pre-fileter的cubemap和第2部分计算的部分相乘,就都出IBL的最终结果了
float3 ApproximateSpecularIBL( float3 SpecularColor , float Roughness , float3 N, float3 V )
{
float NoV = saturate( dot( N, V ) );
float3 R = * dot( V, N ) * N - V;
float3 PrefilteredColor = PrefilterEnvMap( Roughness , R );
float2 EnvBRDF = IntegrateBRDF( Roughness , NoV );
return PrefilteredColor * ( SpecularColor * EnvBRDF.x + EnvBRDF.y );
}
这里需要注意一点 : EPIC在ppt里提供的shader代码,并不是实际运行的代码,也就是说PrefilterEnvMap和 IntegrateBRDF这两个函数还是ALU方式的实现,而实际上是应该用LUT的方式来替换的。也就是下面的shader代码
half3 EnvBRDF( half3 SpecularColor, half Roughness, half NoV )
{
// Importance sampled preintegrated G * F
float2 AB = Texture2DSampleLevel( PreIntegratedGF, PreIntegratedGFSampler, float2( NoV, Roughness ), ).rg;
// Anything less than 2% is physically impossible and is instead considered to be shadowing
float3 GF = SpecularColor * AB.x + saturate( 50.0 * SpecularColor.g ) * AB.y;
return GF;
}
PreIntegratedGF就是我们前面提到的那张红绿的LUT图,这里最后算得的结果,才是UE4最终选择的近似方案,也是

floatMip=ComputeCubemapMipFromRoughness(GBuffer.Roughness,AmbientCubemapMipAdjust.w );
float3SampleColor=TextureCubeSampleLevel(AmbientCubemap,AmbientCubemapSampler, R,Mip).rgb; SpecularContribution+=SampleColor*EnvBRDF(GBuffer.SpecularColor,GBuffer.Roughness,NoV);再把结果相乘,就得到了最终的Specular的颜色。







float a0( float g, float NoV )
{
float t1 = 11.4 * pow( g, ) + 0.1;
float t2 = NoV + ( 0.1 – 0.09 * g );
return ( – exp( -t1 * t2 ) ) * 1.32 * exp2( -10.3 * NoV );
} float a1( float g, gloat NoV )
{
float t1 = max( 1.336 – 0.486 * g, );
float t2 = 0.06 + 3.25 * g + 12.8 * pow( g, );
float t3 = NoV + min( 0.125 – 0.1 * g, 0.1 );
return min( t1 – exp2( -t2 * t3 ), );
}
并进一步的做优化
float a0f( float g, float NoV )
{
float t1 = 0.095 + g * ( 0.6 + 4.19 * g );
float t2 = NoV + 0.025;
return t1 * t2 * exp2( – * NoV );
}
float a1f( float g, float NoV )
{
float t1 = 9.5 * g * NoV;
return 0.4 + 0.6 * ( – exp2( -t1 ) );
}rf0(ground truth)是点线,a0是实线,a0f是线段


float a004( float g, float NoV )
{
float t = min( 0.475 * g, exp2( -9.28 * NoV ) );
return ( t + 0.0275 ) * g + 0.015;
}ground truth rf0 =0.04是点线 a004是实线
float a1vf( float g )
{
return 0.25 * g + 0.75;
}
再用a004和a1vf算出新的a0r
float a0r( float g, float NoV )
{
return ( a004( g, NoV ) - a1vf( g ) * 0.04 ) / 0.96;
}至此,a0和a1的最终近似版本也完成了,前面我们提到实际计算就是关于rf0的插值运算
这里我们把rf0提出来
rf0 * a1+ (1-rf0) * a0 = rf0 (a1 - a0) + a0 ,那么最后的Environment BRDF近似公式
float3 EnvironmentBRDF( float g, float NoV, float3 rf0 )
{
float4 t = float4( /0.96, 0.475, (0.0275 - 0.25 * 0.04)/0.96, 0.25 );
t *= float4( g, g, g, g );
t += float4( , , (0.015 - 0.75 * 0.04)/0.96, 0.75 );
float a0 = t.x * min( t.y, exp2( -9.28 * NoV ) ) + t.z;
float a1 = t.w;
return saturate( a0 + rf0 * ( a1 - a0 ) );
}OP2的近似方法就先讲到这里了,PPT的公式推导还是太简单,建议还是看notebook的吧,如果有问题可以留言给我讨论
half3 EnvBRDFApprox( half3 SpecularColor, half Roughness, half NoV )
{
const half4 c0 = { -, -0.0275, -0.572, 0.022 };
const half4 c1 = { , 0.0425, 1.04, -0.04 };
half4 r = Roughness * c0 + c1;
half a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
half2 AB = half2( -1.04, 1.04 ) * a004 + r.zw;
return SpecularColor * AB.x + AB.y;
}材质为非金属时的近似公式
half EnvBRDFApproxNonmetal( half Roughness, half NoV )
{
// Same as EnvBRDFApprox( 0.04, Roughness, NoV )
const half2 c0 = { -, -0.0275 };
const half2 c1 = { , 0.0425 };
half2 r = Roughness * c0 + c1;
return min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
}在非金属的情况下,Specular没有颜色而只是一个亮度,这里就假设为0.04了
DiffuseColor+=SpecularColor*0.45;
SpecularColor=;
下面是和使用黑色行动2里的拟合方式的对比效果


UnrealEngine4 PBR Shading Model 概述的更多相关文章
- 基于Shading Model(对光照变化一定不变性)的运动目标检测算法
光照模型(Shading Model)在很多论文中得到了广泛的应用,如robust and illumination invariant change detection based on linea ...
- [UE4] Adding a custom shading model
转自:https://blog.felixkate.net/2016/05/22/adding-a-custom-shading-model-1/ This was written in Februa ...
- 【计算机视觉】基于Shading Model(对光照变化一定不变性)的运动目标检测算法
光照模型(Shading Model)在很多论文中得到了广泛的应用,如robust and illumination invariant change detection based on linea ...
- object model 概述
Object Model 综述 标准 C++ 的对象模型为对象的动态特性提供了运行时的支持. 但是它静态的本性决定了在某些领域它表现出僵化.不可扩展的特点. GUI编程就是一个既需要运行时编译的效率, ...
- 2.MVC基础-Model概述(思维导图)
已思维导图形式,便于记忆和补充
- 由浅入深学习PBR的原理和实现
目录 一. 前言 1.1 本文动机 1.2 PBR知识体系 1.3 本文内容及特点 二. 初阶:PBR基本认知和应用 2.1 PBR的基本介绍 2.1.1 PBR概念 2.1.2 与物理渲染的差别 2 ...
- CSharpGL(54)用基于图像的光照(IBL)来计算PBR的Specular部分
CSharpGL(54)用基于图像的光照(IBL)来计算PBR的Specular部分 接下来本系列将通过翻译(https://learnopengl.com)这个网站上关于PBR的内容来学习PBR(P ...
- PBR(基于物理的渲染)学习笔记
PBR基本介绍 PBR代表基于物理的渲染,本质上还是 gl_FragColor = Emssive + Ambient + Diffuse + Specular 可能高级一些在考虑下AO也就是环境光遮 ...
- PBR(基于物理的渲染)学习笔记2
相关资料 https://www.cnblogs.com/dojo-lzz/p/13237686.html 文档:PBR学习笔记.note 链接:http://note.youdao.com/note ...
随机推荐
- DRF如何序列化外键的字段
我觉得在有些应用场景下,这个操作是有用的,因为可以减少一个AJAX的请求,以增加性能. 当然,是二次请求,还是一次传输.这即要考虑用户体验,还要兼顾服务器性能. 一切是有条件的平衡吧.就算是一次传输, ...
- 浅析十三种常用的数据挖掘的技术&五个免费开源的数据挖掘软件
一.前 沿 数据挖掘就是从大量的.不完全的.有噪声的.模糊的.随机的数据中,提取隐含在其中的.人们事先不知道的但又是潜在有用的信息和知识的过程.数据挖掘的任务是从数据集中发现模式,可以发现的模式有很多 ...
- oracle插入数据
插入数据 insert into comm_error_code_def (ID, ERR_MESSAGE, ERR_CODE, ERR_DESC, NAME, MISC_DESC, STATUS, ...
- flume与Mosquitto的集成
文章来自:http://www.cnblogs.com/hark0623/p/4173714.html 转发请注明 因业务需求,需要flume收集MQTT(Mosquitto)的数据. 方法就是 ...
- 思维 UVALive 3708 Graveyard
题目传送门 /* 题意:本来有n个雕塑,等间距的分布在圆周上,现在多了m个雕塑,问一共要移动多少距离: 思维题:认为一个雕塑不动,视为坐标0,其他点向最近的点移动,四舍五入判断,比例最后乘会10000 ...
- ubuntu 重置密码
背景:在登陆ubuntu之后,按Ctr+Alt+F1进入控制台时,需要登陆,一时忘了密码... 参考:http://www.cnblogs.com/relaxgirl/p/3179507.html ...
- 使用“Empty 模式”改进 Null Object
概述 Null Object 是Martin 大师提出的一种重构手段,其思想就是通过多态(派生一个Null对象)来减少逻辑(if … then …else)的判断. 而.NET中已经有Null Obj ...
- xml文件读写
创建xml文件,对xml文件进行添加新节点.删除节点.更新节点.创建的如下的xml文件. <?xml version="1.0" encoding="UTF-8&q ...
- 利用CSS3 中steps()制用动画
.monster { width: 190px; height: 240px; margin: 2% auto; background: url('http://treehouse-code-samp ...
- Flex 4中组件背景设置(填充方式)group为例子
以下以Group为例子讲述如何在Flex 4中填充背景颜色.图片: 1.图片填充方式: <s:Group x="0" y="0" height=" ...