简体   繁体   English

如何在 C++ 中进行线程安全的光线投射?

[英]how to make thread safe raycasting in C++?

i am implementing simple plane raycasting in c++ and i used OpenMP for multithreading.我正在用 C++ 实现简单的平面光线投射,我使用 OpenMP 进行多线程处理。
here is the function that goes through all pixels and computes intersections:这是遍历所有像素并计算交点的函数:

 #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;
}

here is the result:结果如下:
光线投射

as you can see some of the pixels are mixed up, but if i uncomment mutex lock and unlock from this code, then results is correct, but it takes even longer to compute than not using pragma omp正如您所看到的,一些像素被混淆了,但是如果我取消注释互斥锁并从此代码解锁,则结果是正确的,但与不使用 pragma omp 相比,计算时间更长

any idea how could i make this more thread safe?知道如何使这个线程更安全吗? when i started, almost half of the pixels were mixed up, then in my custom classes i added every variable as private and create getters and setters, which helped, but its still not completely correct当我开始时,几乎一半的像素被混淆了,然后在我的自定义类中,我将每个变量添加为私有并创建了 getter 和 setter,这有帮助,但仍然不完全正确

EDIT: updated code based on @Jérôme Richard advise and added code for intersection编辑:基于@Jérôme Richard 建议的更新代码并添加了交集代码

Calling a method called bool Plane::Intersect(Ray &) that mutates the Plane object in addition to determining whether there is an intersection, and then later pulling the result of this mutation out of the Plane object while hoping it wasn't changed in another thread in the meantime, is likely your problem (or at least one of them), and moreover is just not great software engineering.调用一个名为bool Plane::Intersect(Ray &) ,除了确定是否存在交集之外,该方法还会对Plane 对象进行变异,然后将该变异的结果从Plane对象中拉出,同时希望它在与此同时,另一个线程可能是您的问题(或至少是其中一个),而且不是很好的软件工程。

I'd recommend getting rid of the whole SetDistanceT / GetDistanceT functionality entirely.我建议完全摆脱整个SetDistanceT / GetDistanceT功能。 Just return the distance from the method that checks intersections directly, and make that method const in both its argument and its instance.只需返回与直接检查相交的方法的距离,并使该方法的参数和实例均为const

(How do you handle the case where dot is zero? You could either return std::numeric_limits<double>::infinity() in that case, or you could have the method return something like a std::pair<bool, double> , or a custom struct, or...) (您如何处理dot为零的情况?在这种情况下您可以返回std::numeric_limits<double>::infinity() ,或者您可以让该方法返回类似std::pair<bool, double> ,或自定义结构,或...)

EDIT: And while you're at it, I'd declare this method as float Intersect(const Ray &) const after you fix it, so that the compiler enforces that it doesn't mutate the ray or the the plane.编辑:当您使用它时,我会在修复它后将此方法声明为float Intersect(const Ray &) const ,以便编译器强制它不会改变光线或平面。 (The second const there says that the method doesn't mutate the instance it's called on, in this case the plane you're intersecting with.) (那里的第二个const表示该方法不会改变它被调用的实例,在这种情况下是与您相交的平面。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM