ВВЕДЕНИЕ
Я получаю нежелательную пульсацию и замедление при рендеринге 2d-частиц, которые должны рисоваться слабо (низкая альфа) и оставлять затухающий след под действием силы тяжести. Ниже приведено структурированное объяснение. Я думаю, что изолировал это довольно хорошо, но я не могу ни в малейшей степени объяснить, что происходит или какой процесс вызывает мои сбои, так что, если вы можете, это было бы здорово! К вашему сведению: я не думаю, что это гонка данных, я не понимаю, как это возможно здесь.
ЦЕЛЬ:
Я пытаюсь изучить C++ самостоятельно, написав 2D-симуляцию частиц с использованием SDL. Я новичок в этом, поэтому ошибка новичка невозможна. Моделирование должно иметь фиксированный временной шаг обновления физики для детерминированного поведения. Я реализовал это задолго до того, как начал использовать многопоточность, с помощью переменной «lag». Физика и рендеринг в проекте какое-то время не менялись и до сих пор всегда работали нормально.
Чтобы увеличить количество частиц, я начал использовать многопоточность. Сначала я запускал параллельные рабочие потоки физики, ждал обновления, а затем выполнял рендеринг. Это сработало без каких-либо проблем. Теперь я запускаю рабочие потоки физики и параллельно рендерю данные из предыдущего кадра. На самом деле это работает отлично, пока я не попытаюсь реализовать фиксированный физический временной шаг.
СТРУКТУРА КОДА:
это общий обзор:
во время (работа){
- вычисление времени, прошедшего с момента начала предыдущего кадра (задержка)
- вычисление количества физических кадров ( while(lag>= TIMESTEP){updates ++; lag -= TIMESTEP;} )
- вызов физического работника в нескольких потоках на частицахWrite (указатель)
- рендеринг всех частиц на частицахЧтение (указатель)
- дождаться потоков физического работника
- поменять местами частицыЧтение и частицыЗапись
- SDL_Delay до тех пор, пока кадрTime = TIMESTEP (если кадр был быстрее, чем TIMESTEP)
СИМПТОМЫ:
Когда я реализую цикл в обновлении физики, который выполняет «обновления» раз, частицы «пульсируют», их альфа-канал отображается неправильно. Иногда они, кажется, прыгают из позиции, но их общая модель движения правильная.
Некоторое замедление также нарастает, кадры становятся все медленнее и медленнее, пока я не смотрю Powerpoint, в течение 10-20 секунд.
ЧТО Я ПРОБОВАЛ:
Вот здесь это становится странным, и почему я вообще не понимаю, что происходит.
--> swap while для цикла структура цикла for для «обновлений» > проблема сохраняется.
--> передайте обновление в PhysicsWorker по ссылке, а не просто передавайте (также пробовал указатель) > проблема сохраняется.
--> убедитесь, что я не записываю обновления в физический цикл > проблема сохраняется.
--> полностью выведите цикл « while (updates >0)» из PhysicsWorker, обернув его вокруг всего кода кадра и используя if (счетчик == 0) для части рендеринга (т.е. убедитесь, что он визуализируется только один раз) > проблема сохраняется.
--> передайте значение обновлений в новую переменную в (или непосредственно перед вызовом) Physicsworker > проблема сохраняется.
--> измените тип обновлений переменной (Uint32, int, size_t) > проблема сохраняется.
--> задержка печати и обновление каждого 50-го кадра на убедитесь, что это разумные значения и не накапливаются странным образом (они кажутся совершенно нормальными и, как и ожидалось).
--> уменьшите количество частиц в 10 раз, чтобы все это не могло занять больше времени, чем TIMESTEP > проблема сохраняется (замедление занимает намного больше времени, но оно все еще существует).
--> поменяйте местами последовательность переменных в объявлении updateChunk void > проблема сохраняется.
НО когда я просто говорю "Uint32 update=1" (или 0. или 2. или 3. Не важно) проблема полностью решена и все работает нормально! Это то, что мне кажется совершенно странным, потому что, когда я включаю переменную задержки, обновления также имеют значение Uint32 = 1, но вычисляются только перед их использованием.
Кажется, имеет значение только то, использую ли я вычисленное значение обновлений или нет. Не имеет значения, где я поместил цикл (внутри или вне потоков), какова на самом деле длительность кадра или что-то еще. Я этого не понимаю. Как уже было сказано, я печатал переменную обновления каждый 50-й кадр, и она всегда равна 1 для меньшего количества частиц.
АКТИЧЕСКИЙ КОД
Вот соответствующие фрагменты кода, сначала обновление void:
void updateChunk(std::vector
& particles, const std::vector& planets, size_t start, size_t end, Uint32 updates)
{
Uint32 up = updates;
while (up > 0)
{
for (size_t i = start; i < end; ++i)
{
// create handles
Particle& p = particles;
// Update acceleration
p.ax = -p.vx*dampingConstant - signFunction(p.vx)*fixedDamping;
p.ay = -p.vy*dampingConstant + GRAV - signFunction(p.vy)*fixedDamping;
// Calculate planet acceleration
for (size_t s = 0; s < planets.size(); ++s)
{
// Get distances from planet
const Planet& planet = planets;
float dxp = p.x - float(planet.x);
float dyp = p.y - float(planet.y);
float dMag = fastSqrt(float(dxp * dxp + dyp * dyp));
// Sin and cos from fraction, not sin function. Small float in denominator to ensore no /0.
float axp = std::abs(dxp / (dMag + 0.0001f)) * (planet.gravity / (dMag + 4.0f));
float ayp = std::abs(dyp / (dMag + 0.0001f)) * (planet.gravity / (dMag + 4.0f));
p.ax -= signFunction(dxp)*axp;
p.ay -= signFunction(dyp)*ayp;
}
// Update velocity
p.vy += (p.ay * (float)TIMESTEP) / 1000.0f;
p.vx += (p.ax * (float)TIMESTEP) / 1000.0f;
// Update position
p.x += (p.vx*(float)TIMESTEP) / 1000.0f;
p.y += (p.vy*(float)TIMESTEP) / 1000.0f;
// Bounce of walls
if (p.x - EPS < 0) {
p.vx *= -1.0f;
p.x = EPS;
}
else if (p.x + EPS > WIDTH - 1) {
p.vx *= -1.0f;
p.x = WIDTH - 1 - EPS;
}
if (p.y - EPS = HEIGHT - 1) {
p.vy *= -1.0f;
p.y = HEIGHT - 1 - EPS;
}
}
up -= 1;
}
}
Остальное находится в int main(). Я, очевидно, опустил ненужные части, но включил всю часть рендеринга, поскольку вижу и визуальные сбои:
while (running)
{
// time logic, get current time, elapsed time, total elapsed time etc.
Uint32 currentTime = SDL_GetTicks();
Uint32 elapsedTime = currentTime - previousTime;
previousTime = currentTime;
lag += elapsedTime;
totalTime += elapsedTime;
// Calculate the amount of physics updates
Uint32 updates = 0;
while (lag >= TIMESTEP) {
updates++;
lag -= TIMESTEP;
}
// Call the physics update function on multiple threads.
std::vector threads;
for (int t = 0; t < NUMTHREADS; ++t) {
size_t start = t chunkSize;
size_t end = (t == NUMTHREADS - 1) ? particlesWrite->size() : start + chunkSize;
threads.emplace_back(updateChunk, std::ref(*(particlesWrite)), std::ref(planets), start, end, updates);
}
// Set Render Draw colour for all particles
SDL_SetRenderDrawColor(renderer, 0, 255, 255, 30);
// Render previous frame
// Render our moving pixel, if not equal to last known position
// Cast to int first
for (int u = 0; u < particlesA.size(); u++)
{
// create handles
Particle& p = (*particlesRead);
PrevPosition& pp = prevPositions;
int newX = int(p.x + 0.5f);
int newY = int(p.y + 0.5f);
int dx = abs(newX - pp.x);
int dy = abs(newY - pp.y);
if (newX != pp.x || newY != pp.y) {
if (abs(dx)
Подробнее здесь: https://stackoverflow.com/questions/798 ... ting-fixed
Нежелательная пульсация при рендеринге и совокупное замедление при реализации фиксированного временного шага физики в мн ⇐ C++
Программы на C++. Форум разработчиков
1763670469
Anonymous
ВВЕДЕНИЕ
Я получаю нежелательную пульсацию и замедление при рендеринге 2d-частиц, которые должны рисоваться слабо (низкая альфа) и оставлять затухающий след под действием силы тяжести. Ниже приведено структурированное объяснение. Я думаю, что изолировал это довольно хорошо, но я не могу ни в малейшей степени объяснить, что происходит или какой процесс вызывает мои сбои, так что, если вы можете, это было бы здорово! К вашему сведению: я не думаю, что это гонка данных, я не понимаю, как это возможно здесь.
ЦЕЛЬ:
Я пытаюсь изучить C++ самостоятельно, написав 2D-симуляцию частиц с использованием SDL. Я новичок в этом, поэтому ошибка новичка невозможна. Моделирование должно иметь фиксированный временной шаг обновления физики для детерминированного поведения. Я реализовал это задолго до того, как начал использовать многопоточность, с помощью переменной «lag». Физика и рендеринг в проекте какое-то время не менялись и до сих пор всегда работали нормально.
Чтобы увеличить количество частиц, я начал использовать многопоточность. Сначала я запускал параллельные рабочие потоки физики, ждал обновления, а затем выполнял рендеринг. Это сработало без каких-либо проблем. Теперь я запускаю рабочие потоки физики и параллельно рендерю данные из предыдущего кадра. На самом деле это работает отлично, пока я не попытаюсь реализовать фиксированный физический временной шаг.
СТРУКТУРА КОДА:
это общий обзор:
во время (работа){
- вычисление времени, прошедшего с момента начала предыдущего кадра (задержка)
- вычисление количества физических кадров ( while(lag>= TIMESTEP){updates ++; lag -= TIMESTEP;} )
- вызов физического работника в нескольких потоках на частицахWrite (указатель)
- рендеринг всех частиц на частицахЧтение (указатель)
- дождаться потоков физического работника
- поменять местами частицыЧтение и частицыЗапись
- SDL_Delay до тех пор, пока кадрTime = TIMESTEP (если кадр был быстрее, чем TIMESTEP)
СИМПТОМЫ:
Когда я реализую цикл в обновлении физики, который выполняет «обновления» раз, частицы «пульсируют», их альфа-канал отображается неправильно. Иногда они, кажется, прыгают из позиции, но их общая модель движения правильная.
Некоторое замедление также нарастает, кадры становятся все медленнее и медленнее, пока я не смотрю Powerpoint, в течение 10-20 секунд.
ЧТО Я ПРОБОВАЛ:
Вот здесь это становится странным, и почему я вообще не понимаю, что происходит.
--> swap while для цикла структура цикла for для «обновлений» > проблема сохраняется.
--> передайте обновление в PhysicsWorker по ссылке, а не просто передавайте (также пробовал указатель) > проблема сохраняется.
--> убедитесь, что я не записываю обновления в физический цикл > проблема сохраняется.
--> полностью выведите цикл « while (updates >0)» из PhysicsWorker, обернув его вокруг всего кода кадра и используя if (счетчик == 0) для части рендеринга (т.е. убедитесь, что он визуализируется только один раз) > проблема сохраняется.
--> передайте значение обновлений в новую переменную в (или непосредственно перед вызовом) Physicsworker > проблема сохраняется.
--> измените тип обновлений переменной (Uint32, int, size_t) > проблема сохраняется.
--> задержка печати и обновление каждого 50-го кадра на убедитесь, что это разумные значения и не накапливаются странным образом (они кажутся совершенно нормальными и, как и ожидалось).
--> уменьшите количество частиц в 10 раз, чтобы все это не могло занять больше времени, чем TIMESTEP > проблема сохраняется (замедление занимает намного больше времени, но оно все еще существует).
--> поменяйте местами последовательность переменных в объявлении updateChunk void > проблема сохраняется.
НО когда я просто говорю "Uint32 update=1" (или 0. или 2. или 3. Не важно) проблема полностью решена и все работает нормально! Это то, что мне кажется совершенно странным, потому что, когда я включаю переменную задержки, обновления также имеют значение Uint32 = 1, но вычисляются только перед их использованием.
Кажется, имеет значение только то, использую ли я вычисленное значение обновлений или нет. Не имеет значения, где я поместил цикл (внутри или вне потоков), какова на самом деле длительность кадра или что-то еще. Я этого не понимаю. Как уже было сказано, я печатал переменную обновления каждый 50-й кадр, и она всегда равна 1 для меньшего количества частиц.
АКТИЧЕСКИЙ КОД
Вот соответствующие фрагменты кода, сначала обновление void:
void updateChunk(std::vector
& particles, const std::vector& planets, size_t start, size_t end, Uint32 updates)
{
Uint32 up = updates;
while (up > 0)
{
for (size_t i = start; i < end; ++i)
{
// create handles
Particle& p = particles[i];
// Update acceleration
p.ax = -p.vx*dampingConstant - signFunction(p.vx)*fixedDamping;
p.ay = -p.vy*dampingConstant + GRAV - signFunction(p.vy)*fixedDamping;
// Calculate planet acceleration
for (size_t s = 0; s < planets.size(); ++s)
{
// Get distances from planet
const Planet& planet = planets[s];
float dxp = p.x - float(planet.x);
float dyp = p.y - float(planet.y);
float dMag = fastSqrt(float(dxp * dxp + dyp * dyp));
// Sin and cos from fraction, not sin function. Small float in denominator to ensore no /0.
float axp = std::abs(dxp / (dMag + 0.0001f)) * (planet.gravity / (dMag + 4.0f));
float ayp = std::abs(dyp / (dMag + 0.0001f)) * (planet.gravity / (dMag + 4.0f));
p.ax -= signFunction(dxp)*axp;
p.ay -= signFunction(dyp)*ayp;
}
// Update velocity
p.vy += (p.ay * (float)TIMESTEP) / 1000.0f;
p.vx += (p.ax * (float)TIMESTEP) / 1000.0f;
// Update position
p.x += (p.vx*(float)TIMESTEP) / 1000.0f;
p.y += (p.vy*(float)TIMESTEP) / 1000.0f;
// Bounce of walls
if (p.x - EPS < 0) {
p.vx *= -1.0f;
p.x = EPS;
}
else if (p.x + EPS > WIDTH - 1) {
p.vx *= -1.0f;
p.x = WIDTH - 1 - EPS;
}
if (p.y - EPS = HEIGHT - 1) {
p.vy *= -1.0f;
p.y = HEIGHT - 1 - EPS;
}
}
up -= 1;
}
}
Остальное находится в int main(). Я, очевидно, опустил ненужные части, но включил всю часть рендеринга, поскольку вижу и визуальные сбои:
while (running)
{
// time logic, get current time, elapsed time, total elapsed time etc.
Uint32 currentTime = SDL_GetTicks();
Uint32 elapsedTime = currentTime - previousTime;
previousTime = currentTime;
lag += elapsedTime;
totalTime += elapsedTime;
// Calculate the amount of physics updates
Uint32 updates = 0;
while (lag >= TIMESTEP) {
updates++;
lag -= TIMESTEP;
}
// Call the physics update function on multiple threads.
std::vector threads;
for (int t = 0; t < NUMTHREADS; ++t) {
size_t start = t chunkSize;
size_t end = (t == NUMTHREADS - 1) ? particlesWrite->size() : start + chunkSize;
threads.emplace_back(updateChunk, std::ref(*(particlesWrite)), std::ref(planets), start, end, updates);
}
// Set Render Draw colour for all particles
SDL_SetRenderDrawColor(renderer, 0, 255, 255, 30);
// Render previous frame
// Render our moving pixel, if not equal to last known position
// Cast to int first
for (int u = 0; u < particlesA.size(); u++)
{
// create handles
Particle& p = (*particlesRead)[u];
PrevPosition& pp = prevPositions[u];
int newX = int(p.x + 0.5f);
int newY = int(p.y + 0.5f);
int dx = abs(newX - pp.x);
int dy = abs(newY - pp.y);
if (newX != pp.x || newY != pp.y) {
if (abs(dx)
Подробнее здесь: [url]https://stackoverflow.com/questions/79825942/undesired-pulsating-in-rendering-and-cumulative-slowdown-when-implementing-fixed[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия