1

我正在使用 OpenTK 在 C# 中编写一个简单的光线投射器。我希望我的视图每秒刷新 60 次,所以我有一个计时器调用我的 Render() 函数,它在屏幕上显示纹理。

我想使用递归函数通过将场景划分为较小的矩形并渲染每个矩形来渲染我的场景,直到矩形大小为 1px。我的递归将像素的颜色写入字节数组,我需要将其转换为纹理。递归非常慢,所以每当我的场景发生变化时,我都想在背景线程中运行它。

同步线程的正确方法是什么,以便一个写入纹理数组(大约需要一秒钟),但另一个线程每 1/60 秒读取一次并在屏幕上打印?

    byte[, ,] texture;

递归:

    public void RenderAdaptively(int top, int left, int width, int height)
    {
        Color color = getColor(top, left);
        for (int i = top; i < top + width + 1; i++)
        {
            for (int j = left; j < left + height; j++)
            {
                texture[i, j, 0] = color.R;
                texture[i, j, 1] = color.G;
                texture[i, j, 2] = color.B;
            }
        }

        int halfw = width / 2;
        int halfh = height / 2;
        int newwidth = width - halfw;
        int newheight = height - halfh;

        if (width > 1 && height > 1)
        {
            RenderAdaptively(top, left, halfw, halfh, false);
            RenderAdaptively(top + halfw, left + halfh, newwidth, newheight, false);
            RenderAdaptively(top, left + halfh, halfw, newheight, false);
            RenderAdaptively(top + halfw, left, newwidth, halfh, false);
        }
    }

在另一个线程中:

    raycasting_texture = TexUtil.CreateRGBTexture(width, height, texture);
4

1 回答 1

1

你有几个选择可以尝试,但是我会这样做:

  • 有两个缓冲区用于将纹理存储为字节数组,例如01

  • 在一个缓冲区中进行纹理计算,

  • 完成后,通过将 a 设置volatile int updated_buffer为更新的缓冲区索引来发出信号。

  • 定期读取另一个线程updated_buffer,并保留其最新值的副本。当该副本和 int 不同步时,更新副本并将纹理上传到内存,

请注意,此解决方案依赖于几件事:

  1. 只有两个线程处理字节数组缓冲区,

  2. updated_buffer仅由(纹理)消费者线程读取并由生产者线程写入,

  3. 最重要的是,纹理上传明显比计算快。

如果 #2 或 #3 损坏,您将不得不对纹理缓冲区使用更严格的同步方法,如互斥锁,以确保纹理缓冲区在仍在上传时不会被覆盖。

最后,您的递归计算可以通过移动到低于某个阈值(例如 8*8 像素块)的迭代得到轻微的提升,而不是一直下降到 1px。事实上,迭代地做这一切应该更快(如果在单个内核上的单个线程中完成),尽管它在很大程度上取决于计算像素的算法。

于 2013-03-10T14:01:28.150 回答