【问题标题】:Simple Ray Tracer, Diffuse Shading problems c++简单的光线追踪器,漫反射着色问题 c++
【发布时间】:2013-12-27 19:58:18
【问题描述】:

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

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

【问题讨论】:

  • 确保最终颜色不超过颜色范围(0 到 1 或 255)。根据库的不同,太亮的颜色可能会覆盖并变成黑色。插入分钟:pixelFinalColor(min(1, kd * Factor...Factor = max(0, NormalIntersect... 执行相同操作
  • 谢谢,好建议。在将 min(1) 添加到像素颜色之后,它似乎已经解决了某些球体上的问题,但是在不同位置的其他球体也出现了同样的问题。如果我还将 max(0) 添加到因子中,则所有对象都会变成单色调的平面阴影,根本没有漫反射阴影。感谢您的帮助。谢谢您
  • 如果一切看起来都是单一的色调,它可能没有点亮,只是显示您的环境照明。你确定你的灯在你认为的位置吗?
  • 正,在添加 max(0) 之前根据我移动光的位置 (x,y,z) 改变球体的着色方式,对于那些没有被破坏的球体,它看起来准确。我已经测试了多个照明位置,这绝对不是问题。感谢您的宝贵时间和意见。

标签: c++ opengl raytracing pixel-shading


【解决方案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));

(并在您的color 的生产中删除min 调用)。

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

这是我的代码的最终版本,应该可以工作。我将假设您在 TVector 类中定义了 scale(float)operator +(const 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);

【讨论】:

  • 很好的答案,感谢您的宝贵时间。这解决了我的问题。至于多次归一化L1,我注意到昨晚很晚,这是一个有点愚蠢的错误。再次感谢。
【解决方案2】:

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

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

【讨论】:

  • 我已经更新了,抱歉,当我尝试修复它时,代码中可能存在一些小错误,但这次更正对最终结果没有影响。非常感谢您的回复
  • 这不是一个小错误,除非你的半径接近 1,否则应该会严重破坏事情
  • 对不起,我明白你的意思了,我只说次要,因为它以前是正确的,只是在我放在这里的在线代码中不合适。非常感谢您的回复。有了这个修复程序,你知道我为什么会出现这些阴影错误吗?谢谢
猜你喜欢
  • 2017-08-16
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多