首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >光线追踪,为什么GGX会使我的渲染结果变得越来越暗?

光线追踪,为什么GGX会使我的渲染结果变得越来越暗?
EN

Computer Graphics用户
提问于 2020-08-31 22:24:18
回答 2查看 405关注 0票数 0

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

代码语言:javascript
复制
        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;
代码语言:javascript
复制
// 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);
}
EN

回答 2

Computer Graphics用户

发布于 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项计算是否正确。

代码语言:javascript
复制
  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都是基于各自的文章,如果我没记错的话。

我不确定这是否引起了问题,但这是值得肯定的。另外,我不认为你是用来总结框架的

代码语言:javascript
复制
(previous_average * frame_count + current_color) / (frame_count + 1) 

都是正确的,无论是统一的还是重要的GGX取样。在这种情况下,您应该派生pdf,它可以在我之前发送给您的链接中找到-- http://cwyman.org/code/dxrTutors/tutors/Tutor14/tutorial14.md.html --它通常是一个很好的教程,并且一步一步地介绍DXR。

票数 1
EN

Computer Graphics用户

发布于 2020-09-02 21:06:17

尽管对G进行了讨论,但仍然存在两个主要问题。修好他们就能解决问题。

  1. Float16限制在65504。当乘以一个大帧数时,它就会溢出,变成一个小数目,然后就再也不会回来了。https://en.wikipedia.org/wiki/Half-precision_浮点_格式化
  2. 向量wowi在法线方向上应位于同一半球。其中之一应该是reverse射线方向。我看到的大多数文件都忽略了这一部分。尽管如此,PBRT-v3中的这一章帮助我解决了这个问题。

http://www.pbr-book.org/3ed-2018/Reflection_模型/微面_Models.html

票数 0
EN
页面原文内容由Computer Graphics提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://computergraphics.stackexchange.com/questions/10176

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档