graphics - PBR - 不正确的直接照明
问题描述
基于许多互联网资源,我为我的 DirectX 11 游戏引擎编写了定向照明的 PBR 实现,但它工作不正确。
贝娄,你可以看到我强制金属度为0.0f和粗糙度为1.0f的屏幕截图。如您所见,反射太多。例如,草的反射性很强,但粗糙度设置为0,所以看起来不应该那样。
贝娄,我可视化了环境光照,它看起来是正确的。
不幸的是,directLighting似乎完全关闭了,我不知道为什么。有太多的反思。可能是因为我为定向光源错误地应用了 PBR 公式,但我不知道如何使它正确。
这是我的 PBR 源代码。我希望你能帮助我解决这个问题,或者至少给我一个提示,问题可能出在哪里,说实话,我现在不知道如何解决它。
static const float PI = 3.14159265359f;
static const float3 DIELECTRIC_FACTOR = float3(0.04f, 0.04f, 0.04f);
static const float EPSILON = 0.00001f;
float DistributionGGX(float3 normal, float3 halfway, float roughness)
{
float alpha = roughness * roughness;
float alphaSquare = alpha * alpha;
float cosHalfway = max(dot(normal, halfway), 0.0f);
float cosHalfwaySquare = cosHalfway * cosHalfway;
float denominator = (cosHalfwaySquare * (alphaSquare - 1.0f)) + 1.0f;
denominator = PI * denominator * denominator;
return alphaSquare / denominator;
}
float GeometrySchlickGGX(float cosinus, float roughness)
{
float r = (roughness + 1.0);
float k = (r * r) / 8.0;
float denominator = cosinus * (1.0 - k) + k;
return cosinus / denominator;
}
float GeometrySmith(float3 normal, float roughness, float cosView, float cosLight)
{
return GeometrySchlickGGX(cosView, roughness) * GeometrySchlickGGX(cosLight, roughness);
}
float3 FresnelSchlick(float cosTheta, float3 F0)
{
return F0 + (1.0f - F0) * pow(1.0f - cosTheta, 5.0f);
}
float3 FresnelSchlickRoughness(float cosTheta, float3 F0, float roughness)
{
return F0 + (max(float(1.0f - roughness).xxx, F0) - F0) * pow(1.0f - cosTheta, 5.0f);
}
int GetTextureMipMapLevels(TextureCube input)
{
int width, heigth, levels;
input.GetDimensions(0, width, heigth, levels);
return levels;
}
float3 Pbr(float3 albedo, float3 normal, float metallic, float roughness, float occlusion,
TextureCube irradianceTexture, TextureCube radianceTexture, Texture2D brdfLut,
SamplerState defaultSampler, SamplerState brdfSampler, float3 lightDirection,
float3 lightColor, float3 cameraPosition, float3 pixelPosition, float shadowMultiplier)
{
lightDirection *= -1;
float3 viewDirection = normalize(cameraPosition - pixelPosition);
float3 halfwayDirection = normalize(viewDirection + lightDirection);
float3 reflectionDirection = reflect(-viewDirection, normal);
float3 F0 = lerp(DIELECTRIC_FACTOR, albedo, metallic);
float cosView = max(dot(normal, viewDirection), 0.0f);
float cosLight = max(dot(normal, lightDirection), 0.0f);
float NDF = DistributionGGX(normal, halfwayDirection, roughness);
float G = GeometrySmith(normal, roughness, cosView, cosLight);
float3 F = FresnelSchlick(max(dot(halfwayDirection, viewDirection), 0.0f), F0);
float3 nominator = NDF * G * F;
float denominator = 4 * cosView * cosLight + EPSILON;
float3 specular = nominator / denominator;
float3 kD = lerp(float3(1.0f, 1.0f, 1.0f) - F, float3(0.0f, 0.0f, 0.0f), metallic);
float3 directLighting = (kD * albedo / PI + specular) * lightColor * cosLight;
F = FresnelSchlickRoughness(cosView, F0, roughness);
kD = lerp(float3(1.0f, 1.0f, 1.0f) - F, float3(0.0f, 0.0f, 0.0f), metallic);
float3 irradiance = irradianceTexture.Sample(defaultSampler, normal).rgb;
float3 diffuse = irradiance * albedo;
int radianceLevels = GetTextureMipMapLevels(radianceTexture);
float3 radiance = radianceTexture.SampleLevel(defaultSampler, reflectionDirection, roughness * radianceLevels).rgb;
float2 brdf = brdfLut.Sample(brdfSampler, float2(cosView, roughness)).xy;
float3 specularColor = radiance * (F0 * brdf.x + brdf.y);
float3 ambientLighting = (kD * diffuse + specularColor) * occlusion;
return ambientLighting + (directLighting * shadowMultiplier);
}
解决方案
推荐阅读
- javascript - 将内联 javascript 转换为 Alpine.js
- reactjs - 如何重定向到其他页面以响应函数中的外部组件
- python - Numpy:难以获得 3D 数组的 2D 切片
- ajax - 如何使用 AJAX 结果更新 Master detail razor 页面中的模型
- sql - PostgreSQL 计算子查询中的行数
- android - 仅在需要时调整文本视图文本大小以适合文本视图大小
- node.js - 在使用 MessageCollector 达到设置的时间限制后如何触发代码?
- php - 来自popen的PHP pid
- firebase - 由于我的应用程序使用密码身份验证,因此上面的代码将在该字段中给我 null
- azure - 如何在 Azure 托管应用程序 ARM 部署中强制选择服务主体