Java Raytracer:每个线程的屏幕不同部分的多线程CPU渲染

时间:2014-09-27 15:42:43

标签: java rendering real-time raytracing

所以我一直在使用一个简单的实时光线跟踪器,使用纯Java,现在我有大多数东西正常工作,从漫反射光照和镜面高光到光线反射和折射,我开始想知道我是否可以做一个简约的冒险游戏使用我的新发动机。阻止我这样做的唯一因素是高于512x512分辨率的性能不佳。

所以我决定在Java中阅读一些关于多线程的内容,因为我从来没有为我的项目需要多个线程,因此我以前没有关于该主题的经验。所以在那之后我尝试了各种方法来实现多线程渲染,最后得到了一个点,4个线程分别渲染屏幕的给定部分并将其传递给代表屏幕的缓冲图像的像素数据。而且我对此非常好,现在唯一真正的问题是将渲染与更新整个图像同步并且我尝试了很多方法来做到这一点但是不能提出任何好的,它总是闪烁或有一些噪音或者是块状的,因为即使在刷新屏幕时也会一直呈现内容。

这是我在github中的项目源代码,渲染是在Engine.java中完成的:https://github.com/Harha/JRay

我试图通过谷歌和stackoverflow直接寻找答案,没有运气,似乎没有人在过去公开做过这样的事情,或者我只是不好寻找事情。无论如何,我没有想法,并想知道这里是否有人可以提出一些明智的答案,可以用来将所有渲染线程与更新位图的主线程同步。

在此先感谢,我绝不想要用勺子,但就像我说的那样,我真的没有想法......

编辑:这是我的固定运行循环。

/*
 * Main run method.
 * Handles the update and render methods.
 */
public void run() {
    for (int i = 0; i < THREAD_COUNT; i++) {
        updateDelta(i);
        lastFPS[i] = getTime();
    }
    requestFocus();
    while (running) {
        updateDelta(0);
        update(delta[0]);
        runRenderThreads();
        try {
            e.awaitTermination(10, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        render();
    }
    stop();
}

渲染线程等待10毫秒完成给定任务,如果超过该时间,则只需将图像渲染到render()中的缓冲区并重新开始,并不关心任务是否堆积。

2 个答案:

答案 0 :(得分:2)

光线跟踪实际上是多线程的一个主要示例,因为它具有简单的任务分配和大的性能要求,所以这肯定是以前完成的。

我建议您使用double buffering。也就是说,您不直接在屏幕上绘制,而是在不可见的缓冲区上绘制,并为每个线程分配相同数量的像素。等到每个线程完成后再用可见缓冲区交换可见性,然后从新图像开始。如果仍然出现闪烁,请尝试垂直同步。

<强>伪代码

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Raytracer
{
    final static int THREADS = 4;

    public static void main(String[] args) throws InterruptedException
    {
        ExecutorService renderPool = Executors.newFixedThreadPool(THREADS);
        while(true)
        {
            for(int i=0;i<THREADS;i++)
            {
                renderPool.execute(createRenderThread(i));
            }
            if(renderPool.awaitTermination(1,TimeUnit.MINUTES))
            {
                // delay here in case you want to artifically limit the frame rate  
                // v-sync if necessary here
                swapBuffers(); // should be available from your graphics library, e.g. open GL
            }
        }

    }

    private static Runnable createRenderThread(final int i)
    {
        return new Runnable()
        {
            @Override public void run()
            {
                for(int x=..;x<..;x++)
                    for(int y=..;y<..;y++)
                        render(x,y);
                // do something ...
            }
        };
    }

}

答案 1 :(得分:1)

除了双缓冲之外,您还应确保在缓冲区完成后使用synchronized来交换缓冲区。

您可以考虑使用显卡进行渲染,但速度会比使用CPU快得多。