我是靠谱客的博主 复杂羽毛,最近开发中收集的这篇文章主要介绍dot ue4_UE4中的基于物理的着色(二),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

上一节UE4中的基于物理的着色(一)说到得到了主要的BRDF值之后,将要计算最终各个方向光线影响下的辐射度值,漫反射和高光反射分开计算,积分式子都为:

对于漫反射,UE4选择Lambert模型BRDF:

最后要求

为了方便积分,将该式子转成球面坐标系对

积分。

部分看成

为入射方向立体角,根据立体角的定义有部分

,转成球面坐标系后得到:

对半球上

方向均匀的采样或者说用黎曼和的思想积分得到:

为入射光线,需要注意的是这里的

是定义在切空间下的坐标,需要将其转换到世界坐标下再从环境贴图中采样。

对于高光反射,建立在微表面模型下,UE4使用Cook-Torrance模型BRDF:

最后要求

对这个式子使用蒙特卡洛求积分得到:

要估计该式子的值需要从

中入手,不从入射光线

入手,具体原因和式子推导可以参考最后引用部分的文章。

为微表面的法线概率密度函数(未归一化),这个定义的意义不从数学公式看,从直观感受上来说,现实中人眼看到某一微小面积的高光区域同时结合微表面角度来考虑,这片高光区域的入射光线可能是从任意方向来的,但是大部分的光线肯定还是遵循宏观表明的法线

反射,也就是微表面法线

和宏观表面法线

相似的概率大,相差很多的概率小,所以说微表面法线

可以近似一个正太分布的钟形曲线。

在UE4中

的选择为GGX / Trowbridge-Reitz模型

这也是和Disney选择一样,在Physically Based Shading at Disney中对

部分描述如下,可以看到

的大概样子:

所以我们以

分布来进行采样,为了得到 符合

分布的数据,采样求反函数的方法。

的定义我们已经知道了,需要对其进行归一化。

到这一步需要注意到

为两个独立事件,我们需要单独求出

再求在

之下的

最终得到

的表达式,

为随机数,利用低差异序列(low-discrepancy sequence)可以得到分布更加均匀的随机数,简单来说就是随机数生成过程中总是往最还没生成过的区域生成。

通过

的随机结果得到带入表达式得到

再转换坐标系得到

,该

符合

分布的数据,然后通过

之间的关系,调整样本的权重。引用自Surface Reflection: Physical and Geometrical Perspectives有

,这些参数都是在微表面下,

也为

的夹角,所以

实现代码如下:

float3 ImportanceSampleGGX( float2 Xi, float Roughness, float3 N )

{

float a = Roughness * Roughness;

float Phi = 2 * PI * Xi.x;

float CosTheta = sqrt( (1 - Xi.y) / ( 1 + (a*a - 1) * Xi.y ) );

float SinTheta = sqrt( 1 - 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(0,0,1) : float3(1,0,0);

float3 TangentX = normalize( cross( UpVector, N ) );

float3 TangentY = cross( N, TangentX );

// Tangent to world spacereturn TangentX * H.x + TangentY * H.y + N * H.z;

}

float3 SpecularIBL( float3 SpecularColor , float Roughness, float3 N, float3 V )

{

float3 SpecularLighting = 0;

const uint NumSamples = 1024;

for( uint i = 0; i < NumSamples; i++ )

{

float2 Xi = Hammersley( i, NumSamples );

float3 H = ImportanceSampleGGX( Xi, Roughness, N );

float3 L = 2 * 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 > 0 )

{

float3 SampleColor = EnvMap.SampleLevel( EnvMapSampler , L, 0 ).rgb;

float G = G_Smith( Roughness, NoV, NoL );

float Fc = pow( 1 - VoH, 5 );

float3 F = (1 - 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;

}

ImportanceSampleGGX函数运用到最后

的表达式,得到符合

分布的

样本数据,需要注意的是切空间和世界坐标系的转换。SpecularIBL进行1024次采样,计算最后的高光值,Hammersley为获得地差异序列。

到此已经可以估计各个方向的光线漫反射和高光反射对着色的影响,然而对于实时来说,虽然用到了重要性采样,但是采样的数量还是很多,UE4选择的方案将采样数量降为1次。

将最后积分的公式拆分成两部分,进行预处理计算。下一节将继续介绍。

点赞是我最大的动力~

最后

以上就是复杂羽毛为你收集整理的dot ue4_UE4中的基于物理的着色(二)的全部内容,希望文章能够帮你解决dot ue4_UE4中的基于物理的着色(二)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(68)

评论列表共有 0 条评论

立即
投稿
返回
顶部