Ответ 1
Вот алгоритм, который позволяет создавать точки, случайным образом распределенные по единице.
Мне нужно уточнение с алгоритмом, генерирующим случайные значения для моего луча-трассировщика.
Я испускаю лучи из одной точки. И у меня есть проблема с распределением этих лучей: мне нужно, чтобы распределение было равномерным, но это не...
Проблема, с которой я сталкиваюсь сейчас, состоит в том, что распределение, являющееся однородным, изначально неоднозначно после моих искажений пространства результатов.
Так, например, я генерирую r и t углы, если полярная система координат. Распределение неравномерно и не может быть равномерным: пространство, близкое к каждому полюсу, имеет гораздо большую плотность результатов, чем, скажем, близко к экватору. Причина довольно ясна: я преобразовываю равномерно распределенные точки из цилиндрического пространства в сферическое. И я искажаю результаты. Та же проблема заключается в том, что я нормализую точки, созданные случайным образом в кубе.
Теперь моя идея: я хочу создать тетраэдр, нормализовать его вершины, разделить каждую грань (треугольник) с точкой посередине, нормализовать ее и повторить рекурсивно, пока у меня не будет достаточно очков. Затем я немного "искажаю" эти точки. Затем я нормализую их снова. Это.
Я понимаю, что этот метод не является чисто математическим методом Монте-Карло, потому что я не использую случайное распределение ни на одном шаге, кроме последнего. И мне не нравится это решение для этой сложности.
Может ли кто-нибудь предложить что-нибудь более простое, но все же
Спасибо!
EDIT:
Мне нужен быстрый метод, а не только правильный. Вот почему я спрашиваю о Монте-Карло. Предоставленные ответы являются правильными, но не быстрыми. Метод с тетраэдром является быстрым, но не очень "случайным" = > неверным.
Мне действительно нужно что-то более подходящее.
Вот алгоритм, который позволяет создавать точки, случайным образом распределенные по единице.
Здесь реализация Java, которую я использовал в прошлом:
public static double[] randomPointOnSphere(Random rnd)
{
double x, y, z, d2;
do {
x = rnd.nextGaussian();
y = rnd.nextGaussian();
z = rnd.nextGaussian();
d2 = x*x + y*y + z*z;
} while (d2 <= Double.MIN_NORMAL);
double s = Math.sqrt(1.0 / d2);
return new double[] {x*s, y*s, z*s};
}
Вам действительно нужно случайное распределение или равномерное распределение по сфере?
Тогда я бы предложил углы ZCW, которые равномерно распределены по всей сфере и быстро вычисляются. Другие методы - TheSydneyOperaHouse (SOPHE) и Отталкивание. (поиск отталкивания .c) Метод отталкивания довольно неплохой, но медленный: он итеративно распределяет точки равномерно по сфере. К счастью, это нужно сделать только один раз.
Это используется в кристаллографии и ЯМР, потому что для образцов порошков быстрее использовать равномерное распределение по сравнению с случайным распределением (вам нужно меньше очков).
Здесь - реализация Python для ZCW.
Подробнее в этих статьях:
Исследование неслучайного численного метода для многомерного интегрирования, Чэн, Вера Б. и Генри Х. Сузукава-младший и Вольфсберг, Макс
Компьютерное моделирование в твердотельном ЯМР. III. Порошковое усреднение, Матиас Эден
Я не уверен, что это вообще имеет смысл, но здесь вы идете:
Единая фракционная часть: простой быстрый метод для генерации непрерывных случайных вариаций
Если вы не трассируете только тривиальные сцены, будет ли ваше время рендеринга на самом деле доминировать на выборке? Если нет, то, вероятно, еще не стоит оптимизировать, хотя стоит прочитать и понять методы единообразной выборки, приведенные в других ответах.
Кроме того, ваши образцы не обязательно должны быть очень случайными для получения хорошей оценки любой функции, которую вы отбираете. Вы можете исследовать, используя последовательность квазислучайных чисел, такую как последовательность Halton. Идея вашего тетраэдрового подразделения неплохая. Это должно привести к хорошим хорошо распределенным точкам, которые должны быть лучше, чем равномерные псевдослучайные выборки для большинства сцен, хотя в некоторых случаях это может привести к ужасающим артефактам.
В любом случае, вы должны проконсультироваться на форумах на ompf.org. Там есть супер-хардкор-рейтрейзеры.
Для сферических секций ваш угол равномерно распределяется в phi
(полярный угол) и cos(theta)
(для theta азимутальный угол) между вашими пределами.
В псевдокоде:
phi = phi_low_limit + rand()*(phi_high_limit - phi_low_limit)
ct = cos(theta_high_limit) + rand()*(cos(theta_low_limit) - cos(theta_high_limit))
// The order is inverted here because cos heads down for increasing theta
theta = arccos(ct)
Это частный случай правила, который говорит инвертировать Jacobian и генерировать равномерно в этом пространстве этих координат.
Примечание. Обратите внимание, что я использую противоположное соглашение для phi и theta из линии Дэвида Нормана.
Обратите внимание: это не самый быстрый метод, а скорее тот, который иллюстрирует общий принцип.