[TOC]
纹理使用流程SetupRC:准备纹理数据【重点】
分配纹理、绑定纹理
纹理变量:一般使用无符号整型。GLuint textureID;
这个变量在分配纹理的时候就指定了,相当于是这个纹理的一个标识符(身份证)
如果要设置纹理,需要知道是设置哪个纹理,textureID 告诉你是哪个。
如果要获取纹理,也需要知道获取哪个纹理,同样的,textureID 告诉你是哪个。
所以 textureID 是在使用纹理的时候一个很重要的全局标识符
- 分配纹理
//分配纹理对象 参数1:纹理对象个数,参数2:纹理对象指针
glGenTextures(1, &textureID);
- 绑定纹理
//绑定纹理状态 参数1:纹理状态2D 参数2:纹理对象
glBindTexture(GL_TEXTURE_2D, textureID);
载入纹理
载入纹理流程很多时候,流程图比再多的文字解释更容易让人明白。
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
GLbyte *pBits;
int nWidth, nHeight, nComponents;
GLenum eFormat;
//1、读纹理位,读取像素
pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
if(pBits == NULL)
return false;
//2、设置纹理参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
//3.载入纹理
glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,
eFormat, GL_UNSIGNED_BYTE, pBits);
//使用完毕释放pBits
free(pBits);
//4.纹理生成所有的Mip层
if(minFilter == GL_LINEAR_MIPMAP_LINEAR ||
minFilter == GL_LINEAR_MIPMAP_NEAREST ||
minFilter == GL_NEAREST_MIPMAP_LINEAR ||
minFilter == GL_NEAREST_MIPMAP_NEAREST)
glGenerateMipmap(GL_TEXTURE_2D);
return true;
}
纹理坐标
金字塔一个金字塔:5个顶点 -> 6个三角形
金字塔的每一个边长度都为 根号2,X与Y交界处的那条边长为 2,而坐标系的原点就在这条边的中点。
如何给这个金字塔的6个三角形都设置纹理坐标?
- 创建5个顶点数据
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 };
- 设置 三角形X 和 三角形Y 的纹理坐标
- 三角形X的顶点:vBackLeft、vBackRight、vFrontRight
- 三角形Y的顶点:vFrontLeft、vBackLeft、vFrontRight
//vBackLeft
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3fv(vBackLeft);
//vBackRight
pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
pyramidBatch.Vertex3fv(vBackRight);
//vFrontRight
pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
pyramidBatch.Vertex3fv(vFrontRight);
函数:设置纹理坐标:MultiTexCoord2f
- 参数1:texture,纹理层次,对于使用存储着色器来进行渲染,设置为0
- 参数2:s:对应顶点坐标中的x坐标
- 参数3:t:对应顶点坐标中的y。(s,t,r,q对应顶点坐标的x,y,z,w)
重点就是如何设置顶点坐标与纹理坐标之间的对应关系
在3D空间里面,我们有6个方向,上下左右前后,这6个方向代表的就是观察者观察物体所在的方向。
三角形X和三角形Y都在金字塔的底部,所以观察者应该要从下面观察这个金字塔。
底部纹理坐标很多时候,图片真的比文字更有说服力
- 左边:表示从底部观察金字塔时看到的内容
- 右边:从底部观察时,“俯视图”坐标,也即每个点对应的纹理坐标
- 三角形前面的纹理坐标
在来一个前面的坐标:观察者从正前方观察金字塔看到的内容
前面纹理坐标//三角形:(Apex,vFrontLeft,vFrontRight)
pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
pyramidBatch.Vertex3fv(vApex);
pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
pyramidBatch.Vertex3fv(vFrontLeft);
pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
pyramidBatch.Vertex3fv(vFrontRight);
剩下的几个面就不再一一画图说明了,学习是举一反三的过程,而不是穷举的过程。
RenderScene:使用纹理
// 绑定纹理,因为我们的项目中只有一个纹理。如果有多个纹理。绑定纹理很重要
glBindTexture(GL_TEXTURE_2D, textureID);
// 纹理替换矩阵着色器
/*
参数1:GLT_SHADER_TEXTURE_REPLACE(着色器标签)
参数2:模型视图投影矩阵
参数3:纹理层
*/
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);
在使用纹理时,一般是两个步骤:
- 绑定纹理:
glBindTexture
。如果有多个纹理的时候,我们需要知道我们当前使用的 纹理是哪一个,所以在绘制之前需要执行一次绑定纹理的操作。 - 纹理替换着色器:
GLT_SHADER_TEXTURE_REPLACE
。只有使用了这个着色器,在绘制的时候才会去寻找纹理数据,进行渲染。
【疑问】
OpenGL的状态机是否每次只能指定一个纹理对象 textureID
?
ShutdownRC:删除纹理
在介绍纹理的文章中讲到了,使用纹理是一个比较耗性能的,所以在使用完之后,需要删除纹理。
void ShutdownRC(void)
{
glDeleteTextures(1, &textureID);
}
int main(int argc, char* argv[])
{
……
glutMainLoop();
ShutdownRC();
return 0;
}
网友评论