我试图添加GGX和PBR纹理到我的GPU射线追踪器。结果很奇怪,每一帧都变暗了。


float ao = texAO.sample(textureSampler, hitRecord.uv).r;
float3 albedo = texAlbedo.sample(textureSampler, hitRecord.uv).rgb;
albedo = pow(albedo, 2.2); //albedo = float3(1.0);
float metallic = texMetallic.sample(textureSampler, hitRecord.uv).r;
float3 tNormal = texNormal.sample(textureSampler, hitRecord.uv).xyz;
tNormal = normalize(tNormal * 2 - 1);
float roughness = texRoughness.sample(textureSampler, hitRecord.uv).r;
roughness = max(roughness, 0.001);
float3 nx, ny;
CoordinateSystem(normal, nx, ny);
float3x3 stw = { nx, ny, normal };
normal = stw * tNormal;
CoordinateSystem(normal, nx, ny);
stw = { nx, ny, normal };
float3 wi, wh;
float3 wo = transpose(stw) * (ray.direction);
auto pSpecular = 1/(2-metallic);
auto r0 = randomF(seed);
auto r1 = randomF(seed);
if (randomF(seed) > pSpecular) {
float sinTheta = sqrt(r0);
float cosTheta = sqrt(1-r0);
float phi = 2.0 * M_PI_F * r1;
float x = sinTheta * cos(phi);
float y = sinTheta * sin(phi);
float z = cosTheta;
wi = { x, y, z };
wh = normalize(wo + wi); // not specular
} else {
auto a1 = roughness;
auto a2 = a1 * a1;
auto theta = acos(sqrt((1-r0) / ((a2-1)*r0+1)));
auto phi = 2 * M_PI_F * r1;
auto x = sin(theta) * cos(phi);
auto y = sin(theta) * sin(phi);
auto z = cos(theta) * 1;
//wo = transpose(stw) * (ray.direction);
wh = normalize( {x, y, z} );
wi = reflect(wo, wh);
}
if (wi.z <= 0 || dot(wh, wi) <= 0) { return false; }
auto D = NDF(wh, roughness);
auto G = GX(wo, wi, roughness);
auto F = FX(wi, wh, albedo, metallic);
float denominator = 4.0f * abs(wo.z * wi.z);
auto specular = D * G * F / max(FLT_MIN, denominator);
auto diffuse = albedo / M_PI_F;
auto kS = F;
auto kD = (1 - metallic) * (1.0f - kS);
ray = Ray(hitRecord.p, stw * wi);
scatRecord.attenuation = (kD * diffuse + specular) * ao;
//auto pdf = PDF(wh, roughness);
//scatRecord.attenuation /= abs(pdf);
return true;// Normal Distribution Function
float NDF(const thread float3& h, float roughness) {
// GGX / Trowbridge-Reitz
float a1 = roughness;
float a2 = a1 * a1;
float NoH = abs(h.z);
float d = (NoH * a2 - NoH) * NoH + 1;
return a2 / (d * d * M_PI_F);
}
// Geometry Function
float GX(const thread float3& wo, const thread float3& wi, float roughness) {
// Schlick, remap roughness and k
if (wo.z >= 0 || wi.z <= 0)
return 0;
float k = pow(roughness + 1, 2) / 8.f;
k = pow(roughness, 4);
float G1_wo = wo.z / (wo.z*(1 - k) + k);
float G1_wi = wi.z / (wi.z*(1 - k) + k);
return G1_wo * G1_wi;
}
// Fresnel
float3 FX(const thread float3& wi, const thread float3& h, const thread float3 albedo, float metallic) {
// Schlick’s approximation
// use a Spherical Gaussian approximation to replace the power.
// slightly more efficient to calculate and the difference is imperceptible
float3 F0 = mix(float3(0.04f), albedo, metallic);
float HoWi = dot(h, wi);
return F0 + (float3(1.0f) - F0) * pow(2.0f, (-5.55473f * HoWi - 6.98316f) * HoWi);
}发布于 2020-09-02 17:57:42
http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.htm -这里引用不同的几何阴影方程
http://jcgt.org/published/0003/02/03/paper.pdf -解释G项是如何工作的,以及它是建立在什么假设上的。
再次查看您的代码,我不确定(基于Karis博客的第一个链接)您的G项计算是否正确。
float k = pow(roughness + 1, 2) / 8.f;
k = pow(roughness, 4);你用粗糙^4覆盖k,它不属于任何Schlick方程,可以在Karis博客上看到,如果我没记错的话,我在任何论文中都没有看到过。另一个注意事项是,您要将ω_o和ω_i传递给您的几何函数,但是基于您关于这是Schlick和总体上下文的评论,我认为您应该使用NoL和NoV (点优先pointToLight方向,然后是viewDir)。
我试图做我自己的图像,但我找到了论文,它总结了史密斯G模型是如何工作的(请看图1) - https://www.microsoft.com/en-us/research/wp-content/uploads/1977/01/p192-blinn.pdf#page=2&zoom=auto,-264,459
不久前,我玩了一些不同的D,F,G方程-- https://github.com/komilll/dxFramework/blob/master/dxFramework/Shaders/PS_BRDF.hlsl --看看PS_BRDF.hlsl和PS_BRDF_Helper.hlsl,以供进一步参考。我把我的方程式建立在Karis博客上,有些是基于其他的文章修改的,比如Frostbite和Disney都是基于各自的文章,如果我没记错的话。
我不确定这是否引起了问题,但这是值得肯定的。另外,我不认为你是用来总结框架的
(previous_average * frame_count + current_color) / (frame_count + 1) 都是正确的,无论是统一的还是重要的GGX取样。在这种情况下,您应该派生pdf,它可以在我之前发送给您的链接中找到-- http://cwyman.org/code/dxrTutors/tutors/Tutor14/tutorial14.md.html --它通常是一个很好的教程,并且一步一步地介绍DXR。
发布于 2020-09-02 21:06:17
尽管对G进行了讨论,但仍然存在两个主要问题。修好他们就能解决问题。
wo和wi在法线方向上应位于同一半球。其中之一应该是reverse射线方向。我看到的大多数文件都忽略了这一部分。尽管如此,PBRT-v3中的这一章帮助我解决了这个问题。http://www.pbr-book.org/3ed-2018/Reflection_模型/微面_Models.html

https://computergraphics.stackexchange.com/questions/10176
复制相似问题