我最近在我的游戏中实施了Frustum剔除,并试图挤出渲染周期的最后一滴,我还决定实施Occlusion Culling。它的工作非常出色,然而,我很痛苦地发现如果我不在游戏中看任何东西(如果我注意到虚空并远离我的游戏对象),我的显卡就会崩溃。我正在运行一个体素型游戏,这意味着它是一个充满立方体的世界。如果我的视线中没有立方体,则会发生崩溃。
这是我的渲染循环,其中包含遮挡代码:
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 / OpenGL会翻动它,但我不知道为什么。如果没有任何可见的话,循环本身应该通过。我在这里错过了什么吗?
每次我开始游戏并远离关卡时,我都能真正重现这次崩溃。崩溃我的意思是我的整个显示器变黑,挂断,然后重新开始显示我的显示器驱动程序停止工作
答案 0 :(得分:1)
应用程序可能会通过传递无效状态或数据(有时甚至是有效状态)来使GPU崩溃。
尝试使用apitrace跟踪发给驱动程序的OpenGL命令,并捕获导致崩溃的命令。
使用调试版OpenTK.dll
运行应用程序也可以帮助您捕获错误:OpenTK将在每个GL命令后使用GL.GetError()
,如果出现问题则引发异常。要构建OpenTK的调试版本,download the source code并构建OpenTK.sln
。
答案 1 :(得分:0)
尽管它激怒了我,但我必须再次回答我自己的问题。我想我确定了这个错误,虽然我不是特别理解它......它不再崩溃了。我没有进行两次传递,而是将渲染周期压缩为单次迭代;这解决了显卡崩溃的问题。任何人都知道为什么会这样:
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()的双重调用引起的;似乎只有两次传递本身就是错误。
编辑:经过进一步测试和各种形式的文献后,我得出结论,我使用上面的代码是完全错误的。根据其他消息来源,我应该在开始遮挡查询之前禁用几乎所有的东西。这意味着:纹理,光照,甚至深度缓冲。我仍然不知道是什么原因导致我的显卡崩溃,但是,这肯定是因为我对这个主题缺乏了解。
答案 2 :(得分:0)
也许是因为你在两遍之间添加了以下几行:
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);