ПрограммированиеФорумГрафика

Отскок частицы в случайном направлении в рамках полусферы, диффузное отражение

Страницы: 1 2 Следующая »
#0
11:05, 26 авг 2022

Помогите пожалуйста, ковыряюсь с системой частиц в 3Д на шейдерах (Godot 4).

Никак не могу сделать вроде элементарную вещь - диффузное отражение. У меня есть следующие данные: частица, она летит по направлению Vector3(x,y,z), ударяется в препятствие, в точке ударения я знаю нормаль в виде произвольного вектора в направлении Vector3(x,y,z). Мне нужно развернуть направление движения частицы в рандомном направлении в соответствии с нормалью по полусфере образованной плоскостью нормали, вот так:
Диффузное отражение луча | Отскок частицы в случайном направлении в рамках полусферы, диффузное отражение
Как это сделать самым простым способом?

В 2Д всё это решалось так просто...

vec2 rotate(vec2 v, float a) 
{
  float s = sin(a);
  float c = cos(a);
  //либо так: lowp mat2 m = mat2(vec2(c,-s),vec2(s,c));
  return vec2(v.x*c - v.y*s,v.x*s + v.y*c); //m * v;
}

В 3Д у меня есть такой код старта частицы в рандомном направлении:

float angle_xz = rand_from_seed_m1_p1(alt_seed) * spread_rad_xz;
float angle_yz = rand_from_seed_m1_p1(alt_seed) * spread_rad_yz;
vec3 direction_xz = vec3(sin(angle_xz), 0.0, cos(angle_xz));
vec3 direction_yz = vec3(0.0, sin(angle_yz), cos(angle_yz));
vec3 spread_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);

vec3 direction_nrm = length(direction) > 0.0 ? normalize(direction) : vec3(0.0, 0.0, 1.0);
// rotate spread to direction
vec3 binormal = cross(vec3(0.0, 1.0, 0.0), direction_nrm);
if (length(binormal) < 0.0001) {
// direction is parallel to Y. Choose Z as the binormal.
  binormal = vec3(0.0, 0.0, 1.0);
}
binormal = normalize(binormal);
vec3 normal = cross(binormal, direction_nrm);
spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z;
VELOCITY = spread_direction * speed;

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

#1
12:32, 26 авг 2022

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

чтобы сгенерить рандомное направление на сфере, проще всего сделать это в полярных координатах, для этого генеришь сначала угол ф как равномерно распределённый 0..2*pi, а потом cos theta, как равномерно распределённое число -1..1. заметь, не угол тета равномерно распределён, а его косинус.

вот тут рассказывается, как сгенерить случайную точку на сфере: https://mathworld.wolfram.com/SpherePointPicking.html (у них угол фи и тета поменяны местами). обрати внимание, что сам угол тета тебе ни в какой момент времени не нужен, достаточно сгенерить его косинус и из косинуса напрямую посчитать синус.

#2
12:48, 26 авг 2022

Suslik
Пущай сразу равномерное распределение делает

float goldenAngle = pi * (3.0f - sqrt(5.0f));

for(int i = 0; i < samples; i++)
{
  float y = 1.0f - ((float)i / (samples - 1)) * 2.0f;

  float radii = sqrt(1.0f - y * y);
  float theta = goldenAngle * i;

  float x = cos(theta) * radii;
  float z = sin(theta) * radii;
}
#3
13:53, 26 авг 2022

Спасибо за помощь!
Прикол что я блин находил всё это. И даже уже готовый код:

+ Показать

Внедрял его, получил странный результат, и начал пытаться делать по другому...
А странность результата в том, что первый отскок работает как надо, а на последующий, второй отскок, частица летит в направлении точки удара первого отскока (то есть тупо угол отражения = углу падения) частица возвращается туда, откуда летела, то есть будто её направление умножается на -1 (это и происходит в функции return v * sign(dot(v, n));)

И в итоге меня походу проблема с генерацией рандомных чисел или что-то вроде того?
На вход функции vec3 randomSpherePoint(vec3 rand) - надо подать 2 рандомных числа (rand.x, rand.y) в диапазоне -1..1, верно же?
Делаю так:

vec3 vec_random = vec3(rand_from_seed_m1_p1(alt_seed),rand_from_seed_m1_p1(alt_seed),0.0);
vec3 new_dir = randomHemispherePoint(vec_random,COLLISION_NORMAL);
VELOCITY = normalize(new_dir) * speed;

Нужно генерировать другой seed?

+ Показать
#4
13:54, 26 авг 2022

Prescott
> На вход функции vec3 randomSpherePoint(vec3 rand) - надо подать 2 рандомных
> числа (rand.x, rand.y) в диапазоне -1..1, верно же?
да, но их нужно подавать _разные_. каждый раз, когда ты генеришь рандом, его нужно генерить разный, а ты дважды используешь одно и то же рандомное число. обычно рандомное число генерится как хеш экранных координат ещё чего-то. вот это "что-то" — это обычно произвольное число. чтобы сгенерить два разных рандомных числа, достаточно это число взять разное:

float3 v0 = hash33(float3(screen_coord.xy, 0.0f));
float3 v1 = hash33(float3(screen_coord.xy, 1.0f));

в случае множественных отражений имеет смысл вместо константы использовать номер баунса.

#5
17:15, 26 авг 2022

Да, спасибо ещё раз, вроде заработало адекватно.
Подобрать эти произвольные числа для более-менее нормального результата оказалось не так просто.

Получилось самая бессмысленная и беспощадная система освещения на частицах:

Запустить видео по клику - Как делать игрыЗапустить видео по клику - Как делать игры

300 000 точек, ну, зато все "фотоны" в 3Д и тени тоже 3Д. Нвидиа РТХ отдыхает!

#6
17:48, 26 авг 2022

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

> Получилось самая бессмысленная и беспощадная система освещения на частицах:
топ, продолжай.

#7
17:48, 26 авг 2022

система освещения на частицах.
300 000 точек, ну, зато все "фотоны"

Частицы сделать крупнее в раз 5 или 8.
И всего 60 000.
И надо еще блюрить.


PS: У Suslika появился конкурент :)))

#8
19:51, 26 авг 2022

Suslik
> если у тебя нормальная хеш-функция, то конкретные значения чисел не должны
> играть никакой роли
Хэш функция стоковая:

+ Показать

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

Suslik
> достаточно чтобы они были побитово различны.
Побитовая различность достигается тем, что на вход разные числа подаются?
Новые сиды генерировал так:

uint new_seed1 = alt_seed + pos_seed + uint(bounces*10+100);
uint new_seed2 = alt_seed + pos_seed + uint(bounces*30+300) + base_number;
#9
19:54, 26 авг 2022

ronniko
> Частицы сделать крупнее в раз 5 или 8.
> И всего 60 000.
> И надо еще блюрить.
>
>
> PS: У Suslika появился конкурент :)))
Да, попробую поэкспериментировать с размерами/типом частиц, но блюрить не знаю как. Надо же блюрить именно 3Д "изображение", весь объём воздуха, а не 2Д... Типа наверное по схожей технике как делают Volumetric Fog. Но мне пока до этого далеко, так же как и до конкуренции с Suslik :)

#10
18:42, 28 авг 2022

Prescott
Это как рейтрейсинг с ограниченной скоростью света?

#11
19:54, 28 авг 2022

Aslan
> Это как рейтрейсинг с ограниченной скоростью света?
Да, скорость частиц можно регулировать, правда получится просто освещение с задержкой.

#12
20:42, 28 авг 2022

Prescott
Частицы исходят из источников света?  Или обратно из камеры?

#13
21:07, 28 авг 2022

Aslan
Текущая реализация самая тупая и наивная - частицы (это Billboard quad mesh) исходят из источника света и рандомно отскакивают от поверхностей по нормальной полусфере, после каждого отскока у частицы на 25% отнимается альфа канал.

#14
21:15, 28 авг 2022

Prescott
Ааа, так частицу видно со стороны. Интересная идея!
Думаю, можно вместо рисования квадов писать пикселы в фреймбуффер уменьшенного размера и раздувать постобработкой, притом аккумулировать несколько кадров

Страницы: 1 2 Следующая »
ПрограммированиеФорумГрафика

Тема в архиве.