一、基本的像素操作
1.glReadPixels
2.glDrawPixels
3.glCopyPixels
glCopyPixels (0, 0, checkImageWidth, checkImageHeight, GL_COLOR);
4.glPixelZoom()
二、像素渲染管线:
1.包装和解包
2.控制图像存储模式
glPixelStore — set pixel storage modes
void glPixelStoref( | GLenum pname, |
| GLfloat param) ; |
void glPixelStorei( | GLenum pname, |
| GLint param) ; |
-
Specifies the symbolic name of the parameter to be set. Six values affect the packing of pixel data into memory:
GL_PACK_SWAP_BYTES
,GL_PACK_LSB_FIRST
,GL_PACK_ROW_LENGTH
,GL_PACK_IMAGE_HEIGHT
,GL_PACK_SKIP_PIXELS
,GL_PACK_SKIP_ROWS
,GL_PACK_SKIP_IMAGES
, andGL_PACK_ALIGNMENT
. Six more affect the unpacking of pixel data from memory:GL_UNPACK_SWAP_BYTES
,GL_UNPACK_LSB_FIRST
,GL_UNPACK_ROW_LENGTH
,GL_UNPACK_IMAGE_HEIGHT
,GL_UNPACK_SKIP_PIXELS
,GL_UNPACK_SKIP_ROWS
,GL_UNPACK_SKIP_IMAGES
, andGL_UNPACK_ALIGNMENT
. -
Specifies the value that
pname
is set to.
pname
param
glPixelStore
sets pixel storage modes that affect the operation of subsequent glReadPixels as well as the unpacking of texture patterns (see glTexImage1D, glTexImage2D, glTexImage3D, glTexSubImage1D, glTexSubImage2D,glTexSubImage3D), glCompressedTexImage1D, glCompressedTexImage2D, glCompressedTexImage3D, glCompressedTexSubImage1D, glCompressedTexSubImage2D or glCompressedTexSubImage1D.
pname
is a symbolic constant indicating the parameter to be set, and param
is the new value. Six of the twelve storage parameters affect how pixel data is returned to client memory. They are as follows:
3.像素传输操作和像素映射
1)像素传输操作
像素在CPU内存和GPU帧缓冲区之间传递时候,可以进行的操作叫做像素传输操作。
像素传输操作,可以将像素内部的颜色成分限制在一定的范围内(进行截取,或索引进行截取),可以创建颜色映射将RGBA等颜色模式 和 颜色索引模式之间做转换。
颜色缓存,深度,模板缓存之间具有许多相似之处,但也有一些差异,需要不同的设置。
像素传输的有些特征是用glPixelTransfer*()函数设置,其它特征有glPixelMap*()函数指定。
glPixelTransfer — set pixel transfer modes
void glPixelTransferf( | GLenum pname, |
| GLfloat param) ; |
void glPixelTransferi( | GLenum pname, |
| GLint param) ; |
-
Specifies the symbolic name of the pixel transfer parameter to be set. Must be one of the following:
GL_MAP_COLOR
,GL_MAP_STENCIL
,GL_INDEX_SHIFT
,GL_INDEX_OFFSET
,GL_RED_SCALE
,GL_RED_BIAS
,GL_GREEN_SCALE
,GL_GREEN_BIAS
,GL_BLUE_SCALE
,GL_BLUE_BIAS
,GL_ALPHA_SCALE
,GL_ALPHA_BIAS
,GL_DEPTH_SCALE
, orGL_DEPTH_BIAS
.Additionally, if the
ARB_imaging
extension is supported, the following symbolic names are accepted:GL_POST_COLOR_MATRIX_RED_SCALE
,GL_POST_COLOR_MATRIX_GREEN_SCALE
,GL_POST_COLOR_MATRIX_BLUE_SCALE
,GL_POST_COLOR_MATRIX_ALPHA_SCALE
,GL_POST_COLOR_MATRIX_RED_BIAS
,GL_POST_COLOR_MATRIX_GREEN_BIAS
,GL_POST_COLOR_MATRIX_BLUE_BIAS
,GL_POST_COLOR_MATRIX_ALPHA_BIAS
,GL_POST_CONVOLUTION_RED_SCALE
,GL_POST_CONVOLUTION_GREEN_SCALE
,GL_POST_CONVOLUTION_BLUE_SCALE
,GL_POST_CONVOLUTION_ALPHA_SCALE
,GL_POST_CONVOLUTION_RED_BIAS
,GL_POST_CONVOLUTION_GREEN_BIAS
,GL_POST_CONVOLUTION_BLUE_BIAS
, andGL_POST_CONVOLUTION_ALPHA_BIAS
. -
Specifies the value that
pname
is set to.
pname
param
glPixelTransfer
sets pixel transfer modes that affect the operation of subsequent glCopyPixels, glCopyTexImage1D, glCopyTexImage2D, glCopyTexSubImage1D,glCopyTexSubImage2D, glCopyTexSubImage3D, glDrawPixels, glReadPixels, glTexImage1D, glTexImage2D, glTexImage3D, glTexSubImage1D, glTexSubImage2D, and glTexSubImage3Dcommands. Additionally, if the ARB_imaging
subset is supported, the routines glColorTable, glColorSubTable, glConvolutionFilter1D, glConvolutionFilter2D, glHistogram,glMinmax, and glSeparableFilter2D are also affected. The algorithms that are specified by pixel transfer modes operate on pixels after they are read from the frame buffer (glCopyPixels glCopyTexImage1D, glCopyTexImage2D, glCopyTexSubImage1D, glCopyTexSubImage2D, glCopyTexSubImage3D, and glReadPixels), or unpacked from client memory (glDrawPixels, glTexImage1D, glTexImage2D, glTexImage3D, glTexSubImage1D, glTexSubImage2D, and glTexSubImage3D). Pixel transfer operations happen in the same order, and in the same manner, regardless of the command that resulted in the pixel operation. Pixel storage modes (see glPixelStore) control the unpacking of pixels being read from client memory and the packing of pixels being written back into client memory.
Pixel transfer operations handle four fundamental pixel types: color, color index, depth, and stencil. Color pixels consist of four floating-point values with unspecified mantissa and exponent sizes, scaled such that 0 represents zero intensity and 1 represents full intensity. Color indices comprise a single fixed-point value, with unspecified precision to the right of the binary point. Depth pixels comprise a single floating-point value, with unspecified mantissa and exponent sizes, scaled such that 0.0 represents the minimum depth buffer value, and 1.0 represents the maximum depth buffer value. Finally, stencil pixels comprise a single fixed-point value, with unspecified precision to the right of the binary point
指定了GL_MAP_COLOR
, GL_MAP_STENCIL就会启用像素映射功能。
其它是颜色成分的缩放和偏移(限制在范围内),包括索引的位移和偏移(限制在一定范围内)
.
GL_POST_CONVOLUTION和GL_POST_COLOR_MATRIX系列参数,是只有在OGL实现支持图像处理子集功能时候才可用。
2)像素映射操作
所有的颜色成分,颜色索引和模板索引在进入屏幕内存之前都可以通过表查找的方式进行更改(从CPU端通过映射的方式对GPU中的待光栅化像素数据进行映射更新),用于控制这种映射的函数就是glPixelMap。
glPixelMap — set up pixel transfer maps
void glPixelMapfv( | GLenum map, |
| GLsizei mapsize, |
| const GLfloat * values) ; |
void glPixelMapuiv( | GLenum map, |
| GLsizei mapsize, |
| const GLuint * values) ; |
void glPixelMapusv( | GLenum map, |
| GLsizei mapsize, |
| const GLushort * values) ; |
-
Specifies a symbolic map name. Must be one of the following:
GL_PIXEL_MAP_I_TO_I
,GL_PIXEL_MAP_S_TO_S
,GL_PIXEL_MAP_I_TO_R
,GL_PIXEL_MAP_I_TO_G
,GL_PIXEL_MAP_I_TO_B
,GL_PIXEL_MAP_I_TO_A
,GL_PIXEL_MAP_R_TO_R
,GL_PIXEL_MAP_G_TO_G
,GL_PIXEL_MAP_B_TO_B
, orGL_PIXEL_MAP_A_TO_A
. -
Specifies the size of the map being defined.
-
Specifies an array of
mapsize
values.
map
mapsize
values
glPixelMap
sets up translation tables, or maps, used by glCopyPixels, glCopyTexImage1D, glCopyTexImage2D, glCopyTexSubImage1D, glCopyTexSubImage2D, glCopyTexSubImage3D,glDrawPixels, glReadPixels, glTexImage1D, glTexImage2D, glTexImage3D, glTexSubImage1D, glTexSubImage2D, and glTexSubImage3D. Additionally, if the ARB_imaging
subset is supported, the routines glColorTable, glColorSubTable, glConvolutionFilter1D, glConvolutionFilter2D, glHistogram, glMinmax, and glSeparableFilter2D. Use of these maps is described completely in the glPixelTransfer reference page, and partly in the reference pages for the pixel and texture image commands. Only the specification of the maps is described in this reference page.
map
is a symbolic map name, indicating one of ten maps to set. mapsize
specifies the number of entries in the map, and values
is a pointer to an array of mapsize
map values.
If a non-zero named buffer object is bound to the GL_PIXEL_UNPACK_BUFFER
target (see glBindBuffer) while a pixel transfer map is specified, values
is treated as a byte offset into the buffer object's data store.
查询像素映射表的大小:
4.纹理内存和纹理操作
5.光栅化时的图像的放大,缩小,翻转
6.片断操作,纹理映射(非像素映射)
7.绘制,复制,缩放像素数据的例子
#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
/* Create checkerboard image */
#define checkImageWidth 64
#define checkImageHeight 64
GLubyte checkImage[checkImageHeight][checkImageWidth][3];
static GLdouble zoomFactor = 1.0;
static GLint height;
void makeCheckImage(void)
{
int i, j, c;
for (i = 0; i < checkImageHeight; i++) {
for (j = 0; j < checkImageWidth; j++) {
c = ((((i&0x8)==0)^((j&0x8))==0))*255;
checkImage[i][j][0] = (GLubyte) c;
checkImage[i][j][1] = (GLubyte) c;
checkImage[i][j][2] = (GLubyte) c;
}
}
}
void init(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
// 从下往上,从左往右生成图像数据数组
makeCheckImage();
// 像素存储模式,内存对齐为1
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
// 定义光栅化位置,从左下角开始
glRasterPos2i(0, 0);
// 绘制图像数据,每个成分的类型是GL_UNSIGNED_BYTE,整个像素是GL_RGB有三个成分;数据块是checkImage
glDrawPixels(checkImageWidth, checkImageHeight, GL_RGB,
GL_UNSIGNED_BYTE, checkImage);
glFlush();
}
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
height = (GLint) h;
// 正交投影,设置屏幕宽高
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, (GLdouble) w, 0.0, (GLdouble) h);
// 视图模型矩阵是单位矩阵
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void motion(int x, int y)
{
static GLint screeny;
screeny = height - (GLint)y;
printf("y is now %d\n", y);
printf("screeny is now %d\n", screeny);
// 改变光栅化位置,就是鼠标x值的位置
// 因为窗口系统的位置是左上角,OGL屏幕坐标系是左下角,所以要减去screeny = height - (GLint)y;
glRasterPos2i (x, screeny);
// 改变图像或位图光栅化时候的缩放值
glPixelZoom (zoomFactor, zoomFactor);
// 复制左下角的数据块,到当前位置绘制像素数据块,相当于read 和 draw 图像或位图数据
glCopyPixels (0, 0, checkImageWidth, checkImageHeight, GL_COLOR);
// 恢复图像或位图光栅化时候的缩放值
glPixelZoom (1.0, 1.0);
glFlush ();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'r':
case 'R':
zoomFactor = 1.0;
glutPostRedisplay();
printf ("zoomFactor reset to 1.0\n");
break;
case 'z':
zoomFactor += 0.5;
if (zoomFactor >= 3.0)
zoomFactor = 3.0;
printf ("zoomFactor is now %4.1f\n", zoomFactor);
break;
case 'Z':
zoomFactor -= 0.5;
if (zoomFactor <= 0.5)
zoomFactor = 0.5;
printf ("zoomFactor is now %4.1f\n", zoomFactor);
break;
case 27:
exit(0);
break;
default:
break;
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(250, 250);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
// The motion callback for a window is called when the mouse moves within the window while one or more
// mouse buttons are pressed
// 按下鼠标并移动
glutMotionFunc(motion);
glutMainLoop();
return 0;
}
使用缓存区对象传输像素数据
每帧绘制时候不需要将图像或位图数据从CPU内存拷贝到GPU缓存中,而是初始化时候将指定解包,存储模式,传输;只需要传输一次,后面每帧渲染只需要从GPU缓存区对象,绑定指针读取数据即可。而且可以初始化后更改数据。
初始化时候,拷贝数据到缓存区对象中
glGenBuffers(1, &pixelBuffer);
// 2.绑定GL_PIXEL_UNPACK_BUFFER全局指针
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBuffer);
// 3.对GL_PIXEL_UNPACK_BUFFER全局指针,拷贝数据
glBufferData(GL_PIXEL_UNPACK_BUFFER, 3 * checkImageWidth*checkImageHeight, checkImage, GL_STATIC_DRAW);
// 数据一次拷贝到了GPU缓存区对象中,可以释放CPU中的数据块
memset(checkImage, 0, 3 * checkImageWidth*checkImageHeight);
每帧绘制时候绑定到缓存区对象全局指针,绘制使用偏移NULL绘制
{
glClear(GL_COLOR_BUFFER_BIT);
// 定义光栅化位置,从左下角开始
glRasterPos2i(0, 0);
// 4..对GL_PIXEL_UNPACK_BUFFER全局指针,绑定到pixelBuffer缓存区对象
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBuffer);
// 绘制图像数据,每个成分的类型是GL_UNSIGNED_BYTE,整个像素是GL_RGB有三个成分;数据块是checkImage
// 5.正常绘图,对*data传递的是GL_PIXEL_UNPACK_BUFFER全局指针的开始地址
glDrawPixels(checkImageWidth, checkImageHeight, GL_RGB,
GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
glFlush();
}
#include <GL/glew.h>
#include <GL/glut.h>
//# include <GL/freeglut.h>
#include <stdlib.h>
#include <stdio.h>
#pragma comment(lib, "glew32d.lib")
/* Create checkerboard image */
#define BUFFER_OFFSET(bytes) ((GLubyte*)NULL + (bytes))
#define checkImageWidth 64
#define checkImageHeight 64
GLubyte checkImage[checkImageHeight][checkImageWidth][3];
static GLdouble zoomFactor = 1.0;
static GLint height;
static GLuint pixelBuffer;
void makeCheckImage(void)
{
int i, j, c;
for (i = 0; i < checkImageHeight; i++) {
for (j = 0; j < checkImageWidth; j++) {
c = ((((i&0x8)==0)^((j&0x8))==0))*255;
checkImage[i][j][0] = (GLubyte) c;
checkImage[i][j][1] = (GLubyte) c;
checkImage[i][j][2] = (GLubyte) c;
}
}
}
void init(void)
{
glewInit();
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
// 从下往上,从左往右生成图像数据数组
makeCheckImage();
// 像素存储模式,内存对齐为1
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// 1.获取
glGenBuffers(1, &pixelBuffer);
// 2.绑定GL_PIXEL_UNPACK_BUFFER全局指针
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBuffer);
// 3.对GL_PIXEL_UNPACK_BUFFER全局指针,拷贝数据
glBufferData(GL_PIXEL_UNPACK_BUFFER, 3 * checkImageWidth*checkImageHeight, checkImage, GL_STATIC_DRAW);
// 数据一次拷贝到了GPU缓存区对象中,可以释放CPU中的数据块
memset(checkImage, 0, 3 * checkImageWidth*checkImageHeight);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
// 定义光栅化位置,从左下角开始
glRasterPos2i(0, 0);
// 4..对GL_PIXEL_UNPACK_BUFFER全局指针,绑定到pixelBuffer缓存区对象
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBuffer);
// 绘制图像数据,每个成分的类型是GL_UNSIGNED_BYTE,整个像素是GL_RGB有三个成分;数据块是checkImage
// 5.正常绘图,对*data传递的是GL_PIXEL_UNPACK_BUFFER全局指针的开始地址
glDrawPixels(checkImageWidth, checkImageHeight, GL_RGB,
GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
glFlush();
}
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
height = (GLint) h;
// 正交投影,设置屏幕宽高
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, (GLdouble) w, 0.0, (GLdouble) h);
// 视图模型矩阵是单位矩阵
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void motion(int x, int y)
{
static GLint screeny;
screeny = height - (GLint)y;
printf("y is now %d\n", y);
printf("screeny is now %d\n", screeny);
// 改变光栅化位置,就是鼠标x值的位置
// 因为窗口系统的位置是左上角,OGL屏幕坐标系是左下角,所以要减去screeny = height - (GLint)y;
glRasterPos2i (x, screeny);
// 改变图像或位图光栅化时候的缩放值
glPixelZoom (zoomFactor, zoomFactor);
// 复制左下角的数据块,到当前位置绘制像素数据块,相当于read 和 draw 图像或位图数据
glCopyPixels (0, 0, checkImageWidth, checkImageHeight, GL_COLOR);
// 恢复图像或位图光栅化时候的缩放值
glPixelZoom (1.0, 1.0);
glFlush ();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'r':
case 'R':
zoomFactor = 1.0;
glutPostRedisplay();
printf ("zoomFactor reset to 1.0\n");
break;
case 'z':
zoomFactor += 0.5;
if (zoomFactor >= 3.0)
zoomFactor = 3.0;
printf ("zoomFactor is now %4.1f\n", zoomFactor);
break;
case 'Z':
zoomFactor -= 0.5;
if (zoomFactor <= 0.5)
zoomFactor = 0.5;
printf ("zoomFactor is now %4.1f\n", zoomFactor);
break;
case 27:
exit(0);
break;
default:
break;
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(250, 250);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
// The motion callback for a window is called when the mouse moves within the window while one or more
// mouse buttons are pressed
// 按下鼠标并移动
glutMotionFunc(motion);
glutMainLoop();
return 0;
}
使用缓存区对象读取像素数据
可以将缓存区对象读取会CPU内存,进行更改操作。对于glReadPixels和glGetTexImage这样的函数可以传入读取缓存区对象指针偏移读取数据到读取缓存区对象中。
和绘制相比,区别是使用GL_PIXEL_PACK_BUFFER做为读取的缓存区对象。
读取完到读取缓存区对象后就可以用glMapBuffer, glGetBufferSubData来访问修改读取缓存区对象内的数据值。
实例:
// 1.获取
glGenBuffers(1, &pixelBuffer);
// 2.绑定GL_PIXEL_PACK_BUFFER全局指针
glBindBuffer(GL_PIXEL_PACK_BUFFER, pixelBuffer);
// 3.对GL_PIXEL_PACK_BUFFER全局指针,拷贝数据
glBufferData(GL_PIXEL_PACK_BUFFER, sizeof(GLfloat) * checkImageWidth*checkImageHeight,
NULL,// 申请内存大小,但是不初始化数据块
GL_STATIC_READ); // 为读取数据流
// 绘制数据,当前绘制的数据块,不是GL_PIXEL_PACK_BUFFER缓存区数据块
GLsizei numPixels = checkImageWidth * checkImageHeight;
glDrawPixels(checkImageWidth, checkImageHeight, GL_RGB,
GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
glReadPixels(0, 0, checkImageWidth, checkImageHeight, GL_RGB,
GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
GLfloat *pixels = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
for (int i = 0; i < numPixels; i++)
{
/*CPU 内存中修改 pixels数据值*/
pixels[i] = pixels[i] * 0.5f;// 亮度降低0.5
}
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);