OpenGL glTexSubImage2D写入像素渲染异常问题
问题描述
我有一组存储字母q像素数据的无符号字节数组,需要调用glTexImage2D写入OpenGL纹理。代码中已经做了两层有效性校验:一是确认宽度、高度的乘积和数组长度完全匹配,二是把像素打印到终端做可视化验证。代码基于Rust编写,GL调用逻辑和其他语言的绑定规则完全一致:
// create the array of pixels let data: &[u8] = &[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 37, 2, 0, 0, 0, 0, 0, 0, 0, 119, 248, 252, 241, 92, 223, 130, 0, 0, 0, 84, 253, 108, 8, 36, 202, 248, 130, 0, 0, 0, 198, 182, 0, 0, 0, 52, 255, 130, 0, 0, 0, 241, 120, 0, 0, 0, 0, 245, 130, 0, 0, 3, 252, 108, 0, 0, 0, 0, 233, 130, 0, 0, 0, 223, 143, 0, 0, 0, 14, 253, 130, 0, 0, 0, 144, 234, 20, 0, 0, 126, 255, 130, 0, 0, 0, 23, 219, 223, 142, 173, 194, 231, 130, 0, 0, 0, 0, 18, 120, 156, 108, 13, 223, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 149, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; // check that WxH equals the number of pixels let data_w = 11; let data_h = 15; assert_eq!(data_w * data_h, data.len()); // write the pixels to the texture glBindTexture(GL_TEXTURE_2D, texture); // initialize the texture glTexImage2D( GL_TEXTURE_2D, 0, GL_RED as _, 256, 256, 0, GL_RED, GL_UNSIGNED_BYTE, ptr::null(), ); // write the pixels glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, data_w as _, data_h as _, GL_RED, GL_UNSIGNED_BYTE, data.as_ptr() as _, ); // print the pixels to the terminal let mut counter = 0; for _ in 0..data_h { for _ in 0..data_w { if data[counter] > 100 { print!("+"); } else { print!(" "); } counter += 1; } println!() }
终端打印的像素可视化结果如下,可以正确显示字母q的轮廓,证明像素数据本身没有问题:
++++ ++ ++ +++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +++ +++++++ +++ ++ ++ ++ +
但纹理渲染到屏幕时出现了扭曲错位,实际效果如下:
故障原因
OpenGL对传入的像素数据有默认的行对齐要求:GL_UNPACK_ALIGNMENT参数默认值为4,即要求每一行像素的起始内存地址是4的倍数,每行数据长度不足4的倍数时会自动在末尾补位跳过字节。
当前传入的像素格式是GL_RED+GL_UNSIGNED_BYTE,每个像素占1字节,每行共11个像素也就是11字节,不是4的倍数。OpenGL读取像素时会按每行12字节(补1个空字节对齐)解析,导致从第二行开始所有像素的读取位置全部偏移,最终渲染结果扭曲错位。
解决方法
在调用glTexSubImage2D(或glTexImage2D)上传像素数据之前,添加一行代码将像素解包的行对齐设置为1字节(即紧密排列,不做对齐补位)即可:
// C/C++ 写法 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Rust 写法 gl::PixelStorei(gl::UNPACK_ALIGNMENT, 1);
设置后OpenGL会按实际的每行11字节长度解析像素,不会再出现错位问题。
内容的提问来源于stack exchange,提问作者Roy Varon
相关产品推荐
相关产品推荐

