在学校的一个项目中,我们的任务是写一个光线跟踪器。我选择使用C++,因为它是我最喜欢的语言,但是我得到了一些奇怪的东西。
请记住,我们还处于本课程的前几节课,所以现在我们仅限于检查光线是否击中某个物体。
当我的光线跟踪器很快完成(不到1秒的时间用于实际的光线跟踪)我注意到并不是所有的点击都在我的“帧缓冲区”中注册。
为了举例说明,这里有两个例子:
2.:
我想知道有没有人能帮我弄清楚为什么会这样?
我应该提到我的应用程序是多线程的,代码的多线程部分如下所示:
Stats RayTracer::runParallel(const std::vector<Math::ivec2>& pixelList, const Math::vec3& eyePos, const Math::vec3& screenCenter, long numThreads) noexcept
{
//...
for (int i = 0; i < threads.size(); i++)
{
threads[i] = std::thread(&RayTracer::run, this, splitPixels[i], eyePos, screenCenter);
}
for (std::thread& thread: threads)
{
thread.join();
}
//...
}
Stats RayTracer::run(const std::vector<Math::ivec2>& pixelList, const Math::vec3& eyePos, const Math::vec3& screenCenter) noexcept
{
this->frameBuffer.clear(RayTracer::CLEAR_COLOUR);
// ...
for (const Math::ivec2& pixel : pixelList)
{
// ...
for (const std::shared_ptr<Objects::Object>& object : this->objects)
{
std::optional<Objects::Hit> hit = object->hit(ray, pixelPos);
if (hit)
{
// ...
if (dist < minDist)
{
std::lock_guard lock (this->frameBufferMutex);
// ...
this->frameBuffer(pixel.y, pixel.x) = hit->getColor();
}
}
}
}
// ...
}
这是framebuffer类的运算符()
class FrameBuffer
{
private:
PixelBuffer buffer;
public:
// ...
Color& FrameBuffer::operator()(int row, int col) noexcept
{
return this->buffer(row, col);
}
// ...
}
使用PixelBuffer的操作符()
class PixelBuffer
{
private:
int mRows;
int mCols;
Color* mBuffer;
public:
// ...
Color& PixelBuffer::operator()(int row, int col) noexcept
{
return this->mBuffer[this->flattenIndex(row, col)];
}
// ...
}
我没有费心使用任何同步原语,因为每个线程都会从完整图像中指定一个特定的像素子集。线程为每个指定的像素投射一条光线,并将结果颜色写回该像素槽中的颜色缓冲区。这意味着,当我的所有线程同时访问(并写入)同一对象时,它们不会写入相同的内存位置。
应该注意的是,我在线程之间划分像素的方式决定了伪影的方向。如果我给每个线程一组行,工件将是水平线,如果我给每个线程一组列,工件将是垂直线。
建议之后
Jeremy Friesner
我在一个线程上运行了10次raytracer,没有任何问题,所以问题确实看起来是一个争用条件。