根据 Phong 模型进行着色时,镜面反射周围出现奇怪的环

问题描述 投票:0回答:1

我正在使用 Phong 照明模型编写光线追踪器和着色器。在此示例中,我的材料没有任何环境术语。当我渲染时,我得到以下图像:

diffuse and specularity render

如您所见,镜面反射周围似乎有一个较浅的环。如果我完全禁用镜面反射并仅渲染漫反射,我将获得以下结果:

diffuse only render

所以,只有当我引入镜面反射时才会发生这种情况。我已经做过多次阴影处理,但以前从未见过这种情况。整个着色代码如下(我标准化了比我需要的更多的向量,只是为了确保这不是问题):

glm::vec3 shading(std::shared_ptr<scene::scene> scene, std::shared_ptr<hit> hit, uint16_t level)
{
    glm::vec3 normal = glm::normalize(hit->normal);
    glm::vec3 result = hit->mat->ka; // Initialize ambient lighting with unit (global) intensity.
    glm::vec3 point = hit->r.origin + (glm::normalize(hit->r.direction) * hit->t); // Surface vertex.
    glm::vec3 viewing = glm::normalize(scene->camera_pos - point); // Direction vector to the camera.
    // Iterate through every light source in the scene, as this contributes to the overall lighting.
    for (auto& light_source : scene->lights)
    {
        glm::vec3 light = glm::normalize(light_source.position - point); // Direction vector to the light.
        // Calculate diffuse.
        float diffuse_dot = glm::dot(normal, light); // N . L
        if (diffuse_dot > 0.0f)
        {
            glm::vec3 diffuse = light_source.intensity * (diffuse_dot * hit->mat->kd); // Compute diffuse component.
            result += diffuse; // Add diffuse component to result.
        }
        // Calculate specularity.
        glm::vec3 reflected = glm::reflect(-light, normal); // GLM takes opposite light vector.
        float specularity_dot = glm::dot(viewing, reflected); // R . V
        if (specularity_dot > 0.0f)
        {
            float specularity_coefficient = glm::pow(specularity_dot, hit->mat->ns); // Add specularity component to result.
            glm::vec3 specularity = light_source.intensity * (specularity_coefficient * hit->mat->ks);
            result += specularity; // Add specularity.
        }
    }
    return glm::clamp(result, 0.0f, 1.0f);
}

颜色写入PPM文件,每个像素写入如下:

// Writes the color; currently not thread safe.
void write_color(std::ostream& out, glm::vec3& color)
{
    out << static_cast<int>(255.999 * color.x) << ' '
        << static_cast<int>(255.999 * color.y) << ' '
        << static_cast<int>(255.999 * color.z) << '\n';
}

最后材质定义如下:

static std::shared_ptr<rt::material> material_blue = std::make_shared<rt::material>(
    glm::vec3{ 0.0f }, // Ka
    glm::vec3{ 0.0f, 0.0f, 1.0f }, // Kd
    glm::vec3{ 1.0f, 1.0f, 1.0f }, // Ks
    10.0f, // Ns/Shininess/the power the specularity is raised to
    // -snip-
);

我怀疑这可能与

glm::clamp
有关。如果我最后将代码更改为下面的代码,我会得到如下所示的调试渲染。

if (result.x > 1.0f || result.y > 1.0f || result.z > 1.0f)
{
    return glm::vec3{ 1.0f, 0.0f, 0.0f };
}
return glm::clamp(result, 0.0f, 1.0f);

debug render

这个形状看起来与这个戒指的轮廓非常熟悉。因此我怀疑这可能是与夹紧相关的问题,但无数个小时的调试并没有让我更进一步。

TL;DR 我的镜面反射周围有一个奇怪的“环”(参见第一张图片),我想知道如何摆脱它。

c++ glm-math raytracing phong
1个回答
0
投票

Phong 模型是现象学的,不是基于物理的,因此它可能会产生一些伪影。这个环是“正常的”,为了验证这一点,您可以使用 OpenGL 1.x 重新创建相同的场景(固定管道,因此 Phong 模型位于驱动程序中,如果您不必编写代码,则不会引入错误它)。

我认为主要原因可能与缺乏能量守恒定律有关(因此需要夹紧,这可能会加剧一些缺陷)。如果你尝试从 PBR 模型中借鉴一些节能思想,问题就会消失。作为一个简单的想法,您可以说认为同一“光能”(比如说光子)不能同时添加镜面反射和漫反射。一个可以大大改善这种情况的简单补丁是使用 1-specularity_coefficient 对漫反射项进行加权,因此我们确保两个贡献之和最多为 1。

© www.soinside.com 2019 - 2024. All rights reserved.