Задача
Я пишу трассировщик лучей как пример использования конкретного подхода машинного обучения в компьютерной графике.
Моя проблема в том, что, когда я пытаюсь найти пересечение между лучом и поверхностью, результат не является точным.
В принципе, если я рассеиваю луч от точки O к поверхности, расположенной в (x, y, z) , где z = 81, я бы ожидал, что решение быть чем-то вроде S = (x, y, 81) .
Проблема в том, что я получаю решение типа (x, y, 81.000000005) .
Это, конечно, проблема, потому что от этого решения зависят следующие операции, и оно должно быть точным.
Вопрос
У меня вопрос: как люди в компьютерной графике справляются с этой проблемой? Я попытался изменить мои переменные с float
на double
, и это не решило проблему.
Альтернативные решения
Я пытался использовать функцию std::round()
. Это может помочь только в определенных ситуациях, но не тогда, когда точное решение содержит одну или несколько значащих цифр.
То же самое для std::ceil()
и std::floor()
.
EDIT
Вот так я вычисляю пересечение с поверхностью (прямоугольником), параллельной осям xz .
Прежде всего, я вычисляю расстояние t
между началом моего Луча и поверхностью. Если мой Луч в указанном направлении не попадает на поверхность, t
возвращается как 0.
class Rectangle_xy: public Hitable {
public:
float x1, x2, y1, y2, z;
...
float intersect(const Ray &r) const { // returns distance, 0 if no hit
float t = (y - r.o.y) / r.d.y; // ray.y = t* dir.y
const float& x = r.o.x + r.d.x * t;
const float& z = r.o.z + r.d.z * t;
if (x < x1 || x > x2 || z < z1 || z > z2 || t < 0) {
t = 0;
return 0;
} else {
return t;
}
....
}
В частности, с учетом Луча и id
объекта в списке (который я хочу ударить):
inline Vec hittingPoint(const Ray &r, int &id) {
float t; // distance to intersection
if (!intersect(r, t, id))
return Vec();
const Vec& x = r.o + r.d * t;// ray intersection point (t calculated in intersect())
return x ;
}
Функция intersect()
в предыдущем фрагменте кода проверяет каждый прямоугольник в списке rect
, если я пересекаю некоторый объект:
inline bool intersect(const Ray &r, float &t, int &id) {
const float& n = NUMBER_OBJ; //Divide allocation of byte of the whole scene, by allocation in byte of one single element
float d;
float inf = t = 1e20;
for (int i = 0; i < n; i++) {
if ((d = rect[i]->intersect(r)) && d < t) { // Distance of hit point
t = d;
id = i;
}
}
// Return the closest intersection, as a bool
return t < inf;
}
Координата затем получается с использованием геометрической интерполяции между линией и поверхностью в трехмерном пространстве:
Vec& x = r.o + r.d * t;
где:
r.o
: он представляет происхождение луча. Он определяется как r.o: Vec (float a, float b, float c
)
r.d
: это направление луча. Как и прежде: r.d: Vec (float d, float e, float f
).
t
: float
представляет расстояние между объектом и началом координат.