在Android中使用OpenGL有几个重要但是容易忽视的事项
1. Render Mode
Render的mode可以设为两种模式,一种是自动循环模式,也就是说GL线程以一定的时间间隔自动的循环调用用户实现的onDrawFrame()方法进行一帧一帧的绘制,还有一种的“脏”模式,也就是说当用户需要重绘的时候,主动“拉”这个重绘过程,有点类似于Canvas中的invalidate()
具体的调用方法是在GLSurfaceView中
a.自动模式
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
b."脏"模式
.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
当需要重绘时,调用
GLSurfaceView.requestRender()
一般情况下我使用脏模式,这样可以有效降低cpu负载。在N1的测试结果表明,OpenGL真正绘图时一般会占到30%以上的cpu。
2. Dither
Dither又叫抖动,是一种在色彩空间较小的设备上展示较大色彩空间的图像的一种方法。比如在一个RGB_565的设备上展示RGB_888的图像。如果简单的截断位的话,会造成色彩的失真和生硬。dither使用一个矩阵,来调整一个像素周围的像素的值,来使人眼产生错觉,而“模拟”出原来的色彩。缺省情况下GLSurfaceView是RGB——565的surface,所以如果在该surface上直接绘制RGB_888的纹理的话就会产生色彩失真,修复办法就是使能dither。方法很简单
gl.glEnable(GL10.GL_DITHER);
3. 深度测试
深度测试是在片断处理过程中通过测试一个片断在eye space的深度坐标,来判断它是否被更小深度坐标的片断遮挡而决定是否真去绘制它。没有深度测试,物体展现与否就会取决于绘制顺序而不是摆放的坐标。
在Android中打开深度测试的方法是
GLSufaceView.setEGLConfigChooser(true);
你甚至可以进一步规范片断处理中每种测试所占的位数:
mGLView.setEGLConfigChooser(redSize, greenSize, blueSize, alphaSize, depthSize, stencilSize)
4.深度坐标的精度
3中已经知道我们可以设置深度缓冲区的位数以达到合理的精度。如果精度不够的话,在“远方”的物体可能出现不希望的重叠。道理显而易见,由于深度坐标是非线性的,越远的地方单位深度坐标对应的实际距离越大。当精度不足时,较短差距的两个物体就会被“截位”到同样的深度坐标而导致深度测试时发生错误。
解决的办法有两个:
1. 不要将投影平截头的远方坐标设的太大,一般不要 far/near < 100 比较合适
2. 扩大深度缓冲区所占的位数,以提高精度。代价就是占用的内存会增大。
一般我首选1方案。