光线追踪反射畸变
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 Vector
和 Position
。这似乎是个好主意,但为什么不将位置视为从原点开始的平移向量呢?我认为这会避免一些代码重复(除非你做了类似 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 它的代码 :)
我已经开始编写光线追踪器,但今天在处理反射时遇到问题。
首先,这是问题的图片:
我只计算了物体的反射颜色(因此没有对反射物体应用光效) 问题是我真的不明白的失真。 我查看了我的 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
Vector
和Position
。这似乎是个好主意,但为什么不将位置视为从原点开始的平移向量呢?我认为这会避免一些代码重复(除非你做了类似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 它的代码 :)