原始图像数据
图像的存储空间 = 图像的高度 * 图像的宽度 * 每个像素点占用的字节数
我们在OpenGL中使用的纹理文件是:.tga
后缀的文件:

图像的函数


/// 改变像素存储方式
void glPixelStorei(GLenum pname , GLint param);
/// 恢复像素存储方式
void glPixelStoref(GLenum pname , GLfloat param);
//举例:
//参数1:枚举类型 用来指定OpenGL用什么方式从缓存中解包图像数据
//参数2:为参数1指定的方式设置一个值
//GL_UNPACK_ALIGNMENT 指内存中每个像素⾏起点的排列列请求,
//允许设置为1 (byte排列列)、2(排列列为偶数byte的⾏行行)、4(字word排列列)、8(行从双字节 边界开始)
void glPixelStorei(GL_UNPACK_ALIGNMENT,1);
/// 从颜色缓存区内容作为像素图直接读取
// 参数1:矩形左下角的窗口坐标;
// 参数2:矩形左下角的窗口坐标;
// 参数3:矩形的宽,以像素为单位
// 参数4: 矩形的高,以像素为单位
// 参数5:OpenGL的像素格式
// 参数6:解释参数7-> pixels指向的数据,告诉OpenGL使用缓存区中的什么类型数据来存储颜色分量,像素数据的数据类型,参考表6-2;
// 参数7: pixels 指向图形数据的指针
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, Glenn format, GLenum type, GLvoid *pixels)
void glReadBuffer(mode); // 指定读取的内容
void glWriteBuffer(mode); //指定写入的缓存
/// 载入纹理
void glTexImage1D(<#GLenum target#>, <#GLint level#>, <#GLint internalformat#>, <#GLsizei width#>, <#GLint border#>, <#GLenum format#>, <#GLenum type#>, <#const GLvoid *pixels#>)
void glTexImage2D(<#GLenum target#>, <#GLint level#>, <#GLint internalformat#>, <#GLsizei width#>, <#GLsizei height#>, <#GLint border#>, <#GLenum format#>, <#GLenum type#>, <#const GLvoid *pixels#>)
//参数解释:
//target: 枚举 -> `GL_TEXTURE_1D`、`GL_TEXTURE_2D`、`GL_TEXTURE_3D`
//level: 指定所夹在的mip贴图层次,通常设置为0;
//internalformat: 每个纹理单元中存储多少颜色成分
//width / height : 宽 / 高 这些值必须是2的整数次方(旧版本OpenGL的要求,新版本已经支持非2的整数次方)
//border: 允许纹理贴图指定一个边界宽度;
//format: 与glReadPixels(...);方法中一样
//type:与glReadPixels(...);方法中一样
//pixels:与glReadPixels(...);方法中一样
//更新纹理:
void glTexSubImage1D(<#GLenum target#>, <#GLint level#>, <#GLint xoffset#>, <#GLsizei width#>, <#GLenum format#>, <#GLenum type#>, <#const GLvoid *pixels#>)
void glTexSubImage2D(<#GLenum target#>, <#GLint level#>, <#GLint xoffset#>, <#GLint yoffset#>, <#GLsizei width#>, <#GLsizei height#>, <#GLenum format#>, <#GLenum type#>, <#const GLvoid *pixels#>)
//插入替换纹理
void glCopyTexSubImage1D(<#GLenum target#>, <#GLint level#>, <#GLint xoffset#>, <#GLint x#>, <#GLint y#>, <#GLsizei width#>)
void glCopyTexSubImage2D(<#GLenum target#>, <#GLint level#>, <#GLint xoffset#>, <#GLint yoffset#>, <#GLint x#>, <#GLint y#>, <#GLsizei width#>, <#GLsizei height#>)
// 使用颜色缓存区加载数据,形成新的纹理使⽤
void glCopyTexImage1D(<#GLenum target#>, <#GLint level#>, <#GLenum internalFormat#>, <#GLint x#>, <#GLint y#>, <#GLsizei width#>, <#GLint border#>)
void glCopyTexImage2D(<#GLenum target#>, <#GLint level#>, <#GLenum internalFormat#>, <#GLint x#>, <#GLint y#>, <#GLsizei width#>, <#GLsizei height#>, <#GLint border#>)
//纹理对象
//指定纹理对象的个数和直指针
void glGenTextures(<#GLsizei n#>, <#GLuint *textures#>)
/// 绑定纹理对象
// target : GL_TEXTURE_1D , GL_TEXTURE_2D , GL_TEXTURE_3D;
// texture : 需要绑定的纹理对象
void glBindTexture(<#GLenum target#>, <#GLuint texture#>)
/// 删除绑定纹理对象 , 离开界面的时候删除纹理或者是不需要在使用的时候删除
void glDeletTexture(<#GLsizei n#> , <#GLuint texture#>);
/// 测试纹理对象是否有效
// texture : 被测试的纹理对象
void glIsTexture(<#GLuint texture#>)
-
纹理对象三步走
纹理对象三步走.png
设置纹理参数 - 过滤方式
///设置纹理参数
void glTexParameterf(<#GLenum target#>, <#GLenum pname#>, <#GLfloat param#>)
void glTexParameteri(<#GLenum target#>, <#GLenum pname#>, <#GLint param#>)
void glTexParameterfv(<#GLenum target#>, <#GLenum pname#>, <#const GLfloat *params#>)
void glTexParameteriv(<#GLenum target#>, <#GLenum pname#>, <#const GLint *params#>)
//参数解释:
//target : 指定纹理模式 : GL_TEXTURE_1/2/3D
//panme : 需要设置的纹理参数GL_TEXTURE_MIN_FILTER(放大) / GL_TEXTURE_MAG_FILTER(缩小)
//param : 参数的值 GL_NEAREST(临近过滤 ) / GL_LINEAR(线性过滤)
//遗留问题: 四个方法的区别???????
//举例:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
-
临近过滤与线性过滤的图形效果
图片取自逻辑教育_CC老师课件
设置纹理参数 - 环绕方式
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_T,GL_CLAMP_TO_EDGE);
//参数1: GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
//参数2: GL_TEXTURE_WRAP_S、GL_TEXTURE_T、GL_TEXTURE_R
//参数3: GL_REPEAT:OpenGL/GL_CLAMP/GL_CLAMP_TO_EDGE/GL_CLAMP_TO_BORDER

纹理坐标
纹理坐标命名为s/ t/r/q
类似顶点坐标x/y/z/w
q
坐标对于几何图形坐标w
,作为缩放因子,作用于其他纹理坐标。也就是说,实际上所使用的纹理坐标是s/q
、t/q
和r/q
。在默认情况下,q
设置为1.0
。

2D纹理坐标
在x
和y
轴上,范围为0~1
之间。使用纹理坐标获取纹理颜色叫做采用(Sampling
)。
假定纹理坐标的起点为(0,0
),那么一张图片的纹理坐标应如下图:

如果此时我们需要绘制一个三角形:

上图中三角形的三个顶点的纹理坐标应该分别是:(0,0),(1,0),(0.5,1)
纹理的映射关系
在使用一张图片时,我们可以随意旋转,但是无法做到交叉

金字塔案例

void SetupRC()
{
//1.
glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
shaderManager.InitializeStockShaders();
//2.开启深度测试
glEnable(GL_DEPTH_TEST);
//3.
//分配纹理对象 参数1:纹理对象个数,参数2:纹理对象指针
glGenTextures(1, &textureID);
//绑定纹理状态 参数1:纹理状态2D 参数2:纹理对象
glBindTexture(GL_TEXTURE_2D, textureID);
//将TGA文件加载为2D纹理。
//参数1:纹理文件名称
//参数2&参数3:需要缩小&放大的过滤器
//参数4:纹理坐标环绕模式
LoadTGATexture("stone.tga", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, GL_CLAMP_TO_EDGE);
//4.创造金字塔pyramidBatch
MakePyramid(pyramidBatch);
//5.
/**相机frame MoveForward(平移)
参数1:Z,深度(屏幕到图形的Z轴距离)
*/
cameraFrame.MoveForward(-10);
}
// 将TGA文件加载为2D纹理。
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
GLbyte *pBits;
int nWidth, nHeight, nComponents;
GLenum eFormat;
//1、读纹理位,读取像素
//参数1:纹理文件名称
//参数2:文件宽度地址
//参数3:文件高度地址
//参数4:文件组件地址
//参数5:文件格式地址
//返回值:pBits,指向图像数据的指针
pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
if(pBits == NULL)
return false;
//2、设置纹理参数
//参数1:纹理维度
//参数2:为S/T坐标设置模式
//参数3:wrapMode,环绕模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
//参数1:纹理维度
//参数2:线性过滤
//参数3:wrapMode,环绕模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
//3.载入纹理
//参数1:纹理维度
//参数2:mip贴图层次
//参数3:纹理单元存储的颜色成分(从读取像素图是获得)
//参数4:加载纹理宽
//参数5:加载纹理高
//参数6:加载纹理的深度
//参数7:像素数据的数据类型(GL_UNSIGNED_BYTE,每个颜色分量都是一个8位无符号整数)
//参数8:指向纹理图像数据的指针
glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,
eFormat, GL_UNSIGNED_BYTE, pBits);
//使用完毕释放pBits
free(pBits);
//4.加载Mip,纹理生成所有的Mip层
//参数:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
glGenerateMipmap(GL_TEXTURE_2D);
return true;
}
绘制金字塔纹理
//绘制金字塔
void MakePyramid(GLBatch& pyramidBatch)
{
/*1、通过pyramidBatch组建三角形批次
参数1:类型
参数2:顶点数
参数3:这个批次中将会应用1个纹理
注意:如果不写这个参数,默认为0。
*/
pyramidBatch.Begin(GL_TRIANGLES, 18, 1);
1)设置法线
void Normal3f(GLfloat x, GLfloat y, GLfloat z);
Normal3f:添加一个表面法线(法线坐标 与 Vertex顶点坐标中的Y轴一致)
表面法线是有方向的向量,代表表面或者顶点面对的方向(相反的方向)。在多数的关照模式下是必须使用。后面的课程会详细来讲法线的应用
pyramidBatch.Normal3f(X,Y,Z);
2)设置纹理坐标
void MultiTexCoord2f(GLuint texture, GLclampf s, GLclampf t);
参数1:texture,纹理层次,对于使用存储着色器来进行渲染,设置为0
参数2:s:对应顶点坐标中的x坐标
参数3:t:对应顶点坐标中的y
(s,t,r,q对应顶点坐标的x,y,z,w)
pyramidBatch.MultiTexCoord2f(0,s,t);
3)void Vertex3f(GLfloat x, GLfloat y, GLfloat z);
void Vertex3fv(M3DVector3f vVertex);
向三角形批次类添加顶点数据(x,y,z);
pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f);
4)获取从三点找到一个法线坐标(三点确定一个面)
void m3dFindNormal(result,point1, point2,point3);
//塔顶
M3DVector3f vApex = { 0.0f, 1.0f, 0.0f };
M3DVector3f vFrontLeft = { -1.0f, -1.0f, 1.0f };
M3DVector3f vFrontRight = { 1.0f, -1.0f, 1.0f };
M3DVector3f vBackLeft = { -1.0f, -1.0f, -1.0f };
M3DVector3f vBackRight = { 1.0f, -1.0f, -1.0f };
M3DVector3f n; // 此处的n就是用来存储法线的
//金字塔底部
//底部的四边形 = 三角形X + 三角形Y
//三角形X = (vBackLeft,vBackRight,vFrontRight)
//1.找到三角形X 法线
m3dFindNormal(n, vBackLeft, vBackRight, vFrontRight);
//vBackLeft
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3fv(vBackLeft);
//vBackRight
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
pyramidBatch.Vertex3fv(vBackRight);
//vFrontRight
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
pyramidBatch.Vertex3fv(vFrontRight);
//三角形Y =(vFrontLeft,vBackLeft,vFrontRight)
//1.找到三角形y 法线
m3dFindNormal(n, vFrontLeft, vBackLeft, vFrontRight);
//vFrontLeft
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
pyramidBatch.Vertex3fv(vFrontLeft);
//vBackLeft
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3fv(vBackLeft);
//vFrontRight
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
pyramidBatch.Vertex3fv(vFrontRight);
// 金字塔前面
//三角形:(Apex,vFrontLeft,vFrontRight)
m3dFindNormal(n, vApex, vFrontLeft, vFrontRight);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
pyramidBatch.Vertex3fv(vApex);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3fv(vFrontLeft);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
pyramidBatch.Vertex3fv(vFrontRight);
//金字塔左边
//三角形:(vApex, vBackLeft, vFrontLeft)
m3dFindNormal(n, vApex, vBackLeft, vFrontLeft);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
pyramidBatch.Vertex3fv(vApex);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
pyramidBatch.Vertex3fv(vBackLeft);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3fv(vFrontLeft);
//金字塔右边
//三角形:(vApex, vFrontRight, vBackRight)
m3dFindNormal(n, vApex, vFrontRight, vBackRight);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
pyramidBatch.Vertex3fv(vApex);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
pyramidBatch.Vertex3fv(vFrontRight);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3fv(vBackRight);
//金字塔后边
//三角形:(vApex, vBackRight, vBackLeft)
m3dFindNormal(n, vApex, vBackRight, vBackLeft);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
pyramidBatch.Vertex3fv(vApex);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3fv(vBackRight);
pyramidBatch.Normal3fv(n);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
pyramidBatch.Vertex3fv(vBackLeft);
//结束批次设置
pyramidBatch.End();
}
金字塔的坐标解析

顶点坐标
vApex(0.0, 1.0, 0.0)
vBackLeft(-1.0, -1.0, -1.0)
vBackRight(1.0. -1.0, -1.0)
vFrontRight(1.0, -1.0, 1.0)
vFrontLeft(-1.0, -1.0, 1.0)
对应的纹理坐标 (注意,此处第一位0是表示level = 0 , 后两位数才是纹理上的坐标) ;
vApex(0,0.5,1)
vFrontLeft(0.0, 0.0, 1.0)
vBackLeft(0.0, 0.0, 0.0)
vFrontRight(0.0, 1.0, 1.0)
回顾一下上面的代码注释中:
2)设置纹理坐标
void MultiTexCoord2f(GLuint texture, GLclampf s, GLclampf t);
参数1:texture,纹理层次,
对于使用存储着色器来进行渲染,设置为0
参数2:s->对应顶点坐标中的x坐标
参数3:t->对应顶点坐标中的y`
(s,t,r,q对应顶点坐标的x,y,z,w)
下面这张图很好的诠释了金字塔底部的纹理坐标取值原理:

本文参考了简书作者:[佐_笾]的<<OpenGL/OpenGL ES入门: 纹理应用 - 纹理坐标及案例解析(金字塔)>>
网友评论