Как сделать потокобезопасное Raycasting в C ++? - PullRequest
0 голосов
/ 29 февраля 2020

Я реализую простую плоскую лучевую трансляцию в c ++, и я использовал OpenMP для многопоточности.
здесь есть функция, которая проходит через все пиксели и вычисляет пересечения:

 #pragma omp parallel for num_threads(std::thread::hardware_concurrency())
 for (int x = 0; x < camera_.GetWidth(); x++)
 {
    for (uint32_t y = 0; y < camera_.GetHeight(); y++)
    {
      Ray ray(camera_.GetPosition());
      ray.SetDirection(GetDirection(glm::vec2((2.0f * x) / camera_.GetWidth() - 1.0f, (2.0f * y) / camera_.GetHeight() - 1.0f)));

      cogs::Color3f temp = cogs::Color3f(0, 0, 0);

      for (uint16_t p = 0; p < models_.size(); p++)
      {
        //mutex.lock();
        if (models_.at(p)->Intersection(ray))
        {
          ray.SetParamT(models_.at(p)->GetDistanceT());
          temp = models_.at(p)->GetColor() * (camera_.GetLightEnergy() / ray.GetParamT());
        }
        //mutex.unlock();
      }
      renderer.SetPixel(x, y, temp );
    }
  }  


bool Plane::Intersection(Ray &ray)
{

  float dot = glm::dot(ray.GetDirection(), normal_);

  if (dot == 0.0f)
  {
    return false;
  }

  float t = glm::dot(reference_ - ray.GetOrigin(), normal_) / dot;

  if (t <= 0.0001 || t > ray.GetParamT())
  {
    return false;
  }

  SetDistanceT(t);

  return true;
}

вот результат:
raycast

Как вы можете видеть, некоторые пиксели перепутаны, но если я раскомментирую блокировку и разблокировку mutex из этого кода, то результаты будут правильными, но это займет еще больше времени. вычислить, чем не используя Pragma omp

Любая идея, как я могу сделать это более потокобезопасным? когда я начинал, почти половина пикселей смешивалась, затем в своих пользовательских классах я добавил каждую переменную как приватную и создал методы получения и установки, что помогло, но все еще не полностью корректно

РЕДАКТИРОВАТЬ: обновление на основе кода на @ Jérôme Richard посоветуйте и добавили код для пересечения

1 Ответ

1 голос
/ 29 февраля 2020

Вызов метода с именем bool Plane::Intersect(Ray &), который мутирует объект Plane в дополнение к определению, существует ли пересечение, и затем позднее вытягивает результат этой мутации из объекта Plane, надеясь на это тем временем не был изменен в другом потоке, скорее всего, это ваша проблема (или, по крайней мере, одна из них), и более того, это просто не очень хорошая разработка программного обеспечения.

Я бы порекомендовал избавиться от всего SetDistanceT / GetDistanceT функциональность целиком. Просто верните расстояние от метода, который напрямую проверяет пересечения, и задайте этому методу const и его аргумент, и его экземпляр.

(Как вы справляетесь со случаем, когда dot равен нулю? вернуть std::numeric_limits<double>::infinity() в этом случае, или вы могли бы иметь метод, возвращающий что-то вроде std::pair<bool, double>, или пользовательскую структуру, или ...)

...