光线追踪反射畸变

Raytracing Reflection distortion

我已经开始编写光线追踪器,但今天在处理反射时遇到问题。

首先,这是问题的图片:

我只计算了物体的反射颜色(因此没有对反射物体应用光效) 问题是我真的不明白的失真。 我查看了我的 rayVector 和 normalVector 之间的角度,它看起来不错,反射矢量也看起来不错。

Vector Math::calcReflectedVector(const Vector &ray,
                                 const Vector &normal) const {
  double cosAngle;
  Vector copyNormal = normal;
  Vector copyView = ray;

  copyNormal.makeUnit();
  copyView.makeUnit();
  cosAngle = copyView.scale(copyNormal);
  return (-2.0 * cosAngle * normal + ray);
}

例如,当我的光线击中我的球体底部时,我有以下值:

因为:1

ViewVector: [185.869,-2.44308,-26.3504]

法线向量:[185.869,-2.44308,-26.3504]

反射向量:[-185.869,2.44308,26.3504]

下面是处理反射的代码:

Color Rt::getReflectedColor(std::shared_ptr<SceneObj> obj, Camera camera,
                            Vector rayVec, double k, unsigned int pass) {
  if (pass > 10)
    return obj->getColor();
  if (obj->getReflectionIndex() == 0) {
    // apply effects
    return obj->getColor();
  }

  Color cuColor(obj->getColor());
  Color newColor(0);
  Math math;
  Vector view;
  Vector normal;
  Vector reflected;
  Position impact;
  std::pair<std::shared_ptr<SceneObj>, double> reflectedObj;

  normal = math.calcNormalVector(camera.pos, obj, rayVec, k, impact);
  view = Vector(impact.x, impact.y, impact.z) -
         Vector(camera.pos.x, camera.pos.y, camera.pos.z);
  reflected = math.calcReflectedVector(view, normal);
  reflectedObj = this->getClosestObj(reflected, Camera(impact));
  if (reflectedObj.second <= 0) {
    cuColor.mix(0x000000, obj->getReflectionIndex());
    return cuColor;
  }
  newColor = this->getReflectedColor(reflectedObj.first, Camera(impact),
                                     reflected, reflectedObj.second, pass + 1);
  // apply effects
  cuColor.mix(newColor, obj->getReflectionIndex());
  return newColor;
}

计算法线和反射向量:

Vector Math::calcReflectedVector(const Vector &ray,
                                 const Vector &normal) const {
  double cosAngle;
  Vector copyRay = ray;

  copyRay.makeUnit();
  cosAngle = copyRay.scale(normal);
  return (-2.0 * cosAngle * normal + copyRay);
}

Vector Math::calcNormalVector(Position pos, std::shared_ptr<SceneObj> obj,
                              Vector rayVec, double k, Position& impact) const {
  const Position &objPos = obj->getPosition();
  Vector normal;

  impact.x = pos.x + k * rayVec.x;
  impact.y = pos.y + k * rayVec.y;
  impact.z = pos.z + k * rayVec.z;
  obj->calcNormal(normal, impact);
  return normal;
}

[编辑 1]

我有一个新图像,我删除了平面只是为了保留球体:

如您所见,球体的边界上有蓝色和黄色。 感谢 neam 我使用以下公式为球体着色:

  newColor.r = reflected.x * 127.0 + 127.0;
  newColor.g = reflected.y * 127.0 + 127.0;
  newColor.b = reflected.z * 127.0 + 127.0;

下面是可视化结果:

如果您需要任何信息,请问我。 提前致谢

有效吗?

我假设你的光线和法向量已经归一化了。

Vector Math::reflect(const Vector &ray, const Vector &normal) const
{
    return ray - 2.0 * Math::dot(normal, ray) * normal;
}

此外,我无法理解你提供的代码这个调用:

this->getClosestObj(reflected, Camera(obj->getPosition()));

应该是这样的吧?

this->getClosestObj(reflected, Camera(impact));

你提供的例子有很多小东西。这可能会——也可能不会——回答你的问题,但我想你是出于学习目的(在学校或空闲时间)做光线追踪器,我会给你一些提示。

  • 你有两个 classes VectorPosition。这似乎是个好主意,但为什么不将位置视为从原点开始的平移向量呢?我认为这会避免一些代码重复(除非你做了类似 using Position = Vector; 的事情)。你可能还想看看一些为你做所有数学事情的库(比如 glm 可以做)。 (这样,您将避免一些错误,例如将 dot 函数命名为 scale()

  • 你从这个位置创建了一个相机(那是真的奇怪的事情)。反射不涉及任何相机。在典型的光线追踪器中,您有一个相机 {position + direction + fov + ...} 并且对于 image/reflections/refractions/... 的每个像素,您投射 rays {origin + direction}(因此名称 raytracer,这不是 cameratracer)。 Camera class 通常与物理相机的概念相关联,例如焦距、景深、光圈、色差……而光线只是……一条光线。 (可以是来自输出图像映射到第一个对象的平面的光线,或者是反射、衍射、散射等产生的光线)。

  • 最后一点,我认为您的错误 可能 来自 Math::calcNormalVector(...) 函数。对于位置 P 和交点 I 的球体,法线 N 为:N = normalize(I - P);.

编辑: 看来您的问题来自 Rt::getClosestObj。其他一切看起来都很好

网上有大量 websites/blogs/educative 内容介绍如何创建简单的光线追踪器,因此对于前两点,我让他们教您。看看glm。 如果不明白 calcNormalVector(...) 有什么问题,请 post 它的代码 :)