首页 > 代码库 > [原]OpenGL基础教程(四)VBO+纹理绘制四边形
[原]OpenGL基础教程(四)VBO+纹理绘制四边形
工程下载地址:http://pan.baidu.com/s/1ntr7NHv 提取码:yf1h
一、本文牵扯知识点梳理:
(1)VBO
(2)纹理
(3)libpng(加载png)
(4)shader
1、VBO(Vertex Buffer Objec)
//顶点坐标
glEnableVertexAttribArray(0);//激活顶点属性数组
glGenBuffers(1, &VertexID);创建句柄
glBindBuffer(GL_ARRAY_BUFFER, VertexID);设置句柄类型
glBufferData(GL_ARRAY_BUFFER, sizeof(positionData),positionData,GL_STATIC_DRAW);上传数据
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, 0);Set up our vertex attributes pointer 具体给shader传输数据
//顶点uv
glEnableVertexAttribArray(1);//顶点uv
glGenBuffers(1, &UVID);
glBindBuffer(GL_ARRAY_BUFFER,UVID);
glBufferData(GL_ARRAY_BUFFER,sizeof(uvData),uvData,GL_STATIC_DRAW);
glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, 0 );
//顶点颜色
glEnableVertexAttribArray(2);//顶点color
glGenBuffers(1, &ColorID);
glBindBuffer(GL_ARRAY_BUFFER,ColorID);
glBufferData(GL_ARRAY_BUFFER,sizeof(colorData),colorData,GL_STATIC_DRAW);
glVertexAttribPointer( 2, 3, GL_FLOAT, GL_FALSE, 0, 0 );
//顶点索引
glGenBuffers(1, &IndexID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,IndexID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexs),indexs,GL_STATIC_DRAW);
2、纹理使用
glGenTextures(1,&textureID);
glBindTexture(GL_TEXTURE_2D,textureID); //将纹理绑定到名字
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,picdata->rgba); //w h 纹理的宽高 picdata->rgba纹理的数据
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//纹理的过滤模式
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
纹理坐标:
3、libpng 开源的png加载库,可以将png转化为byte数组;下载地址 备注libpng依赖于zlib库,需要下载两个库并将它们放在相同目录
读取png图片代码:
1 typedef struct _pic_data pic_data; 2 struct _pic_data 3 { 4 int width, height; /* 尺寸 */ 5 int bit_depth; /* 位深 */ 6 int flag; /* 一个标志,表示是否有alpha通道 */ 7 8 unsigned char *rgba; /* 图片数组 */ 9 }; 10 int detect_png(char *filepath, pic_data* out) 11 /* 用于解码png图片 */ 12 { 13 unsigned char header[8]; //8 14 int k; //用于循环 15 int width, height; //记录图片到宽和高 16 png_byte color_type; //图片到类型(可能会用在是否是开启来通道) 17 png_byte bit_depth; //字节深度 18 19 png_structp png_ptr; //图片 20 png_infop info_ptr; //图片的信息 21 int number_of_passes; //隔行扫描 22 png_bytep * row_pointers;//图片的数据内容 23 int row,col,pos,channels,size; //用于改变png像素排列的问题。 24 25 FILE *fp=fopen(filepath,"rb");//以只读形式打开文件名为file_name的文件 26 if(!fp)//做出相应可能的错误处理 27 { 28 fclose(fp);//关闭打开的文件!给出默认贴图 29 return 0;//此处应该调用一个生成默认贴图返回ID的函数 30 } 31 //读取文件头判断是否所png图片.不是则做出相应处理 32 fread(header, 1, 8, fp); 33 if(png_sig_cmp(header,0,8)) 34 { 35 fclose(fp); 36 return 0; //每个错误处理都是一样的!这样报错之后锁定就要花点小时间来! 37 } 38 39 //根据libpng的libpng-manual.txt的说明使用文档 接下来必须初始化png_structp 和 png_infop 40 png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); //后三个是绑定错误以及警告的函数这里设置为空 41 if(!png_ptr)//做出相应到初始化失败的处理 42 { 43 fclose(fp); 44 return 0; 45 } 46 //根据初始化的png_ptr初始化png_infop 47 info_ptr=png_create_info_struct(png_ptr); 48 49 if(!info_ptr) 50 { 51 //初始化失败以后销毁png_structp 52 png_destroy_read_struct(&png_ptr,(png_infopp)NULL,(png_infopp)NULL); 53 fclose(fp); 54 return 0; 55 } 56 57 58 //老老实实按照libpng给到的说明稳定步骤来 错误处理! 59 if (setjmp(png_jmpbuf(png_ptr))) 60 61 { 62 //释放占用的内存!然后关闭文件返回一个贴图ID此处应该调用一个生成默认贴图返回ID的函数 63 64 png_destroy_read_struct(&png_ptr,(png_infopp)NULL,(png_infopp)NULL); 65 66 fclose(fp); 67 68 return 0; 69 70 } 71 //你需要确保是通过2进制打开的文件。通过i/o定制函数png_init_io 72 png_init_io(png_ptr,fp); 73 //似乎是说要告诉libpng文件从第几个开始missing 74 png_set_sig_bytes(png_ptr, 8); 75 //如果你只想简单的操作你现在可以实际读取图片信息了! 76 png_read_info(png_ptr, info_ptr); 77 //获得图片到信息 width height 颜色类型 字节深度 78 channels = png_get_channels(png_ptr, info_ptr); /*获取通道数*/ 79 out->width = png_get_image_width(png_ptr, info_ptr); 80 out->height = png_get_image_height(png_ptr, info_ptr); 81 color_type = png_get_color_type(png_ptr, info_ptr); 82 //如果图片带有alpha通道就需要 83 // if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) 84 85 // png_set_swap_alpha(png_ptr); 86 out->bit_depth = png_get_bit_depth(png_ptr, info_ptr); 87 //隔行扫描图片 这个必须要调用才能进行 88 number_of_passes = png_set_interlace_handling(png_ptr); 89 //将读取到的信息更新到info_ptr 90 png_read_update_info(png_ptr, info_ptr); 91 92 //读文件 93 if (setjmp(png_jmpbuf(png_ptr))){ 94 fclose(fp); 95 return 0; 96 } 97 98 row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * out->height); 99 100 size = out->height*out->width;101 //通过扫描流里面的每一行将得到的数据赋值给动态数组 102 for (k=0; k<out->height; k++)103 //row_pointers[k] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));104 row_pointers[k] = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr,105 info_ptr));106 //由于png他的像素是由 左-右-从顶到底 而贴图需要的像素都是从左-右-底到顶的所以在这里需要把像素内容进行一个从新排列107 //读图片108 png_read_image(png_ptr, row_pointers);109 if(channels == 4 || color_type == PNG_COLOR_TYPE_RGB_ALPHA)110 {/*如果是RGB+alpha通道,或者RGB+其它字节*/111 112 size *= 4;//*sizeof(unsigned char); /* 每个像素点占3个字节内存 */113 pos = size - (4 * out->width);114 out->flag = HAVE_ALPHA; /* 标记 */115 out->rgba = (unsigned char*) malloc(size);116 if(out->rgba == NULL)117 {/* 如果分配内存失败 */118 fclose(fp);119 puts("错误(png):无法分配足够的内存供存储数据!");120 return 1;121 }122 for( row = 0; row < out->height; row++)123 {124 for( col = 0; col < (4 * out->width); col += 4)125 {126 out->rgba[pos++] = row_pointers[row][col]; // red127 out->rgba[pos++] = row_pointers[row][col + 1]; // green128 out->rgba[pos++] = row_pointers[row][col + 2]; // blue129 out->rgba[pos++] = row_pointers[row][col + 3]; // alpha130 }131 pos=pos - 4*out->width*2;132 }133 }134 else if(channels == 3 || color_type == PNG_COLOR_TYPE_RGB)135 {/* 如果是RGB通道 */136 size *= (3*sizeof(unsigned char)); /* 每个像素点占3个字节内存 */137 pos = size - (3* out->width);138 out->flag = NO_ALPHA; /* 标记 */139 out->rgba = (unsigned char*) malloc(size);140 141 142 if(out->rgba == NULL)143 {/* 如果分配内存失败 */144 fclose(fp);145 puts("错误(png):无法分配足够的内存供存储数据!");146 return 1;147 }148 149 for( row = 0; row < height; row++)150 {151 for( col = 0; col < (3 * width); col += 3)152 {153 out->rgba[pos++] = row_pointers[row][col]; // red154 out->rgba[pos++] = row_pointers[row][col + 1]; // green155 out->rgba[pos++] = row_pointers[row][col + 2]; // blue156 }157 pos=pos - 3*out->width*2;158 }159 }160 else return 1;161 /* 撤销数据占用的内存 */162 png_destroy_read_struct(&png_ptr, &info_ptr, 0);163 return 0;164 }
4、shader使用:
(1)创建着色器对象glCreateShader(type) 顶点和片段着色器对象
(2)把着色器代码和对象关联起来 glShaderSource(。。。)
(3)着色器源代码编译为目标代码 glComplieShader(....)
(4)检查是否编译成功glGetShaderiv(.....)
(5)创建着色器程序 glCreateProgram()
(6)将着色器对象链接到所创建的程序中 glAttachShader(....)
(7)将这些对象链接成一个可执行程序 glLinkProgram(.....)
(8)验证连接成功glGetProgramiv(...)
(9)使用着色器进行顶点或片段处理glUseProgram(.....);
(10)glBindAttribLocation(着色器程序对象, 对应glVertexAttribPointer里面绑定的值, 对应shader里面的属性); 顶点坐标,uv,颜色对应到shader属性 必须在glLinkProgram之前使用
(11)GLuint samplerA = glGetUniformLocation(programHandle,"gSampler"); glUniform1i(samplerA, 0); 在shader中为uniform gSampler纹理赋值
(12)gWVPLocation = glGetUniformLocation(programHandle,"gWVP"); 同上 设置正交投影矩阵
(13)正交投影矩阵赋值(在VBO+shader中gluOrtho2D不好使,不知道是不是自己使用不当)
float l= -100.0f,r=100.0f,t=100.0f,b=-100.0f,n=-100.0f,f=100.0f; // l:left r:right t:top b:bottom n:near f:far
float mat[16] = {2/(r-l),0,0,-(r+l)/(r-l), //正交投影矩阵 http://blog.csdn.net/popy007/article/details/4126809
0,2/(t-b),0,-(t+b)/(t-b),
0,0,2/(n-f),(n+f)/(n-f),
0,0,0,1};
glUniformMatrix4fv(gWVPLocation, 1, GL_FALSE, (const GLfloat*)mat);
(14)顶点和片段源码:
1 //basic.vert 2 #version 330 3 in vec3 Position; 4 in vec3 Color ; 5 in vec2 TexCoord ; 6 uniform mat4 gWVP; 7 out vec3 out_color; 8 out vec2 out_texcoord; 9 void main()10 {11 gl_Position = gWVP*vec4(Position, 1.0);12 out_color = Color;13 out_texcoord = TexCoord;14 }15 16 //basic.frag17 #version 33018 out vec4 FragColor;19 in vec3 out_color;20 in vec2 out_texcoord;21 uniform sampler2D gSampler;22 void main()23 {24 vec4 c= texture2D(gSampler,out_texcoord);25 FragColor = vec4(out_color+c.rgb, 1.0);26 }
简单串一下流程:
void init()
{
initVBO();
initShader("basic.vert","basic.frag");
glUniformMatrix4fv(gWVPLocation, 1, GL_FALSE, (const GLfloat*)mat);//正交投影矩阵不发生变化 所以可以放在初始化里面
initTexture();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,IndexID);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
glDrawElements(GL_TRIANGLES,6, GL_UNSIGNED_INT, 0);
glutSwapBuffers();
}
效果图:只使用颜色时候的效果:
仅使用纹理时候的效果:
纹理和颜色都使用的效果:
[原]OpenGL基础教程(四)VBO+纹理绘制四边形