【问题标题】:Updating scenes in advance while still rendering previous frame提前更新场景,同时仍渲染前一帧
【发布时间】:2012-07-12 23:47:02
【问题描述】:

我目前正在开发一个多线程安全渲染系统,我想知道您对如何在当前渲染前一个场景时正确更新游戏世界的下一步的想法。目前我正在使用带有 Java 的 LWJGL Opengl 绑定。这是我当前设置的游戏循环的伪代码(这可能只是大多数人熟悉的基本循环):

//DrawingLayers are wrappers for in game entities and has an update 
//and render method

game-loop:
    addInputEventsToInputStack()

    removeCompletedDrawingLayers()

    foreach layer in DrawingLayerQueue :
        layer.update(deltaTime) //update position/color/size for entity
        layer.render() //performs OpenGL calls
        if(layer.isCompleted):
            addToCompletedDrawingLayersList()


    swapBuffers() //blocks until scene is fully rendered
goto game-loop

我的问题在于 swapBuffers() 方法,因为它会阻塞直到渲染场景,这意味着在此过程中我无法执行任何更新。我对如何解决这个问题的想法是:

拥有我用于更新实体状态的所有 DrawingLayers 的副本,并将另一个副本作为渲染线程的参考。在渲染帧时,在swapBuffers() 之前启动一个线程以更新未使用的副本。

我对这种方法持谨慎态度,因为我相信在每一帧之前创建副本会使系统速度变慢,超出我的预期。

我的方法有意义吗?如果没有,你们对如何做到这一点有什么建议吗?我愿意进行彻底的重组。

更新:根据 datenwolf 的建议,我已将游戏循环更改为以下内容:

//DrawingLayers are wrappers for in game entities and has an update 
//and render method


//A future for the pre-processing task
Future preProcess = null

game-loop:

    //Update: checks if we have a preprocessed update to wait for
    //and waits for it to complete
    if(preProcess != null):
        preProcess.get()
        preProcess = null

    addInputEventsToInputStack()

    removeCompletedDrawingLayers()

    foreach layer in DrawingLayerQueue :
        layer.render() //performs OpenGL calls
        if(layer.isCompleted):
            addToCompletedDrawingLayersList()

    //UPDATE: the following just calls all the update methods for the layers
    // in a new thread
    preProcess = executorService.submit(new UpdateRunnable())

    swapBuffers() //blocks until scene is fully rendered
goto game-loop

到目前为止,我的性能有了显着提高。可能有一些我看不到的比赛条件问题,但总的来说我对这种改进感到满意。

【问题讨论】:

    标签: java multithreading opengl lwjgl


    【解决方案1】:

    在 swapBuffers() 方法中,因为它在渲染场景之前一直阻塞

    缓冲区交换的阻塞仅在完成渲染时部分实现。由于等待回溯,它通常也会阻塞。但是 OpenGL 向您保证,在任何绘图命令返回后,可以安全地修改它访问的缓冲区,而不会损害任何未决的渲染操作。该实现需要对所有数据进行复制或写时复制映射。

    或者简而言之:只需修改缓冲区中的数据。一旦绘图调用(glDrawArrays、glDrawElements)返回,这样做是安全的。

    【讨论】:

    • 我已根据您的评论使用我所做的更改更新了我的原始问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多