练习TDD时学习OpenGL(单元测试)

时间:2010-07-11 01:02:58

标签: c++ unit-testing opengl tdd

我已经开始了一个新的游戏项目,并决定为它学习和使用OpenGL(项目正在Windows和Linux上同时开发)。与此同时,我对测试驱动开发也非常感兴趣,并且我正在努力编写单元测试,以便在任何实际代码之前进行设计。

然而,我认为我缺乏知识可能会让我感到沮丧,而且我一直试图为代码库的“渲染”部分编写单元测试。我希望有人能给我一些关于如何继续的见解。

我知道我需要对我与OpenGL的交互进行单元测试,而不是OpenGL本身。我能看到这样做的唯一方法是在某种程度上将OpenGL从我的其余代码中抽象出来,或者通过拦截OpenGL函数调用,或者通过创建一个全新的类接口,允许我创建该类的模拟版本用于测试。 (更好的方法是将它们抽象为一个单独的命名空间中的一组非类函数而不是虚拟类抽象,但我不知道如何模拟它。)

然而,由于我还在学习OpenGL,所以我对这个抽象应该是什么样子只有一个概念。例如,我应该包装每个OpenGL调用,还是根据要完成的任务将它们分组到更高级别的函数中?瘦包装器只会调用特定的OpenGL函数,所以我不需要事先测试它们,但我最终可能需要包含大量函数。再说一次,如果我走得太远,并且通过任务将多个OpenGL调用组合在一起,我觉得我最终会在我开始的地方结束,使用OpenGL需要在使用之前对其进行大量测试。< / p>

中间地方在哪里?如何在学习使用OpenGL的同时事先进行适当的单元测试?

6 个答案:

答案 0 :(得分:9)

正确测试渲染是不值得的。但是,在设计应用程序时,您仍然可以将TDD用于其他所有内容。

Here's a great article关于TDD,游戏和OpenGL。

答案 1 :(得分:3)

您无法自动测试渲染部分。为此,你需要一个有能力看到和识别图像的有情人。计算机没有资格。

您可以自动测试成功创建资源--VPO,纹理,着色器,显示列表 - 您可以对着色器进行单元测试编译错误,测试数学库,可以检测OpenGL错误,但无法测试渲染部分。你能做的最好的事情就是做一些能够渲染图片的测试程序(可能是动画和交互式的)并询问它是否正确。测试不是100%可靠 - 可能在一个硬件上工作,而不在其他硬件上,人可能会错过错误等。

  

例如,我应该包装每个OpenGL调用,

不,这不值得。

  

或根据要完成的任务将它们分组到更高级别的函数中?

编写一些调用/类来创建“纹理”,“网格”,“着色器程序”,制作某种自动获取统一位置的方法(如果使用着色器),也许是几个类是有道理的用于自动释放OpenGL资源(即具有glDelete ***或具有glIsTexture等功能的资源),但这就是全部。通常情况下,你不应该引入额外的抽象/类,除非需要它们 - 因为它将是额外的工作,没有收获。

答案 2 :(得分:3)

像对待数据库一样对待OpenGL。我最初会用一个界面开始。随着时间的推移,您添加了更多方法,然后您可以开始将单个接口分解为多个接口。

如前所述,您无法使用标准TDD库来测试渲染。但这是可能的。可以认为它有点像在Web客户端中测试HTML的呈现。在编写我的HTML时,我没有TDD Firefox或Internet Explorer。

答案 3 :(得分:2)

我建议制作一个小型原型或其他一些小型项目并与opengl一起玩。这会让你熟悉它。一旦完成使用tdd构建应用程序应该会更容易。你可以发现你需要模拟opengl而不是测试opengl。

答案 4 :(得分:2)

许多人似乎认为图形不受传统TDD /单元测试的影响。事实并非如此。

围绕TDD的问题是图像并不总是完全相同。像抗锯齿设置(可以被驱动程序设置覆盖)之类的东西。不同GPU如何呈现相同图像(多边形展开顺序等)之间的差异。此外,当您的游戏经历开发时,网格和纹理等内容可能会被更改或调整。

此外,人们认为你经常需要这样做,并在看到它的确定之前先看看结果然后将其添加为通过测试用例(由于上述问题将会破坏)。

你可以用记录的方式包装所有OpenGL调用,并确保按预期调用事物,但不测试图形实际上是有效的,它只是测试你的程序正在进行你预测它应该进行的调用。这不是很有用,而且会有相当多的工作。如果你做了诸如优化不必要的绘制调用之类的事情,那么它将很难维持。

我建议您将渲染输出与窗口系统分离。我的意思是'渲染到纹理'或使用FrameBuffer对象。这也有助于执行视口和UI / HUD叠加等操作。

制作一个'Window'对象。使用Qt,SDL,SFML,GLUT或其他任何东西打开实际桌面窗口的东西。并传递某种渲染器。您可以执行诸如允许多个渲染器之类的操作并指定矩形坐标(您可以在屏幕的角落渲染不同的视图)。或者也许制作一个主渲染器,但继承一个允许它具有子渲染器的版本。 Window对象也可以处理输入,这提供了一种注入假/模拟输入对象的好方法,你可以测试玩家是否按预期向前移动。

这种模块化方法是不受TDD影响的东西,它也可能让你的渲染器有自己的渲染器(也许你想单独做一个天空盒,或者游戏中安全监视器上的图片,反射,shadowmaps等)。您还可以轻松地以与原始桌面不同的分辨率进行渲染(这对于在TDD中设置固定分辨率非常有用,对于简单操作可能只需要32x32,但对于Android等修正分辨率和设备的设备也很有用。 GPU具有不同的功能.Nexus 10不足以在XDPI上渲染你的游戏吗?缩小它。还有助于Linux / Xorg,它并不总是允许你设置GPU所做的所有分辨率,尽管现在几乎没有问题)。

获得FBO后,可以使用一些函数来查询像素颜色。然后,您可以查询所有基本操作。你的网格物体是否正确渲染?测试一下。使用单个白色三角形制作网格,并查询您希望看到白色的位置以及绘制该三角形时应保持黑色的位置。 1x1窗口中的1x1三角形应覆盖%50对角线,因此测试像素靠近边缘和中间的两侧,窗口的边界和尖头位。接下来combine two triangles into a rectangle它应该填满屏幕,现在所有像素都应该是白色的。现在尝试将其从相机移开并检查边框是黑色但是中心是白色的,1.0x1.0窗口中的1.0x1.0矩形距离为1.0,您可以应用一些简单的几何图形来查看边框的大致位置应该结束。 Test with a different color。使用多色立方体制作更复杂的网格并测试旋转。制作测试法线贴图。

您可以通过渲染球体并检查左侧是否比右侧更亮来测试灯光,如果您在另一侧添加另一个灯光它们大致相同(只需添加左侧的所有像素)和右边的所有像素,并在误差范围内进行比较)。增加光亮度并查看像素总和是否增加。您可以通过计算平面上特定点的预期颜色来测试光照算法。 您可以看到光谱突出显示在预期区域最亮。对于普通/凹凸贴图make a test texture

避免任何非常具体的事情,例如不要在边缘上进行精确测试。它们可能是抗锯齿的,或者只是略微偏离。如果您在测试左/右亮度以进行照明时,不要指望不同系统或甚至两侧(在对称场景中)像素数相同,请使用误差范围。不要使用真实数据,请确保使用基本的“测试”纹理和不会改变的网格。

答案 5 :(得分:0)

看看What is the best way to debug OpenGL?;这个问题的答案中提到的工具将使某种形式的测试成为可能,尤其是GLIntercept(一个OpenGL函数调用拦截器)听起来像是一个非常有趣的选择/进一步调查的起点。

相关问题