[OpenGL] glVertexAttribPointer函数与glVertexAttribIPointer函数使用中遇到的小坑(int类型被自动转换为float类型)
起因:用OpenGL ES的变换反馈(transform feedback)特性,在GPU上实现图象处理中常用的查表映射功能(LookUp Table Map)。
这是一个工作量在五天以内的小项目(简单分为三个部分:一、分配顶点数组,二、写着色器,三、利用变换反馈把结果取回内存。)
本应该自己来做。但是凑巧有个算法移植到CUDA平台的工作在手,于是就拜托公司一位比较熟悉OpenGL ES的实习生来做,先第一部分和第三部分,第二部分可以暂时以一个简单的着色器来替代,先把整个框架搭起来。
过了三天,自己手头的事情做好了。就问他做的怎么样,有没有遇到什么问题。小伙子说,框架搭好了,但是遇到了一个百思不得其解的问题,传进去着色器的-1,没做任何改变,纯粹地返回,但是在读出来的时候总是-1082130432。(其中int类型的数字-1是表中较常出现的数字。)
简单review了一下,代码大致没什么问题。
排查-1变成-1082130432的问题。
用以下代码测试
float f = -1.0f;
printf("%d\n", *(int*)&f);
得到的输出结果就是-1082130432。
所以很明显,在传入着色器的过程当中,int类型的-1被转化成了float类型的-1,所以我们在读取以int类型再去读取它的时候,就读出了-1082130432这个数字。
bug定位好了之后,就开始排查数据进入着色器的过程中是否出现了问题。
最后发现,小伙子用了glVertexAttribPointer函数来指定每个顶点的属性,但是这个函数在normalized属性被设置为GL_FALSE时,非float类型的数值将被转换成float类型。于是int类型的-1就被转换成了float类型。
改用glVertexAttribIPointer函数,bug解决。
OpenGL ES 3中的glVertexAttribPointer与glVertexAttribIPointer的文档摘录如下:
For
glVertexAttribPointer
, ifnormalized
is set toGL_TRUE
, it indicates that values stored in an integer format are to be mapped to the range [-1,1] (for signed values) or [0,1] (for unsigned values) when they are accessed and converted to floating point. Otherwise, values will be converted to floats directly without normalization.For
glVertexAttribIPointer
, only the integer typesGL_BYTE
,GL_UNSIGNED_BYTE
,GL_SHORT
,GL_UNSIGNED_SHORT
,GL_INT
,GL_UNSIGNED_INT
are accepted. Values are always left as integer values.