Трассировка лучей / Модель Фонга Диффузный компонент

Итак, у меня возникли проблемы с моделью Фонга, особенно с диффузным компонентом, и с использованием правильного вектора нормали и направления вектора света. Это для школьного проекта, но мне все равно, если я его не закончу, пока кто-нибудь может сказать мне, что я делаю неправильно. Я уже пробовал кое-что, и лучшее, что у меня получилось, это затенить половину большей сферы, но в неправильном направлении. Самая яркая интенсивность находится на внешнем краю половины круга и становится темнее по мере продвижения к центру, когда должно быть наоборот. Похоже, что он затеняет сферу линиями, когда я видел модели, которые выглядят так, как будто он затеняет пустыми кругами.

Затенение второй сферы может быть трудно увидеть. Затененные сферы

Соответствующие структуры:

struct Ray
{
    vec3 origin;        // origin of the ray
    vec3 dir;           // direction of the ray
};

struct Sphere
{   
    vec3 center;
    float radius;       
    vec3 ka, kd, ks;
    vec3 reflectivity;
    float alpha;        

    Sphere(const vec3& ic=vec3(0.0f), const float& ir=0.0f, const vec3& ika=vec3(0.0f), const vec3& ikd=vec3(0.0f), const vec3& iks=vec3(0.0f), const float& ireflectivity=0.1f, const float& ialpha=1.0f):
    center(ic), radius(ir), ka(ika), kd(ikd), ks(iks), reflectivity(ireflectivity), alpha(ialpha)
    {}

    bool intersect(const Ray& ray, float& t0, float& t1);
};

struct PointLight
{
    vec3 location;
    vec3 id, is;    

    PointLight(const vec3& iloc=vec3(0.0f), const vec3& iid=vec3(0.0f), const vec3& iis=vec3(0.0f)):
    location(iloc), id(iid), is(iis)
    {}

};

    vec3 color;
    vec3 amb = my_sphere.ka* my_ambient_light.ia;   // I = ka * ia  ambient component
    int temp = my_point_lights.size() - 1;
    color += amb;

    vec3 diff;
    for (int i = my_point_lights.size() - 1; i >= 0; i--) {
        vec3 n = (ray.origin + ray.dir - my_sphere.center);
        normalize(n);

        vec3 L = (my_point_lights[temp].location - ray.origin);
        normalize(L);

        diff += my_sphere.kd * my_point_lights[temp].id * std::max(dot(n, L), 0.0f);
    }
    color += diff;

person J Rat    schedule 07.12.2018    source источник
comment
Я думаю, что вы не должны вычитать ray.origin из vec3 L. Попробуйте перейти по этой ссылке: shadertoy.com /просмотр/XlXGDj   -  person Felipe Gutierrez    schedule 08.12.2018
comment
Я считаю, что для получения направления к вектору света мне нужно вычесть положение поверхности из положения точечного источника света. Это также может быть точкой пересечения между лучом и сферой, чтобы ray.origin мог работать. Ссылка, которой вы поделились, похожа на некоторые примеры, которые я видел, но в этом примере указано направление света и положение сферы. Нормальный похож на мой. вот, наверное, где я ошибся.   -  person J Rat    schedule 08.12.2018


Ответы (1)


Что вы в основном, кажется, хотите сделать в своем шейдере, так это вычислить диффузное затенение данной точки на сфере. Для этого вам в основном понадобятся две вещи: во-первых, нормаль к поверхности в той точке сферы, которую вы хотите затенить, и, во-вторых, направление, с которого свет падает на точку, которую вы хотите затенить. Теперь, прежде чем вы сможете продолжить и вычислить затенение объекта в данной точке, вам, как правило, необходимо знать фактическое положение этой конкретной точки, которую вы хотите затенить. Поскольку вы на самом деле не предоставили никаких объяснений, что именно такие вещи, как ray.dir, на самом деле представляют в вашем коде, мне придется прибегнуть к догадкам. Я предполагаю, что то, что вы делаете, является своего рода трассировкой лучей в шейдере фрагментов. И мне придется предположить, что ray.dir — это не просто некоторый вектор, указывающий в общем направлении луча, попадающего на сферу в интересующей вас точке, но на самом деле это вектор, который привести вас от начала луча к точной точке попадания на сфере. В противном случае вам не хватает самой важной информации, чтобы действительно что-то сделать, а именно координат точки, которую вы хотите заштриховать. В этом случае вам сначала нужно вычислить, где находится фактическое пересечение вашего луча и вашей сферы.

Теперь, если мы сделаем все эти предположения и, кроме того, предположим, что все эти векторы, которые у вас есть, на самом деле представляют координаты в одной и той же системе координат, тогда ray.origin + ray.dir - my_sphere.center действительно должен дать вектор, указывающий из центра сферы в точку, которую вы хотите заштриховать. И этот вектор действительно должен указывать в направлении нормали к поверхности сферы в точке, которую вы хотите затенить. Однако второй вектор, который вам нужен для вычисления диффузного затенения, — это вектор, указывающий в направлении, из которого свет падает на точку, которую вы хотите затенить. То есть вектор, указывающий от точки затенения к источнику света. Однако вместо этого my_point_lights[temp].location - ray.origin может показаться вектором, указывающим от источника луча к источнику света.

Кроме того, вероятно, следует обратить ваше внимание на то, что, вопреки тому, что у вас, кажется, сложилось впечатление, функция normalize(x) не изменяет вектор, который вы передаете в качестве аргумента. Он просто возвращает другой вектор, который является нормализованной версией любого вектора, который вы ему подаете. Так что, скорее всего, вы на самом деле хотели написать

n = normalize(n);
…
L = normalize(L);

Кроме того, вы накапливаете значения в color и diff, но никогда не инициализируете эти векторы чем-либо. Вы, вероятно, хотели инициализировать их нулем… ????

person Michael Kenzel    schedule 08.12.2018
comment
Вы были правы, предположив, что ray.dir — это вектор. Это вектор направления луча. Я только что обновил его, чтобы включить это. Это в основном большая часть информации, с которой мне приходится работать. Итак, мой мыслительный процесс заключался в том, что мне нужно направление к вектору света, который находится во всех направлениях, где бы свет ни отражался от поверхности сферы. Так как ray.origin — это точка пересечения точки поверхности сферы и луча. Я подумал, что мне нужно вычесть точку на поверхности сферы из положения точечного источника света, чтобы получить направление к вектору света. - person J Rat; 08.12.2018
comment
@JRat Ну ладно, если это просто направление луча и ничего более, то что именно, по вашему мнению, дает вам ray.origin + ray.dir - my_sphere.center !? - person Michael Kenzel; 08.12.2018
comment
Я думал, что это нормаль к поверхности сферы. Друг сказал мне, что это должен быть ray.origin - my_sphere.center, но в некоторых примерах, которые я видел, используется ray.origin + ray.dir * t - my_sphere.center. Как тот, которым поделился Фелипе. - person J Rat; 10.12.2018