Это моделирование жидкости основано на статье Stam. На странице 7 он описывает основную идею адвекции:
Начните с двух сеток: одна содержит значения плотности с предыдущего временного шага, а вторая - новые значения. Для каждой ячейки сетки последнего мы отслеживаем положение центра ячейки в обратном направлении через поле скоростей. Затем мы линейно интерполируем из сетки предыдущих значений плотности и присваиваем это значение текущей ячейке сетки.
Код Advect. Две сетки плотности: d
и d0
, u
и v
- компоненты скорости, dt
- временной шаг, N
(глобальный) - размер сетки, b
можно игнорировать:
void advect(int b, vfloat &d, const vfloat &d0, const vfloat &u, const vfloat &v, float dt, std::vector<bool> &bound)
{
float dt0 = dt*N;
for (int i=1; i<=N; i++)
{
for (int j=1; j<=N; j++)
{
float x = i - dt0*u[IX(i,j)];
float y = j - dt0*v[IX(i,j)];
if (x<0.5) x=0.5; if (x>N+0.5) x=N+0.5;
int i0=(int)x; int i1=i0+1;
if (y<0.5) y=0.5; if (y>N+0.5) y=N+0.5;
int j0=(int)y; int j1=j0+1;
float s1 = x-i0; float s0 = 1-s1; float t1 = y-j0; float t0 = 1-t1;
d[IX(i,j)] = s0*(t0*d0[IX(i0,j0)] + t1*d0[IX(i0,j1)]) +
s1*(t0*d0[IX(i1,j0)] + t1*d0[IX(i1,j1)]);
}
}
set_bnd(b, d, bound);
}
Этот метод краток и работает достаточно хорошо, но мне сложно понять реализацию границ объекта, потому что значения отслеживаются в обратном направлении и интерполируются. Мое текущее решение - просто вытолкнуть плотность за границы, если рядом с ней есть пустое пространство (или пробелы), но это неточно и вызывает увеличение плотности, особенно в углах и областях с диагональной скоростью. удар> только визуально точный. Ищу "правильность" сейчас.
Соответствующие части моего граничного кода:
void set_bnd(const int b, vfloat &x, std::vector<bool> &bound)
{
//...
for (int i=1; i<=N; i++)
{
for (int j=1; j<=N; j++)
{
if (bound[IX(i,j)])
{
//...
else if (b==0)
{
// Distribute density from bound to surrounding cells
int nearby_count = !bound[IX(i+1,j)] + !bound[IX(i-1,j)] + !bound[IX(i,j+1)] + !bound[IX(i,j-1)];
if (!nearby_count) x[IX(i,j)] = 0;
else
x[IX(i,j)] = ((bound[IX(i+1,j)] ? 0 : x[IX(i+1,j)]) +
(bound[IX(i-1,j)] ? 0 : x[IX(i-1,j)]) +
(bound[IX(i,j+1)] ? 0 : x[IX(i,j+1)]) +
(bound[IX(i,j-1)] ? 0 : x[IX(i,j-1)])) / surround;
}
}
}
}
}
bound
- это вектор bools со строками и столбцами от 0
до N+1
. Граничные объекты устанавливаются перед основным циклом путем установки координат ячейки в bound
на 1
.
В документе расплывчато говорится: «Тогда мы просто должны добавить некоторый код в set_bnd()
процедуру, чтобы заполнить значения для занятых ячеек из значений их прямых соседей», что вроде того, что я делаю. Я ищу способ более точной реализации границ, то есть наличие не жидких твердых границ и, возможно, в конечном итоге поддержки границ для нескольких жидкостей. Визуальное качество намного важнее правильности физики.
bound
? Я предполагаю, что граничные ячейки - это строка 0, строка N + 1, столбец 0 и столбец N + 1 [из диаграммы в статье]? Кроме того,set_bnd
имеетelse if (b==0)
, аif
для этогоelse
[выше] отсутствует. Вы можете добавить еще немного? Я вижу некоторые проблемы [проблема, похожая на границы видеокадров и векторы движения], но прежде чем я попытаюсь ответить, я хотел бы получить немного больше информации. Кроме того, когдаb
ноль / ненулевое значение? - person Craig Estey   schedule 31.12.2015set_bnd
относятся к граничным условиям, которые не нужны для вопроса. Полная версия моего кода находится здесь - person qwr   schedule 31.12.2015forall bpt in bound: bpt.i,bpt.j,bpt.xxx
(например, предварительное вычисление большего количества данных, поэтому меньше if в цикле). Чтобы лучше видеть, я сделал сетку внизу цикла рендеринга:SDL_SetRenderDrawColor(renderer,100,100,0,0); SDL_RenderDrawRect(renderer,&r);
, но некоторые линии имеют двойную ширину из-за округления - person Craig Estey   schedule 01.01.2016advect
делается - person qwr   schedule 01.01.2016advect
для работы с коллизиями вместо того, что я делаю сейчас. Текущий код выглядит визуально приемлемым со стационарными границами, но для расширения, такого как движущиеся границы, такие как две жидкости (огонь и воздух, вода и воздух), потребуется реальное решение для адвекта. - person qwr   schedule 01.01.2016