03源码--005--纹理应用:金字塔贴图

2020-07-20  本文已影响0人  修_远

[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个三角形都设置纹理坐标?

  1. 创建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 };
  1. 设置 三角形X 和 三角形Y 的纹理坐标
//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

重点就是如何设置顶点坐标与纹理坐标之间的对应关系

在3D空间里面,我们有6个方向,上下左右前后,这6个方向代表的就是观察者观察物体所在的方向。

三角形X和三角形Y都在金字塔的底部,所以观察者应该要从下面观察这个金字塔。

底部纹理坐标

很多时候,图片真的比文字更有说服力

  1. 三角形前面的纹理坐标

在来一个前面的坐标:观察者从正前方观察金字塔看到的内容

前面纹理坐标
//三角形:(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);

在使用纹理时,一般是两个步骤:

  1. 绑定纹理:glBindTexture。如果有多个纹理的时候,我们需要知道我们当前使用的 纹理是哪一个,所以在绘制之前需要执行一次绑定纹理的操作。
  2. 纹理替换着色器:GLT_SHADER_TEXTURE_REPLACE。只有使用了这个着色器,在绘制的时候才会去寻找纹理数据,进行渲染。

【疑问】
OpenGL的状态机是否每次只能指定一个纹理对象 textureID

ShutdownRC:删除纹理

在介绍纹理的文章中讲到了,使用纹理是一个比较耗性能的,所以在使用完之后,需要删除纹理。

void ShutdownRC(void)
{
    glDeleteTextures(1, &textureID);
}

int main(int argc, char* argv[])
{
    ……
    glutMainLoop();
    
    ShutdownRC();
    
    return 0;
}
上一篇下一篇

猜你喜欢

热点阅读