Opengl es2.0 学习笔记(七)基础纹理
一.使用纹理过程
-
使用FreeImage.lib 读取图片,获取调色板.(windows颜色不是rgb是bgr,此处需要转换)
-
glGenTextures创建一个纹理句柄
-
glBindTexture关联纹理
-
glTexParameteri设置纹理参数
-
glTexImage2D上传到opengl
经过上述步骤我们的纹理句柄就可以使用了
绘制过程
//! 清空缓冲区
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
//! 视口,在Windows窗口指定的位置和大小上绘制OpenGL内容
glViewport(0,0,_width,_height);
//绑定纹理
glBindTexture(GL_TEXTURE_2D,_textureId);
//传入正交投影矩阵 4*4
glUniformMatrix4fv(_shader._MVP, 1, false, matMVP.data());
//传入纹理ID,并且设置为0级纹理
glUniform1i(_shader._texture, 0);
//传入顶点坐标
glVertexAttribPointer(_shader._position,2, GL_FLOAT, false, sizeof(Vertex),vertex);
//传入uv坐标,即纹理坐标
glVertexAttribPointer(_shader._uv,2, GL_FLOAT, false, sizeof(Vertex),&vertex[0].uv);
//传入顶点颜色
glVertexAttribPointer(_shader._color, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex),&vertex[0].color);
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
//shader中代码
const char* vs =
{
"precision lowp float; " //指明精度
"uniform mat4 _MVP;" //正交投影
"attribute vec2 _position;" //传入顶点位置
"attribute vec4 _color;" //颜色
"varying vec4 _outColor;" //传递给片段着色器
"void main()"
"{"
" vec4 pos = vec4(_position,0,1);"//获取位置
" _outColor = _color;" //输出颜色赋值
" gl_Position = _MVP * pos;" //输出的位置
"}"
};
const char* ps =
{
"precision lowp float; "
"varying vec4 _outColor;"
"void main()"
"{"
"vec4 tColor = texture2D(_texture,_outUV);\n"//取颜色
" gl_FragColor = tColor*_outColor;" //加法是没有关系的颜色之间的叠加,而乘法是模拟光的照射过程
"}"
};
二.疑惑:
// index: 着色器脚本对应变量ID
// size : 此类型数据的个数
// type : 此类型的sizeof值
// normalized : 是否对非float类型数据转化到float时候进行归一化处理
// stride : 此类型数据在数组中的重复间隔宽度,byte类型计数
// ptr : 数据指针
glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);glDrawArrays(GL_TRIANGLE_STRIP,0,4);
问题来了,opengl上哪知道数据取多少呢?
答案:
我们使用这个函数,会指明我们要画的点的数量,这样opengl就知道我们需要取多少个元素了
glDrawArrays (GLenum mode, GLint first, GLsizei count);
三.API:
//产生一个纹理Id,可以认为是纹理句柄,后面的操作将书用这个纹理id
glGenTextures( 1, &textureId );
//使用这个纹理id,或者叫绑定(关联)
glBindTexture( GL_TEXTURE_2D, textureId );
/**
*指定纹理的放大,缩小滤波,使用线性方式,即当图片放大的时候插值方式
*/
//GL_TEXTURE_MAG_FILTER放大滤波
//GL_TEXTURE_MIN_FILTER缩小滤波
//GL_LINEAR 指定线性算法,效率低一些,质量好一些
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
/**
- 将图片的rgb数据上传给opengl.
*/
glTexImage2D(
GL_TEXTURE_2D, //! 指定是二维图片
0, //! 指定为第一级别,纹理可以做mipmap,即lod,离近的就采用级别大的,远则使用较小的纹理
GL_RGB, //! 纹理的使用的存储格式
width, //! 宽度,老一点的显卡,不支持不规则的纹理,即宽度和高度不是2^n。
height, //! 宽度,老一点的显卡,不支持不规则的纹理,即宽度和高度不是2^n。
0, //! 是否的边
GL_RGB, //! 数据的格式,bmp中,windows,操作系统中存储的数据是bgr格式
GL_UNSIGNED_BYTE, //! 数据是8bit数据,RGBA是8bit位
pixels
);
四.坐标
屏幕坐标:就是应用在设备屏幕上的坐标系。也就是图形最终绘制的地方。
左上角为原点,箭头为正方向,大小又屏幕像素大小决定。openGL的屏幕坐标系,Y轴向上为正。相当于上面那个三维坐标系截取一个二维的XY。
opengl坐标:
分3个轴,x,y,z 中心点为o, 箭头方向为正方向,最大与最小值为1和-1,这是经过归一化处理的。这样设计是为了显卡计算方便。
texture坐标
:
也做了归一化处理。这个坐标就代表了一个纹理。openGL是基于定点的网格绘制。就是说,openGL的图形都是由很多顶点,按照一定的规则链接起来构成的图形。那么纹理坐标的4个坐标点,映射到顶点上。openGL就会把这个纹理应用到4个定点构成的图形上。
五.纹理贴图的坐标变化:
我们通常使用顶点坐标是 :
屏幕坐标和 mvp矩阵,传入shader,然后 shader中输出点的变量
gl_Position = 屏幕坐标 X mvp矩阵 ,转换为了opengl坐标即-1~+1,屏幕中心点0,0为中心的坐标系
六.坐标对应表
纹理坐标的坐标系如下:
- 纹理坐标的 0,1相等于屏幕坐标的0,0
- 纹理坐标的1,0 相等于屏幕坐标的x,y
- 纹理坐标的1,1 相等于屏幕坐标的x,0
- 纹理坐标的0,0 相等于屏幕坐标的 0,y
如下表:
顶点坐标 | 纹理坐标 |
---|---|
CELL::float2(x,y) | CELL::float2(0 ,1) |
CELL::float2(x + w,y) | CELL::float2(1 ,1) |
CELL::float2(x,y + h) | CELL::float2(0 ,0) |
CELL::float2(x + w, y + h) | CELL::float2(1 ,0) |
如果纹理要顺时针转动:
屏幕坐标 | 纹理坐标 |
---|---|
CELL::float2(x,y) | CELL::float2(0 ,0) |
CELL::float2(x + w,y), | CELL::float2(0 ,1) |
CELL::float2(x,y + h) | CELL::float2(1 ,0) |
CELL::float2(x + w, y + h) | CELL::float2(1 ,1) |