Функция произвольного направления выглядит неправильно для меня.Похоже, что он должен создать три косинуса (wx, wy, wz), которые являются однородными на сфере с радиусом = 1, так что
wx 2 + wy 2 + wz 2 = 1
Первая проблема: вы создаете случайный движок каждый раз при входе в функцию, поэтому все ваши значения одинаковы.Я просто поместил его в Visual Studio 2017, C ++ 14.1, x64, Win10 и произвел два вызова
-0.383666 -0.804919 0.0944412
-0.383666 -0.804919 0.0944412
Вторая проблема - это не случайное измерение, длина не равна 1.
ОБНОВЛЕНИЕ
После статьи Вольфрама http://mathworld.wolfram.com/SpherePointPicking.html, приведен код, который устраняет обе проблемы - в нем есть параметр RNG, поэтому состояние будет меняться.И, во-вторых, точка теперь правильно отбирается на единичной сфере и может использоваться как произвольное направление. Просто замените кортеж на vec3
#include <iostream>
#include <random>
#include <tuple>
std::tuple<float,float,float> random_in_unitSphere(std::mt19937& rng) {
std::uniform_real_distribution<float> distribution{};
float x1, x2, l;
do {
x1 = 2.0f * distribution(rng) - 1.0f;
x2 = 2.0f * distribution(rng) - 1.0f;
l = x1 * x1 + x2 * x2;
} while (l >= 1.0f);
float s = sqrt(1.0f - l);
return std::make_tuple(2.0f*x1*s, 2.0f*x2*s, 1.0f - 2.0f*l);
}
int main() {
std::mt19937 rng{ 987654321ULL };
float wx, wy, wz, squared_length;
std::tie(wx, wy, wz) = random_in_unitSphere(rng);
std::cout << wx << " " << wy << " " << wz << '\n';
squared_length = wx * wx + wy * wy + wz * wz;
std::cout << squared_length << '\n';
std::tie(wx, wy, wz) = random_in_unitSphere(rng);
std::cout << wx << " " << wy << " " << wz << '\n';
squared_length = wx * wx + wy * wy + wz * wz;
std::cout << squared_length << '\n';
return 0;
}
UPDATE II
Вторая проблема заключается в том, что выСгенерированные точки равномерно ВНУТРИ единичной сферы.Так что проблема не в направлениях - ваши wx, wy, wz хороши в направлении, а в длине вектора направления.Типичный код трассировки лучей подобен этому (в некотором псевдокоде)
auto [x0,y0,z0] = start_new_ray();
auto [wx,wy,wz] = sample_direction();
float path = compute_path_in_geometry(x0,y0,z0,wx,wy,wz); // compute path from start point 0 in the wx,wy,wz direction to next object
// move ray to new surface
x1 = x0 + wx*path;
y1 = y0 + wy*path;
z1 = z0 + wz*path;
// do scattering, illumination, ... at (x1,y1,z1)
Если длина (wx, wy, wz) не равна 1, тогда длина вычисляется как sqrt ((x1-x0) 2 + (y1-y0) 2 + (z1-z0) 2 ) НЕ БУДЕТ равно path
.Ваши основные правила геометрии просто нарушаются.