大家好,我是程序员kenney,今天给大家分析一下OpenGL
的黑屏常见原因。
做OpenGL
开发的同学,想必一定碰到过黑屏的问题,特别是刚接触OpenGL
的同学,可能会觉得黑屏问题让人相当头疼,因为OpenGL
的查错没有一般编程时那么简单,我们通常是利用glGetError()
这个API
来获取错误码,但这个方法获取的错误是调用这个方法时,已经产生的错误,它有可能是很久之前产生的,这样查越来还是比较不方便的,而且,有些黑屏的情况下,glGetError()
也不会报任何错。
在给大家总结常见的黑屏原因之前,我们先来了解一下我们看到的黑屏究竟是什么?其实屏幕也是一块frame buffer
,但它比较特殊,是0
号frame buffer
,我们如果自己申请frame buffer
的话,得到的id
是大于0的。那么frame buffer
它就会有自己的颜色,如果不特意设置的话,它就是黑色的,因此如果我们渲染操作未正确执行,什么也没渲染出来,自然看到了底色的黑色。
我们也可以通过glClearColor()+glClear()
来设置消除颜色及执行消除操作,来将一个frame buffer
清成某种颜色。因此,如果你将frame buffer
清成了别的颜色,但其它渲染操作未正确执行,你有可能也不是黑屏,而是你设置的消除颜色,这里也一并总结了,统成为黑屏,同时也包括其它一些不正确的情形。
下面给大家总结一下:
-
调用线程不正确
OpenGL
的API
在调用时需要有正确的上下文,在Android
中称为EGL Context
,其它平台有其它平台的叫法,但原理类似。一个线程需要跟EGL Context
绑定才能正确使用OpenGL
的API
,否则调用不会有任何效果,具体可参考我的一篇文章:《OpenGL ES 高级进阶:EGL及GL线程》。 -
GL Program
不正确OpenGL
渲染需要通过GL Program
,它就是一个程序,和我们的普通程序是一个道理,只不过它是运行在GPU
上的,如果它不正确了,那自然就渲染不出正确的结果,常见的不正确原因为shader
编译失败,通常是因为语法错误,可以用glGetShaderInfoLog()
来在编译之后查看相关shader
信息,以及在Link
后用glGetProgramInfoLog()
查看相关program
信息,如果得到的信息为空,则说明没有错。 -
未调用
glDrawXXX()
要渲染出来东西,必须调用
glDrawXXX()
,一般很少出现没调的情况,一般都是低级失误,最好也排查一下。 -
顶点
attribute
值设置错误顶点关系到渲染到什么位置,如果设置错误导致渲染的位置在可视范围之外,那么就看不到了,等于没做渲染。
-
attribute
未启用我们通过想要设置一个
attribute
的值,需要获取这个attribute
的location
,并通过glVertexAttribPointer()
给它设置值,但别忘了需要使用glGetAttribLocation()
来启用这个location
,不然设置了也没有用,默认是不启用的。 -
View Port
设置错误View Port
即视口,可以理解成我们通过一个窗口去看见OpenGL
世界坐标系里渲染的景物,就像我们通过窗口看到室外的景物一样,如果这个窗口没设置或者设置不正确,也会导致看不到东西,一般情况下,我们会将它设置为surface
的大小,这样渲染出来的东西就刚好填满这个surface
。 -
没有渲染到
0
号frame buffer
有时候渲染操作有很多步,想做完这些步骤后,再将做好的结果显示的屏幕上,这时就会用一些
frame buffer
来做离屏渲染,但在最后一步渲染到屏幕上时,需要将frame buffer
绑定回0
号,才能上屏。 -
渲染了一个不正确的纹理
例如我们希望对一个纹理做一些处理然后渲染出来,但如果这个纹理本身是不正确的,例如前面的步骤出了一些错,导致给过来的纹理
id
不正确,比如是0
,或者纹理id
是正确的,但这个纹理是全黑的或者空的,也会导致黑屏。 -
glDrawXXX()
方法传递的顶点数不正确我们在调用
glDrawXXX()
,会设置顶点数组的开始位置和数量,如果设置不正确,导致传递的顶点是0
个,也会导致渲染不出来任何东西。 -
顶点
buffer
的position
不正确这一点主要是针对
java
及kotlin
,glVertexAttribPointer()
接受数据时是通过一个buffer
,而我们往buffer
是put
数据后,buffer
的position
会相应地往后移动,因此在调用glVertexAttribPointer()
之前,记得将position
设回到0
,否则它将从末尾开始取数据,当然就取不到了。 -
未开启颜色混合渲染了有透明度的纹理
OpenGL
默认是不开启颜色混合的,这会导致透明的部分通常会被渲染成黑色,而不是透出下面的颜色,具体可以参数我的一篇文章:《OpenGL ES 高级进阶:颜色混合》。
好了,先总结到这,这些是比较常见的,也欢迎大家给我留意补充讨论~
感谢阅读!