【问题标题】:Unidirectional path tracer output is too dark单向路径跟踪器输出太暗
【发布时间】:2022-11-01 10:41:57
【问题描述】:

我正在编写一个在 Windows 上运行的 CPU 光线追踪器。不幸的是,当前的输出似乎太暗了,就像我缺少全局照明一样。

这是一个内部房间,照明来自 2 个窗户。只有一种定向光。光反弹次数设置为 8。

这是我的路径跟踪器输出:

搅拌机循环输出:

虽然直接照明很好,但感觉就像我缺少全局照明。但为什么?

这是示例代码:

RGBColor pathTracing(const Math::Ray& ray, nbUint32 depth)
{
    // Find intersection using intel's Embree
    Intersector::IntersectionInfo isectInfo;
    m_intersector->intersect(ray, isectInfo);

    // Check if an intersection occured
    if (isectInfo.object == nullptr)
    {
        return BlackRGBColor;
    }

    // Get intersection properties
    const auto isectProps = buildIntersectionProperties(ray, isectInfo, m_currentScene);

    // The scene model
    const auto& model = m_currentScene->getModel();

    // Read the material
    const DatabaseMaterialPtr material = model->getMaterialPtr_FromEntity(isectInfo.object->getMaterialId());

    // Compute direct lighning
    RGBColor directCont = BlackRGBColor;
    {
        for (const EntityIdentifier& lightId : m_currentScene->getLights())
        {
            // Generate light sample
            const auto light = Entity::EntityDatabaseSingleton::instance()->getEntity<Light::BaseLight>(lightId);
            const auto sampleToLight = light->generateSampleToLight(isectProps.P);

            const nbFloat32 NoL = glm::dot(isectProps.BsdfProps.N, sampleToLight.L);
            if (NoL <= 0.0f)
                continue;

            // Compute occlusion
            Math::Ray shadowRay(isectProps.deltaP, sampleToLight.L, sampleToLight.length);
            const nbFloat32 occlusionStrength = m_intersector->occlusion(shadowRay);

            if (occlusionStrength != 1.0f)
            {
                // Build the bsdf sample struture
                Material::BaseMaterial::SampleBsdfData bsdfSample;
                bsdfSample.L = sampleToLight.L;
                bsdfSample.V = isectProps.V;
                bsdfSample.NoL = NoL;
                bsdfSample.geoProps = &isectProps.BsdfProps;

                // Sample the brdf to get the scale
                auto sampledBrdf = material.sampleBsdf(bsdfSample);

                // Multiply by light radiance
                sampledBrdf *= light->getColor();

                // Multiply by visibility
                sampledBrdf *= (1.0f - occlusionStrength);

                // Finally add light contribution
                directCont += sampledBrdf;
            }
        }
    }


    // Compute indirect lighning
    RGBColor indirectCont;
    if (++depth <= m_settings.m_maxDepth)
    {
        BaseMaterial::SpawnRayResult newRayData;
        newRayData = material->spawnRay(/* some parameters*/);

        // Build the bsdf sample struture
        Material::BaseMaterial::SampleBsdfData bsdfSample;
        bsdfSample.L = newRayData.ray.getDirection();
        bsdfSample.V = isectProps.V;
        bsdfSample.NoL = glm::dot(newRayData.ray.getDirection(), isectProps.BsdfProps.N);
        bsdfSample.geoProps = &isectProps.BsdfProps;

        // Indirect raytracing
        const Spectrum sampledBrdf = material->sampleBsdf(bsdfSample);
        const Spectrum sampledRadiance = sampledBrdf * pathTracing(newRayData.ray, depth);//recursion

        static const float normalizationFactor = 2.0f * Math::Pi.getValue();
        indirectCont = sampledRadiance * normalizationFactor;
    }

    return directCont + indirectCont;
}

这里还有更多代码 sn-ps。

sampleBsdf 方法

RGBColor BaseMaterial::sampleBsdf(const SampleBsdfData& data) const
{
    DistributionFunction::SampleInput distSampleInput;
    distSampleInput.L = data.L;
    distSampleInput.V = data.V;
    distSampleInput.N = data.geoProps->N;
    distSampleInput.T = data.geoProps->T;
    distSampleInput.B = data.geoProps->B;
    distSampleInput.H = glm::normalize(data.L + data.V);

    distSampleInput.HoN = std::abs(glm::dot(data.geoProps->N, distSampleInput.H));
    distSampleInput.NoV = std::abs(glm::dot(data.geoProps->N, data.V));
    distSampleInput.NoL = data.NoL;


    return sampleBrdf(distSampleInput) * distSampleInput.NoL;
}

sampleBrdf 方法

inline nbFloat32 lambert(const SampleInput& input)
{
    return Math::InvPi.getValue();
}

nbFloat32 blinnPhong(const SampleInput& input, nbFloat32 shininess)
{
    const nbFloat32 HoN = std::min(input.HoN, 0.999f);
    nbFloat32 normalizationFactor = (shininess + 8.0f) * Math::InvPi8.getValue();
    normalizationFactor = glm::clamp(normalizationFactor, 0.0f, 1.0f);

    return std::pow(HoN, shininess) * normalizationFactor;
}

#define NO_FRESNEL_VALUE 0.4f

nbFloat32 DefaultDielectric::sampleFresnel(nbFloat32 HoN) const
{
    if (m_fresnelEnabled)
    {
        // Schlick approximation.
        return glm::clamp(m_fresnel0 + (1.0f - m_fresnel0) * pow(1.0f - HoN, 5.0f), 0.0f, 1.0f);
    }

    return NO_FRESNEL_VALUE;
}

RGBColor DefaultDielectric::sampleBrdf(DistributionFunction::SampleInput& distSampleInput) const
{
    nbFloat32 fresnelFactor = sampleFresnel(distSampleInput.HoN);

    // Diffuse
    nbFloat32 diffuseFactor = lambert(distSampleInput) * (1.0f - fresnelFactor);
    auto diffuseLightning = m_diffuse * diffuseFactor;

    // Specular
    nbFloat32 specularFactor = blinnPhong(distSampleInput, m_glossiness) * fresnelFactor;
    auto specLightning = m_specular * specularFactor;

    return m_opacity * (diffuseLightning + specLightning);
}

【问题讨论】:

  • 即使是图片中的黑暗区域也看起来像半灰色。我会先解决这个问题——为什么最暗的部分不是黑色的?即使您的程序使错误的事物变得明亮和黑暗,仍然应该有黑暗的事物。
  • 感谢您的帮助。我的光线追踪器场景有一个环境术语。但是当我将它设置为零时,它是完全黑暗的:imgur.com/a/vbp1Gg6
  • 我希望光线追踪场景具有直接和反射光以及非常少的环境光。如果你看你的第一张照片,它看起来环境光只是为了让整个图像更亮——就好像你只是给所有的 RGB 值添加了相同的数字。最后一张照片显示来自太阳的直接照明正在工作。问题是为什么反射光如此暗。
  • 我不是光线追踪方面的专家。我猜你已经尝试过让 BSDF 有更大的数字?这似乎太明显了
  • 我刚试过。向 bsdf 添加一个因子肯定会使场景更亮。我将发布缺失部分的代码。

标签: c++ rendering raytracing


【解决方案1】:

应用系数为 1.0/2.2f 的伽马校正会有所帮助,但渲染仍然缺乏全局照明。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-05
    • 1970-01-01
    • 2019-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多