遮挡剔除过程中OpenTK显卡崩溃

本文关键字:显卡 崩溃 OpenTK 过程中 遮挡 | 更新日期: 2023-09-27 18:21:49

我最近在游戏中实现了Frustum消隐,为了将渲染周期中的最后一滴都挤出,我还决定实现遮挡消隐。它运行得很好,然而,我很难过地发现,如果我不看游戏中的任何东西(如果我向外看,远离游戏对象),我的显卡就会崩溃。我正在运行一个体素类型的游戏,这意味着它是一个充满立方体的世界。如果我的视线中没有立方体,就会发生碰撞。

这是我的渲染循环,其中包含遮挡代码:

protected override void OnRenderFrame( FrameEventArgs e ) {
    base.OnRenderFrame( e );
    GL.MatrixMode( MatrixMode.Modelview );
    GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
    GL.EnableClientState( ArrayCap.VertexArray );
    GL.EnableClientState( ArrayCap.TextureCoordArray );
    GL.DisableClientState( ArrayCap.ColorArray );
    /**
     * Pass 1
     * Do Occlusion Testing
     */
    GameCamera.LookThrough( this , _mousePosition , e );
    foreach( Voxel voxel in World.VisibleVoxels ) {
        if( GameCamera.Frustum.SphereInFrustum( voxel.Location.X , voxel.Location.Y , voxel.Location.Z , 2.0f ) ) {
            try {
                GL.BeginQuery( QueryTarget.SamplesPassed , voxel.OcclusionID );
                voxel.Render( GameCamera );
                GL.EndQuery( QueryTarget.SamplesPassed );
            } catch( Exception ex ) {
                //
                Console.WriteLine( "Setting It" );
                Console.WriteLine( ex.StackTrace );
            }
        }
    }
    GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
    /**
     * Pass 2
     * Normal Rendering
     */
    GameCamera.LookThrough( this , _mousePosition , e );
    foreach( Voxel voxel in World.VisibleVoxels ) {
        if( GameCamera.Frustum.SphereInFrustum( voxel.Location.X , voxel.Location.Y , voxel.Location.Z , 2.0f ) ) {
            try {
                GL.NV.BeginConditionalRender( voxel.OcclusionID , NvConditionalRender.QueryWaitNv );
                voxel.Render( GameCamera );
                GL.NV.EndConditionalRender();
            } catch( Exception ex ) {
                Console.WriteLine( "Testing It" );
                Console.WriteLine( ex.StackTrace );
            }
        }
    }
    GL.DisableClientState( ArrayCap.VertexArray );
    GL.DisableClientState( ArrayCap.TextureCoordArray );
    GL.DisableClientState( ArrayCap.ColorArray );
    RenderDeveloperHud();
    SwapBuffers();
    this.Title = GAME_NAME + " FPS: " + ( int )this.RenderFrequency;
}

我迫切需要找到解决这个问题的办法。在我看来,当我的视口中看不到任何东西时,OpenTK/ONGL会翻来覆去,但我不知道为什么。如果什么都不可见,则循环本身应该通过。我是不是遗漏了什么?

每当我开始游戏并将目光从关卡移开时,我都能真实地再现这种崩溃。所谓崩溃,我的意思是我的整个显示器变黑,挂断,然后继续显示一条消息,说我的显示器驱动程序停止工作

遮挡剔除过程中OpenTK显卡崩溃

应用程序可能会通过传递无效状态或数据使GPU崩溃,有时甚至会传递有效状态或数据。

尝试使用apitrace来跟踪发出给驱动程序的OpenGL命令,并捕获导致崩溃的命令。

使用调试版本的OpenTK.dll运行应用程序也可以帮助您发现错误:OpenTK将在每个GL命令之后使用GL.GetError(),并在出现问题时引发异常。要构建OpenTK的调试版本,请下载源代码并构建OpenTK.sln

尽管这激怒了我,但我不得不再次回答我自己的问题。我想我已经确定了错误,尽管我不太明白……它不再崩溃了。我没有两次通过,而是将渲染周期压缩为一次迭代;这解决了显卡崩溃的问题。任何人都知道为什么这样做:

protected override void OnRenderFrame( FrameEventArgs e ) {
    base.OnRenderFrame( e );
    GL.MatrixMode( MatrixMode.Modelview );
    GL.Clear( ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit );
    GL.EnableClientState( ArrayCap.VertexArray );
    GL.EnableClientState( ArrayCap.TextureCoordArray );
    GL.DisableClientState( ArrayCap.ColorArray );
    /**
     * Pass 1
     * Normal Rendering && Occlusion Test
     */
    GameCamera.LookThrough( this , _mousePosition , e );
    if(NeedsOcclusionPass) {
        foreach(Voxel voxel in World.VisibleVoxels) {
            if(GameCamera.Frustum.SphereInFrustum(voxel.Location.X, voxel.Location.Y, voxel.Location.Z, 2.0f)) {
                GL.BeginQuery(QueryTarget.SamplesPassed, voxel.OcclusionID);
                voxel.Render(GameCamera);
                GL.EndQuery(QueryTarget.SamplesPassed);
            }
        }
        NeedsOcclusionPass = false;
    } else {
        foreach( Voxel voxel in World.VisibleVoxels ) {
            if( GameCamera.Frustum.SphereInFrustum( voxel.Location.X , voxel.Location.Y , voxel.Location.Z , 2.0f ) ) {
                GL.NV.BeginConditionalRender( voxel.OcclusionID , NvConditionalRender.QueryNoWaitNv );
                voxel.Render( GameCamera );
                GL.NV.EndConditionalRender();
            }
        }
        NeedsOcclusionPass = true;
    }
    GL.DisableClientState( ArrayCap.VertexArray );
    GL.DisableClientState( ArrayCap.TextureCoordArray );
    GL.DisableClientState( ArrayCap.ColorArray );
    //RenderDeveloperHud();
    SwapBuffers();
    this.Title = GAME_NAME + " FPS: " + ( int )this.RenderFrequency;
}

但是我上面的原始代码会导致崩溃吗?现在我更困惑了。(不,这个问题不是由GameCamera.LookThrough()的双重调用引起的;看起来两次传球本身就是个错误。

编辑:经过进一步的测试和各种形式的文献,我得出结论,我使用的上述代码完全错误。根据其他消息来源,在开始阻塞查询之前,我应该禁用几乎所有的功能。这意味着:纹理、照明,甚至深度缓冲区。我仍然不知道是什么原因导致我的显卡崩溃,然而,这肯定是因为我对这个话题缺乏理解。

也许是因为在两次传递之间添加了以下行:

GL.Clear(ClearBufferMask.ColorBufferBit|ClearBufferMask.DepthBufferBit);