Я не видел другой пост с проблемой, похожей на мою, так что, надеюсь, это не излишне.
Я читал книгу об основах компьютерной графики (третье издание) и внедрял базовую программу трассировки лучей, основанную на принципах, которые я усвоил из нее. У меня были небольшие проблемы с реализацией параллельного и перспективного проецирования, но после перехода на Lambertian и Blinn-Phong Shading я столкнулся с трудностью, с которой мне трудно разобраться самостоятельно.
Я считаю, что моя проблема связана с тем, как я вычисляю точку пересечения лучевой сферы и векторы для камеры / света. Я прикрепил изображение, которое выводится, когда я запускаю просто перспективную проекцию без затенения.
Однако, когда я пытаюсь сделать ту же самую сцену с затенением Ламберта, сферы исчезают.
Пытаясь отладить это самостоятельно, я заметил, что если я отменю координаты x, y, z, вычисленные как точка попадания, сферы снова появляются. И я верю, что свет идет в противоположном направлении, я ожидаю.
Ламбертиан, отрицание HitPoint
Я вычисляю точку попадания, добавляя произведение вектора проекции и T значение, рассчитанное по формуле пересечения луча и сферы, до начала координат (где моя «камера», 0,0,0) или просто е + тд.
Вектор от точки попадания к свету, L, Я устанавливаю в положение источника света минус положение точки попадания (поэтому координаты точки попадания минус координаты источника света).
v, вектор от точки попадания до камеры, я получаю, просто отрицая вектор проецируемого вида;
И поверхность нормальная, которую я получаю по точке попадания минус положение сферы.
Все что я считаю правильным. Однако, проходя через часть, которая вычисляет нормаль поверхности, я замечаю что-то странное. Вычитая положение точки попадания из положения сферы, чтобы получить вектор от центра сферы до точки попадания, я полагаю, что я должен ожидать получить вектор, в котором все значения лежат в пределах диапазона (-r, r); но этого не происходит.
Это пример из моего кода:
Расчетная точка попадания: (-0,9971, 0,1255, -7,8284)
Центр сферы: (0, 0, 8) (радиус 1)
После вычитания я получаю вектор, где значение z равно -15.8284. Это кажется мне неправильным; но я не знаю, что вызывает это. Не означает ли значение z -15,8284, что центр сферы и позиция удара находятся на расстоянии ~ 16 единиц друг от друга в плоскости z? Очевидно, что эти два числа находятся в пределах 1 друг от друга в абсолютных значениях, вот что заставляет меня думать, что моя проблема как-то связана с этим.
Вот основной цикл трассировки лучей:
auto origin = Position3f(0, 0, 0);
for (int i = 0; i < numPixX; i++)
{
for (int j = 0; j < numPixY; j++)
{
for (SceneSurface* object : objects)
{
float imgPlane_u = left + (right - left) * (i + 0.5f) / numPixX;
float imgPlane_v = bottom + (top - bottom) * (j + 0.5f) / numPixY;
Vector3f direction = (w.negated() * focal_length) + (u * imgPlane_u) + (v * imgPlane_v);
Ray viewingRay(origin, eye, direction);
RayTestResult testResult = object->TestViewRay(viewingRay);
if (testResult.m_bRayHit)
{
Position3f hitPoint = (origin + (direction) * testResult.m_fDist);//.negated();
Vector3f light_direction = (light - hitPoint).toVector().normalized();
Vector3f view_direction = direction.negated().normalized();
Vector3f surface_normal = object->GetNormalAt(hitPoint);
image[j][i] = object->color * intensity * fmax(0, surface_normal * light_direction);
}
}
}
}
GetNormalAt это просто:
Vector3f Sphere::GetNormalAt(Position3f &surface)
{
return (surface - position).toVector().normalized();
}
Мои сферы расположены в (0, 0, 8) и (-1,5, -1, 6) с радом 1,0f.
Мой свет в (-3, -3, 0) с интенсивностью 1,0f;
Я игнорирую любое пересечение, где T не больше 0, поэтому я не верю, что вызывает эту проблему.
Я думаю, что могу делать какую-то ошибку, когда дело касается сохранения позиций и векторов в одной и той же системе координат (то же самое преобразование?), Но я все еще учусь и по общему признанию не очень хорошо понимаю это. Если направление просмотра всегда в —вес направление, почему мы позиционируем объекты сцены в положительном вес направление?
Любая помощь или мудрость очень ценится. До сих пор я учу все это себе, и я доволен тем, сколько я принял, но что-то в моей интуиции говорит мне, что это относительно простая ошибка.
На всякий случай, если это пригодится, вот функция TestViewRay:
RayTestResult Sphere::TestViewRay(Ray &viewRay)
{
RayTestResult result;
result.m_bRayHit = false;
Position3f &c = position;
float r = radius;
Vector3f &d = viewRay.getDirection();
Position3f &e = viewRay.getPosition();
float part = d*(e - c);
Position3f part2 = (e - c);
float part3 = d * d;
float discriminant = ((part*part) - (part3)*((part2*part2) - (r * r)));
if (discriminant > 0)
{
float t_add = ((d) * (part2)+sqrt(discriminant)) / (part3);
float t_sub = ((d) * (part2)-sqrt(discriminant)) / (part3);
float t = fmin(t_add, t_sub);
if (t > 0)
{
result.m_iNumberOfSolutions = 2;
result.m_bRayHit = true;
result.m_fDist = t;
}
}
else if (discriminant == 0)
{
float t_add = ((d)* (part2)+sqrt(discriminant)) / (part3);
float t_sub = ((d)* (part2)-sqrt(discriminant)) / (part3);
float t = fmin(t_add, t_sub);
if (t > 0)
{
result.m_iNumberOfSolutions = 1;
result.m_bRayHit = true;
result.m_fDist = t;
}
}
return result;
}
РЕДАКТИРОВАТЬ:
Я рад сообщить, что выяснил мою проблему.
Садясь с моей сестрой, чтобы посмотреть на это, я заметил, что в моем обнаружении удара лучевой сферы у меня было это:
float t_add = ((d) * (part2)+sqrt(discriminant)) / (part3);
Что неверно. d должен быть отрицательным. Так должно быть:
float t_add = ((neg_d * (e_min_c)) + sqrt(discriminant)) / (part2);
(Я переименовал пару переменных) Ранее у меня был нулевой вектор, чтобы я мог выразить —d as (zero_vector — d) и я удалил это, потому что я реализовал функцию-член для отмены любого данного вектора; но я забыл вернуться и позвонить на d. После исправления этого положения и перемещения моей сферы в отрицательную плоскость z мои реализации затенения Lambertian и Blinn-Phong работают правильно.
Задача ещё не решена.
Других решений пока нет …