0

我没有看到另一个与我的问题类似的帖子,所以希望这不是多余的。

我一直在阅读一本关于计算机图形学基础的书(第三版),并且我一直在根据我从中学到的原理实现一个基本的光线追踪程序。我在实现平行投影和透视投影时遇到了一点麻烦,但是在使用 Lambertian 和 Blinn-Phong 着色之后,我遇到了一个我自己无法解决的问题。

我相信我的问题与我如何计算射线球交点和相机/灯光的矢量有关。我附上了一张当我运行没有阴影的简单透视投影时输出的图片。

透视输出

然而,当我尝试使用朗伯着色的相同场景时,球体消失了。

空白输出

在尝试自己调试时,我注意到如果我否定计算为命中点的 x、y、z 坐标,球体会再次出现。而且我相信光线来自我预期的相反方向。

朗伯式,无效的生命值

我通过将投影方向矢量和由射线-球体相交公式计算的t值的乘积加到原点(我的“相机”为 0,0,0)或只是e +来计算命中点td _

从命中点到灯光的向量l,我设置为灯光的位置减去命中点的位置(所以命中点的坐标减去灯光的坐标)。

v,从命中点到相机的向量,我通过简单地否定投影视图向量得到;

我得到的表面法线是命中点减去球体的位置。

我认为所有这些都是正确的。但是,在逐步浏览计算表面法线的部分时,我注意到一些我认为很奇怪的东西。当从球体的位置中减去命中点的位置以获得从球体中心到命中点的向量时,我相信我应该期望得到一个向量,其中所有值都在 (-r,r) 范围内;但这并没有发生。

这是逐步执行我的代码的示例:
计算的命中点:(-0.9971, 0.1255, -7.8284)
球体中心:(0, 0, 8)(半径为 1)

减去后,我得到一个 z 值为 -15.8284 的向量。这对我来说似乎是错误的;但我不知道是什么原因造成的。-15.8284 的 z 值是否不意味着球体中心和命中位置在 z 平面上彼此相距约 16 个单位?显然,这两个数字在绝对值方面彼此相差 1,这就是让我认为我的问题与此有关的原因。

这是主要的光线追踪循环:

auto origin = Position3f(0, 0, 0);
for (int i = 0; i < numPixX; i++)
{
    for (int j = 0; j < numPixY; j++)
    {
        for (SceneSurface* object : objects)
        {
            float imgPlane_u = left + (right - left) * (i + 0.5f) / numPixX;
            float imgPlane_v = bottom + (top - bottom) * (j + 0.5f) / numPixY;

            Vector3f direction = (w.negated() * focal_length) + (u * imgPlane_u) + (v * imgPlane_v);

            Ray viewingRay(origin, eye, direction);

            RayTestResult testResult = object->TestViewRay(viewingRay);

            if (testResult.m_bRayHit)
            {
                Position3f hitPoint = (origin + (direction) * testResult.m_fDist);//.negated();

                Vector3f light_direction = (light - hitPoint).toVector().normalized();
                Vector3f view_direction = direction.negated().normalized();
                Vector3f surface_normal = object->GetNormalAt(hitPoint);

                image[j][i] = object->color * intensity * fmax(0, surface_normal * light_direction);
            }
        }
    }
}

GetNormalAt 很简单:

Vector3f Sphere::GetNormalAt(Position3f &surface)
{
    return (surface - position).toVector().normalized();
}

我的球体位于 (0, 0, 8) 和 (-1.5, -1, 6) 处,rad 1.0f。我的光在 (-3, -3, 0) 处,强度为 1.0f;

我忽略了t不大于 0 的任何交集,所以我不认为这是导致此问题的原因。

我认为在将位置和向量保持在同一坐标系中(相同的变换?)时,我可能会犯某种错误,但我仍在学习并且承认不太了解。如果视图方向总是在-w方向,为什么我们将场景对象定位在正w方向?

非常感谢任何帮助或智慧。到目前为止,我都是在自学这些,我对自己学到的东西很满意,但是我的直觉告诉我这是一个相对简单的错误。

以防万一它有任何用处,这里是 TestViewRay 函数:

RayTestResult Sphere::TestViewRay(Ray &viewRay)
{
RayTestResult result;

result.m_bRayHit = false;

Position3f &c = position;
float r = radius;
Vector3f &d = viewRay.getDirection();
Position3f &e = viewRay.getPosition();

float part = d*(e - c);
Position3f part2 = (e - c);
float part3 = d * d;
float discriminant = ((part*part) - (part3)*((part2*part2) - (r * r)));

if (discriminant > 0)
{
    float t_add = ((d) * (part2)+sqrt(discriminant)) / (part3);
    float t_sub = ((d) * (part2)-sqrt(discriminant)) / (part3);

    float t = fmin(t_add, t_sub);

    if (t > 0)
    {
        result.m_iNumberOfSolutions = 2;
        result.m_bRayHit = true;
        result.m_fDist = t;
    }
}
else if (discriminant == 0)
{
    float t_add = ((d)* (part2)+sqrt(discriminant)) / (part3);
    float t_sub = ((d)* (part2)-sqrt(discriminant)) / (part3);

    float t = fmin(t_add, t_sub);

    if (t > 0)
    {
        result.m_iNumberOfSolutions = 1;
        result.m_bRayHit = true;
        result.m_fDist = t;
    }
}

return result;
}

编辑:

我很高兴报告我发现了我的问题。

在和我姐姐坐下来看这个时,我注意到在我的射线球命中检测中我有这个:

float t_add = ((d) * (part2)+sqrt(discriminant)) / (part3);

这是不正确的。d应该是负数。它应该是:

float t_add = ((neg_d * (e_min_c)) + sqrt(discriminant)) / (part2);

(我重命名了几个变量)以前我有一个零向量,所以我可以将 - d表示为 (zero_vector - d ),我已经删除了它,因为我实现了一个成员函数来否定任何给定的向量;但我忘了回去打电话给d。修复该问题并将我的球体移动到负 z 平面后,我的 Lambertian 和 Blinn-Phong 着色实现工作正常。

Lambertian + Blinn-Phong

4

0 回答 0