Простая трассировка лучей с ламбертовским оттенением, путаница - PullRequest
0 голосов
/ 27 апреля 2018

Я не видел другого сообщения с проблемой, похожей на мою, так что, надеюсь, это не является избыточным.

Я читал книгу об основах компьютерной графики (третье издание) и внедрял базовую программу трассировки лучей, основанную на принципах, которые я усвоил из нее. У меня были небольшие проблемы с реализацией параллельного и перспективного проецирования, но после перехода на Lambertian и Blinn-Phong Shading я столкнулся с трудностью, с которой мне трудно разобраться самостоятельно.

Я полагаю, что моя проблема связана с тем, как я вычисляю точку пересечения лучевой сферы и векторы для камеры / света. Я приложил изображение, которое выводится, когда я запускаю просто перспективную проекцию без затенения.

Перспективный вывод

Однако, когда я пытаюсь повторить ту же сцену с затенением Ламберта, сферы исчезают.

Бланк Ouput

Пытаясь отладить это самостоятельно, я заметил, что если я отменю координаты x, y, z, вычисленные как точка попадания, сферы снова появляются. И я верю, что свет идет в противоположном направлении, я ожидаю.

Ламбертиан, отрицание HitPoint

Я вычисляю точку попадания, добавляя произведение вектора проекции и значения t , рассчитанного по формуле пересечения сферы луча, к исходной точке (где моя «камера» равна 0 , 0,0) или просто e + td .

Вектор от точки попадания к свету, 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, поэтому я не верю, что это вызывает эту проблему.

Я думаю, что могу делать какую-то ошибку, когда дело касается сохранения позиций и векторов в одной и той же системе координат (одно и то же преобразование?), Но я все еще учусь и, по общему признанию, не очень хорошо понимаю это. Если направление просмотра всегда в направлении - w , почему мы позиционируем объекты сцены в положительном направлении w ?

Любая помощь или мудрость очень ценится. До сих пор я учу все это самому себе, и я доволен тем, сколько я принял, но что-то в моей интуиции говорит мне, что это относительно простая ошибка.

На всякий случай, если это пригодится, вот функция 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;
}

EDIT:

Я рад сообщить, что выяснил свою проблему.

Когда я сел с сестрой, чтобы посмотреть на это, я заметил, что в моем обнаружении попадания лучевой сферы у меня было следующее:

float t_add = ((d) * (part2)+sqrt(discriminant)) / (part3);

Что неверно. d должно быть отрицательным. Должно быть:

float t_add = ((neg_d * (e_min_c)) + sqrt(discriminant)) / (part2);

(я переименовал пару переменных) Ранее у меня был нулевой вектор, чтобы я мог выразить - d как (zero_vector - d ), и я удалил его, потому что я реализовал функция-член для отрицания любого заданного вектора; но я забыл вернуться и позвонить на d . После исправления и перемещения моей сферы в отрицательную плоскость z мои реализации затенения Ламберта и Блинн-Фонга работают правильно.

Ламбертиан + Блинн-Фонг

...