首先看一下實(shí)際上真實(shí)的效果
再來一張
這是專門去找的。
可以看到絲綢渲染使用了各向異性的GGX去實(shí)現(xiàn),有點(diǎn)仿頭發(fā)的感覺,接下來看一下怎么實(shí)現(xiàn)的。
首先,準(zhǔn)備實(shí)現(xiàn)雙向反射率分布函數(shù)(BRDF)的DVF項(xiàng)。
D項(xiàng)使用UE里面的各項(xiàng)異性GGX:
// [Burley 2012, "Physically-Based Shading at Disney"]
float D_GGXaniso(float ax, float ay, float NoH, float XoH, float YoH)
{
float a2 = ax * ay;
float3 V = float3(ay * XoH, ax * YoH, a2 * NoH);
float S = dot(V, V);
return(1.0f / PI) * a2 * Square(a2 / S);
}
V項(xiàng)使用配合D項(xiàng)的Vis_SmithJointAniso
// [Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs"]
float Vis_SmithJointAniso(float ax, float ay, float NoV, float NoL, float XoV, float XoL, float YoV, float YoL)
{
float Vis_SmithV = NoL * length(float3(ax * XoV, ay * YoV, NoV));
float Vis_SmithL = NoV * length(float3(ax * XoL, ay * YoL, NoL));
return 0.5 * rcp(Vis_SmithV + Vis_SmithL);
}
這個(gè)函數(shù)里面的x就是tangent y就是bitangent 中間的o就是dot計(jì)算結(jié)果
F項(xiàng)使用UE里面的F項(xiàng):
// [Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"]
float3 F_Schlick_UE4(float3 SpecularColor, float VoH)
{
float Fc = Pow5(1 - VoH); // 1 sub, 3 mul
//return Fc + (1 - Fc) * SpecularColor; // 1 add, 3 mad
// Anything less than 2% is physically impossible and is instead considered to be shadowing
return saturate(50.0 * SpecularColor.g) * Fc + (1 - Fc) * SpecularColor;
}
使用DVF項(xiàng)實(shí)現(xiàn)雙向反射率分布函數(shù):
float3 SlikBRDF(float3 DiffuseColor, float3 SpecularColor, float Roughness, float Anisotropy,
float3 N, float3 T, float3 B, float3 V, float3 L, float3 LightColor, float Shadow)
{
float Alpha = Roughness * Roughness;
float a2 = Alpha * Alpha;
// Anisotropic parameters: ax and ay are the Roughness along the tangent and bitangent
// Kulla 2017, "Revisiting Physically Based Shading at Imageworks"
float ax = max(Alpha * (1.0 + Anisotropy), 0.001f);
float ay = max(Alpha * (1.0 - Anisotropy), 0.001f);
float3 H = normalize(L + V);
float NoH = saturate(dot(N, H));
float NoV = saturate(abs(dot(N, V)) + 1e-5);
float NoL = saturate(dot(N, L));
float VoH = saturate(dot(V, H));
float XoV = dot(T, V);
float XoL = dot(T, L);
float XoH = dot(T, H);
float YoV = dot(B, V);
float YoL = dot(B, L);
float YoH = dot(B, H);
float3 Radiance = NoL * LightColor * Shadow * PI;
//直接光漫反射
float3 DiffuseTerm = Diffuse_Lambert(DiffuseColor) * Radiance;
//直接光鏡面反射
float D = D_GGXaniso(ax, ay, NoH, XoH, YoH);
float Vis = Vis_SmithJointAniso(ax, ay, NoV, NoL, XoV, XoL, YoV, YoL);
float3 F = F_Schlick_UE4(SpecularColor, VoH);
float3 SpecularTerm = ((D * Vis) * F) * Radiance;
return DiffuseTerm + SpecularTerm;
}
其它代碼,我們可以直接魔改unity的urp內(nèi)置的lit函數(shù),用于獲取相關(guān)的參數(shù),這里就不再聊了。
那么,你會(huì)發(fā)現(xiàn)一個(gè)問題,因?yàn)镚GXaniso 主要使用的是tangent和bitangent的朝向做高光的,我們平時(shí)做高光的時(shí)候都是使用法向的, 法向貼圖不會(huì)影響這兩個(gè)朝向啊,那么怎么辦,這么辦:
//設(shè)置T和B也受法線貼圖的影響
half3 tangentTS = normalize(surfaceData.normalTS.x * half3(0, 0, 1) * _NormalAniso + half3(1, 0, 0));
half3 T = TransformTangentToWorld(tangentTS, tangentToWorld);
T = NormalizeNormalPerPixel(T);
half3 bitangentTS = normalize(surfaceData.normalTS.y * half3(0, 0, 1) * _NormalAniso + half3(0, 1, 0));
half3 B = TransformTangentToWorld(bitangentTS, tangentToWorld);
B = NormalizeNormalPerPixel(B);
我們用法向的x軸的量去影響切線空間下的切線的向量值,然后再將其轉(zhuǎn)換到世界空間即可。
直接光的函數(shù)運(yùn)算如下:
float3 DirectLighting(float3 DiffuseColor, float3 SpecularColor, float Roughness, float3 WorldPos, float Anisotropy,
float3 N, float3 T, float3 B, float3 V, float4 shadowCoord, float4 shadowMask)
{
//主光源
half3 DirectLighting_MainLight = half3(0, 0, 0);
{
Light light = GetMainLight(shadowCoord, WorldPos, shadowMask);
half3 L = light.direction;
half3 LightColor = light.color;
half Shadow = light.shadowAttenuation;
DirectLighting_MainLight = SlikBRDF(DiffuseColor, SpecularColor, Roughness, Anisotropy, N, T, B, V, L, LightColor, Shadow);
}
//附加光源
half3 DirectLighting_AddLight = half3(0, 0, 0);
#ifdef _ADDITIONAL_LIGHTS
uint pixelLightCount = GetAdditionalLightsCount();
for (uint lightIndex = 0; lightIndex < pixelLightCount; ++lightIndex)
{
Light light = GetAdditionalLight(lightIndex, WorldPos, shadowMask);
half3 L = light.direction;
half3 LightColor = light.color;
half Shadow = light.shadowAttenuation * light.distanceAttenuation;
DirectLighting_AddLight += SlikBRDF(DiffuseColor, SpecularColor, Roughness, Anisotropy, N, T, B, V, L, LightColor, Shadow);
}
#endif
return DirectLighting_MainLight + DirectLighting_AddLight;
}
計(jì)算主光源和附加光源,即可實(shí)現(xiàn)直接光的漫反射和鏡面反射。
這是-0.9的Anisotropy的效果
這是Anisotropy的值為0.9的效果,當(dāng)前的雙向反射率分布函數(shù),如果把Anisotropy設(shè)置為1或者-1,效果上表現(xiàn)會(huì)很差。
環(huán)境光
首先,如果在環(huán)境光鏡面反射上面實(shí)現(xiàn)aniso的效果呢,這里有段代碼:
//根據(jù)設(shè)置的各項(xiàng)異性的強(qiáng)度,對(duì)法向進(jìn)行扭曲,實(shí)現(xiàn)各項(xiàng)異性的環(huán)境高光
float3 anisotropicDirection = Anisotropy >= 0.0 ? B : T;
float3 anisotropicTangent = cross(anisotropicDirection, V);
float3 anisotropicNormal = cross(anisotropicTangent, anisotropicDirection);
float3 bentNormal = normalize(lerp(N, anisotropicNormal, abs(Anisotropy)));
用這個(gè)最終生成的bentNormal去替換之前的計(jì)算反射角度的N,就可以實(shí)現(xiàn)環(huán)境光鏡面反射,效果是這樣的:
為了看效果,我故意把光滑度調(diào)高了。
間接光的實(shí)現(xiàn)函數(shù):文章來源:http://www.zghlxwxcb.cn/news/detail-494918.html
float3 IndirectLighting(float3 DiffuseColor, float3 SpecularColor, float Roughness, float3 WorldPos, float Anisotropy,
float3 N, float3 T, float3 B, float3 V, float Occlusion, float EnvRotation)
{
float NoV = saturate(abs(dot(N, V)) + 1e-5);
//SH
float3 DiffuseAO = AOMultiBounce(DiffuseColor, Occlusion);
float3 RadianceSH = SampleSH(N);
float3 IndirectDiffuse = RadianceSH * DiffuseColor * DiffuseAO;
//根據(jù)設(shè)置的各項(xiàng)異性的強(qiáng)度,對(duì)法向進(jìn)行扭曲,實(shí)現(xiàn)各項(xiàng)異性的環(huán)境高光
float3 anisotropicDirection = Anisotropy >= 0.0 ? B : T;
float3 anisotropicTangent = cross(anisotropicDirection, V);
float3 anisotropicNormal = cross(anisotropicTangent, anisotropicDirection);
float3 bentNormal = normalize(lerp(N, anisotropicNormal, abs(Anisotropy)));
//IBL
half3 R = reflect(-V, bentNormal);
R = RotateDirection(R, EnvRotation);
half3 SpeucularLD = GlossyEnvironmentReflection(R, WorldPos, Roughness, Occlusion);
half3 SpecularDFG = EnvBRDFApprox(SpecularColor, Roughness, NoV);
float SpecularOcclusion = GetSpecularOcclusion(NoV, Pow2(Roughness), Occlusion);
float3 SpecularAO = AOMultiBounce(SpecularColor, SpecularOcclusion);
float3 IndirectSpecular = SpeucularLD * SpecularDFG * SpecularAO;
return IndirectDiffuse + IndirectSpecular;
}
整體的效果:文章來源地址http://www.zghlxwxcb.cn/news/detail-494918.html
到了這里,關(guān)于unity urp 實(shí)現(xiàn)絲綢渲染的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!