简单的光线跟踪器,漫反射着色问题c ++

时间:2013-12-26 11:34:06

标签: c++ opengl raytracing pixel-shading

我正在编写一个基本的Ray-tracer,以便更好地理解整个事物。我遇到了一个问题,这个问题一直让我退缩一段时间,一个球体的漫反射阴影。我使用了以下来源的公式来计算球体交点和漫反射着色。

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);

Diffuse Shading Error

从图中可以看出,某些球体看起来是正确的阴影,而其他球体则完全被打破。起初我认为问题可能在于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);

2 个答案:

答案 0 :(得分:1)

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

TVector NormalIntersect ((intersect.getVectX() - position.getVectX())/r, 
                         (intersect.getVectY() - position.getVectY())/r,
                         (intersect.getVectZ() - position.getVectZ())/r);

答案 1 :(得分:1)

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

此外,您正在对L1进行规范化,然后计算其幅度并将其每个组件除以该幅度,以生成UnitVector,然后再次在上调用normalize 。这是不必要的:第一次归一化后L1的幅度为1,您将相同的矢量标准化3次,只需使用L1

最后一个问题是夹紧问题。您调用Factor的变量是值cos(th),其中th是光线方向与法线之间的角度。但cos(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 &)TVector等,因为它们会让您的生活更轻松。另外,为简洁起见,我打算致电NormalIntersect,只需normal

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);