1

我正在编写一个基本的光线追踪器,以更好地理解整个事情。我遇到了一个困扰我一段时间的问题,球体的漫反射阴影。我使用来自以下来源的公式来计算球体交叉点和漫反射阴影。

http://www.ccs.neu.edu/home/fell/CSU540/programs/RayTracingFormulas.htm

之前显示了我的计算阴影的代码(尝试复制链接上的源代码)。在大多数情况下,计算有时在某些球体上看起来是正确的,但是取决于灯光位置,取决于球体阴影看起来的正确/损坏程度。

TVector intersect   (ray.getRayOrigin().getVectX() + t * (ray.getRayDirection().getVectX() - ray.getRayOrigin().getVectX()),
                    ray.getRayOrigin().getVectY() + t * (ray.getRayDirection().getVectY() - ray.getRayOrigin().getVectY()),
                    ray.getRayOrigin().getVectZ() + t * (ray.getRayDirection().getVectZ() - ray.getRayOrigin().getVectZ()));

//Calculate the normal at the intersect point
TVector NormalIntersect (intersect.getVectX() - (position.getVectX()/r), 
                        intersect.getVectY() - (position.getVectY()/r),
                        intersect.getVectZ() - (position.getVectZ()/r));

NormalIntersect = NormalIntersect.normalize();

//Find unit vector from intersect(x,y,z) to the light(x,y,z)
TVector L1 (light.GetPosition().getVectX() - intersect.getVectX(), 
            light.GetPosition().getVectY() - intersect.getVectY(),
            light.GetPosition().getVectZ() - intersect.getVectZ());
L1 = L1.normalize();
double Magnitude = L1.magnitude();

TVector UnitVector(L1.getVectX() / Magnitude,
                   L1.getVectY() / Magnitude,
                   L1.getVectZ() / Magnitude);

//Normalized or not, the result is the same
UnitVector = UnitVector.normalize();

float Factor = (NormalIntersect.dotProduct(UnitVector));
float kd = 0.9;             //diffuse-coefficient
float ka = 0.1;             //Ambient-coefficient
Color pixelFinalColor(kd * Factor * (color.getcolorRed())  +  (ka * color.getcolorRed()) ,
                      kd * Factor * (color.getcolorGreen())  + (ka * color.getcolorGreen())  ,
                      kd * Factor * (color.getcolorBlue()) +  (ka * color.getcolorBlue()) ,1);

漫反射着色错误

从图片中可以看出,一些球体似乎被正确着色,而另一些球体则完全破碎。起初我认为问题可能在于 UnitVector 计算,但是当我查看它时,我无法找到问题。任何人都可以看到问题的原因吗?

注意:我使用 OpenGL 来渲染我的场景。

更新:我仍然遇到一些问题,但我认为在你们的帮助下,大部分问题已经得到解决,并且对我计算单位向量的方式进行了一些更改。更新如下所示。非常感谢所有给出答案的人。

TVector UnitVector (light.GetPosition().getVectX() - intersect.getVectX(), 
                    light.GetPosition().getVectY() - intersect.getVectY(),
                    light.GetPosition().getVectZ() - intersect.getVectZ());

UnitVector = UnitVector.normalize();
float Factor = NormalIntersect.dotProduct(UnitVector);

//Set Pixel Final Color
Color pixelFinalColor(min(1,kd * Factor * color.getcolorRed())  +  (ka * color.getcolorRed()) ,
                      min(1,kd * Factor * color.getcolorGreen())  + (ka * color.getcolorGreen())  ,
                      min(1,kd * Factor * color.getcolorBlue()) +  (ka * color.getcolorBlue()) ,1);
4

2 回答 2

1

你在正常计算中放错了大括号应该是

TVector NormalIntersect ((intersect.getVectX() - position.getVectX())/r, 
                         (intersect.getVectY() - position.getVectY())/r,
                         (intersect.getVectZ() - position.getVectZ())/r);
于 2013-12-26T16:11:45.657 回答
1

首先,如果你getRayDirection()按照它所说的那样做,它会产生一个方向,而不是一个凝视点,所以你不应该从中减去射线源,这是一个点。(虽然方向和点都是用向量表示的,但是在一个方向上加一个点是没有意义的)

此外,您正在标准化L1,然后取其大小并将其每个分量除以该大小,以产生,然后您再次UnitVector调用normalize它。这是不必要的:第一次归一化后的幅度为 1,您将同一向量归一化 3 次,只需使用.L1L1

最后一个问题是夹紧问题。您调用的变量是光的方向与法线之间的角度的Factor值。但是有一个范围并且你想要一个范围 only ,所以你必须钳制到那个范围:cos(th)thcos(th)[1,-1][0,1]Factor

Factor = max(0, min( NormalIntersect.dotProduct(UnitVector), 1));

(并删除min您生产中的电话color)。

对于法线背对光线的面,这种夹紧是必要的,光线将具有负值cos(th)。它们的法线与光的方向之间的夹角大于pi/2。直观地说,相对于所讨论的光,它们应该看起来尽可能暗,所以我们将它们钳制为 0)。

这是我的代码的最终版本,它应该可以工作。我将假设您在课堂上定义了等scale(float),因为它们显然会让您的生活更轻松。另外,为简洁起见,我将致电,只是:operator +(const TVector &)TVectorNormalIntersectnormal

TVector 
    intersect = ray.getRayOrigin() + ray.getRayDirection().scale(t),
    normal    = (intersect - position).normalize(),
    L1        = (light.GetPosition() - intersect).normalize();

float
    diffuse   = max(0, min(normal.dotProduct(L1), 1)),
    kd        = 0.1,
    ka        = 0.9;

Color pixelFinalColor = color.scale(kd * diffuse + ka);
于 2013-12-27T11:46:54.367 回答