opengl — Simple Ray Tracer, проблемы диффузного затенения Переполнение стека

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

http://www.ccs.neu.edu/home/fell/CSU540/programs/RayTracingFormulas.htm

Мой код, который вычисляет затенение (попытка репликации исходного кода по ссылке), показан ранее. По большей части расчеты кажутся правильными в некоторых сферах, иногда, однако, в зависимости от положения источников света, зависит от того, насколько правильной / нарушенной является штриховка сфер.

TVector intersect   (ray.getRayOrigin().getVectX() + t * (ray.getRayDirection().getVectX() - ray.getRayOrigin().getVectX()),
ray.getRayOrigin().getVectY() + t * (ray.getRayDirection().getVectY() - ray.getRayOrigin().getVectY()),
ray.getRayOrigin().getVectZ() + t * (ray.getRayDirection().getVectZ() - ray.getRayOrigin().getVectZ()));

//Calculate the normal at the intersect point
TVector NormalIntersect (intersect.getVectX() - (position.getVectX()/r),
intersect.getVectY() - (position.getVectY()/r),
intersect.getVectZ() - (position.getVectZ()/r));

NormalIntersect = NormalIntersect.normalize();

//Find unit vector from intersect(x,y,z) to the light(x,y,z)
TVector L1 (light.GetPosition().getVectX() - intersect.getVectX(),
light.GetPosition().getVectY() - intersect.getVectY(),
light.GetPosition().getVectZ() - intersect.getVectZ());
L1 = L1.normalize();
double Magnitude = L1.magnitude();

TVector UnitVector(L1.getVectX() / Magnitude,
L1.getVectY() / Magnitude,
L1.getVectZ() / Magnitude);

//Normalized or not, the result is the same
UnitVector = UnitVector.normalize();

float Factor = (NormalIntersect.dotProduct(UnitVector));
float kd = 0.9;             //diffuse-coefficient
float ka = 0.1;             //Ambient-coefficient
Color pixelFinalColor(kd * Factor * (color.getcolorRed())  +  (ka * color.getcolorRed()) ,
kd * Factor * (color.getcolorGreen())  + (ka * color.getcolorGreen())  ,
kd * Factor * (color.getcolorBlue()) +  (ka * color.getcolorBlue()) ,1);

Ошибка диффузного затенения

Как видно из рисунка, некоторые сферы выглядят правильно затененными, а другие полностью разбиты. Сначала я думал, что проблема может быть связана с вычислением UnitVector, однако, когда я просмотрел его, я не смог найти проблему. Кто-нибудь может увидеть причину проблемы?

Примечание: я использую OpenGl для рендеринга моей сцены.

Обновить:
У меня все еще есть несколько проблем, однако я думаю, что они в основном были решены благодаря помощи вас, ребята, и нескольким изменениям в том, как я вычисляю вектор единиц. Обновления показаны ниже. Большое спасибо всем, кто дал свои ответы.

TVector UnitVector (light.GetPosition().getVectX() - intersect.getVectX(),
light.GetPosition().getVectY() - intersect.getVectY(),
light.GetPosition().getVectZ() - intersect.getVectZ());

UnitVector = UnitVector.normalize();
float Factor = NormalIntersect.dotProduct(UnitVector);

//Set Pixel Final Color
Color pixelFinalColor(min(1,kd * Factor * color.getcolorRed())  +  (ka * color.getcolorRed()) ,
min(1,kd * Factor * color.getcolorGreen())  + (ka * color.getcolorGreen())  ,
min(1,kd * Factor * color.getcolorBlue()) +  (ka * color.getcolorBlue()) ,1);

1

Решение

Во-первых, если ваш getRayDirection() делает то, что он говорит, он производит направление, а не точку взгляда, поэтому вы не должны вычитать из него источник луча, который является точкой.
(Хотя направления и точки представлены векторами, это не имеет смысла
добавить точку в направлении)

Также вы нормализуете L1 а затем взять его величину и разделить каждый из его компонентов на эту величину, чтобы получить UnitVector, который вы тогда называете normalize на снова. Это ненужно: величина L1 после первой нормализации 1, вы нормализуете один и тот же вектор 3 раза, просто используйте L1,

Последняя проблема — это проблема зажима. Переменная, которую вы называете Factor это значение cos(th) где th угол между направлением света и нормалью. Но cos(th) имеет диапазон [1,-1] и вы хотите диапазон только [0,1], так что вы должны зажать Factor к этому диапазону:

Factor = max(0, min( NormalIntersect.dotProduct(UnitVector), 1));

(И удалить min призывает в вашем производстве color).

Этот зажим необходим для поверхностей, нормали которых направлены в сторону от света, который будет иметь отрицательный cos(th) ценности. Угол между их нормалью и направлением света больше, чем pi/2, Интуитивно понятно, что они должны выглядеть как можно темнее по отношению к рассматриваемому свету, поэтому мы фиксируем их на 0).

Вот мой окончательный вариант кода, который должен Работа. Я собираюсь работать в предположении, что у вас есть scale(float) а также operator +(const TVector &) и т. д. определено на вашем TVector класс, потому что они совершенно очевидно сделают вашу жизнь проще. Также для краткости я собираюсь позвонить NormalIntersect, просто normal:

TVector
intersect = ray.getRayOrigin() + ray.getRayDirection().scale(t),
normal    = (intersect - position).normalize(),
L1        = (light.GetPosition() - intersect).normalize();

float
diffuse   = max(0, min(normal.dotProduct(L1), 1)),
kd        = 0.1,
ka        = 0.9;

Color pixelFinalColor = color.scale(kd * diffuse + ka);
1

Другие решения

Вы неуместные брекеты в обычном расчете это должно быть

TVector NormalIntersect ((intersect.getVectX() - position.getVectX())/r,
(intersect.getVectY() - position.getVectY())/r,
(intersect.getVectZ() - position.getVectZ())/r);
1

По вопросам рекламы [email protected]