我正在重写上学期为大学开发的raytracer,但遇到了以下问题:当我在Debug中编译并运行我的代码时,输出如预期的那样
但是当我启用更高的优化级别时,例如结果是“ -O2”完全不同:
而且我不确定为什么会这样。我将其跟踪到球面相交代码
//#pragma GCC push_options
//#pragma GCC optimize("O0")
Intersection Sphere::intersect(const Ray& ray, const float previous) const
{
const auto oc = ray.origin - center_;
const auto lhv = -dot(ray.direction, oc);
const auto discriminant = lhv * lhv - (oc.lensqr() - radius_ * radius_);
if (discriminant < 0.0F)
{
return Intersection::failure();
}
float distance;
const auto rhv = std::sqrt(discriminant);
const auto r = std::minmax(lhv + rhv, lhv - rhv);
if (r.first <= 0.0F)
{
if (r.second <= 0.0F)
{
return Intersection::failure();
}
distance = r.second;
}
else
{
distance = r.first;
}
const auto hit = ray.getPoint(distance);
const auto normal = (hit - center_).normalize();
if (0.0F <= distance && distance < previous - epsilon)
{
return {distance, ray, this, normal, hit};
}
return Intersection::failure();
}
//#pragma GCC pop_options
如果我在发布模式下取消注释该杂注,我将再次获得预期的结果。也许我的代码中有一些未定义的行为导致了这一点?
您也可以在这里查看,因为很难再现一个最小的示例。 https://github.com/Yamahari/RayTracer/blob/master/rt/solid/Sphere.cpp
((您也可以克隆存储库并使用cmake构建项目,您仅需要SFML作为依赖项。
将-DSFML_INCLUDE_DIR =“ include_dir”和-DSFML_LIB_DIR =“ lib_dir”与通过所需编译器编译的sfml库一起使用]
std::minmax
返回一对对其参数的引用。如果使用prvalues作为参数调用它,则在完整表达式结束后,该对中的引用将悬空,这意味着访问r.first
in
if (r.first <= 0.0F)
这里将有未定义的行为。
因此将lhv + rhv
和lhv - rhv
存储在变量中,并在它们上调用std::minmax
或使用
std::minmax({lhv + rhv, lhv - rhv})
选择std::initializer_list
重载,它返回一对实际值。
正如@ Jarod42在评论中指出的那样,您实际上实际上不需要std::minmax
。 rhv
是std::sqrt
调用的结果,因此它始终为非负数,从而使lhv + rhv
始终为更大(或相等)的值。