iOS视觉(八) -- OpenGL纹理使用案例

507 阅读3分钟

一、纹理绘制

这里简单的使用纹理来绘制一个通道的界面:

这个界面可以简单的分为四个部分:上下左右四个墙面。经过前面的学习知道每一个面其实都是由许多个三角形构成。

例如地板的绘制:

它就是由多个三角形组合成一个梯形图像。

按照上面的示例来看,一共需要三个纹理:天花板、地板、墙壁(左右墙壁纹理一致为同一个)

来创建三个宏定义、存放纹理的数组以及纹理文件名字的数组:

#define TEXTURE_BRICK   0    //墙面
#define TEXTURE_FLOOT   1    //地板
#define TEXTURE_CEILING 2    //天花板
#define TEXTURE_COUNT   3    //纹理个数

GLuint textures[TEXTURE_COUNT];//纹理数组

//文件tag名字数组
const char *szTextureFiles[TEXTURE_COUNT] = { "brick.tga", "floor.tga", "ceiling.tga" };

//4个批次容器类
GLBatch             floorBatch;//地面
GLBatch             ceilingBatch;//天花板
GLBatch             leftWallBatch;//左墙面
GLBatch             rightWallBatch;//右墙面

1.1、纹理相关设置

根据前文得知, 设置纹理步骤为:

  1. 生成纹理标记
  2. 加载纹理文件
  3. 设置纹理参数(过滤、环绕等)
  4. 纹理载入

这里由于需要三个纹理,直接使用for循环来生成相关纹理并进行设置:

//加载纹理
GLbyte *pBytes;
GLint iWidth, iHeigth, iComponents;
GLenum eFormat;
GLint iLoop;

//生成纹理标记
glGenTextures(TEXTURE_COUNT, textures);

//循环生成纹理数组参数
for (iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++) {
    
    glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
    
    //加载TGA文件
    pBytes = gltReadTGABits(szTextureFiles[iLoop], &iWidth, &iHeigth, &iComponents, &eFormat);
    
    //纹理参数 -- 放大/缩小过滤方式
    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_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


    //纹理载入
    glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeigth, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
    
    //纹理维度
    glGenerateMipmap(GL_TEXTURE_2D);
    free(pBytes);
}
    

1.2、顶点设置

这里需要生成4组顶点数据,分别在4个批次类上:

//设置几何图形顶点/纹理坐标(上.下.左.右)

GLfloat z;//Z表示深度,隧道的深度

floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);

 for(z = 60.0f; z >= 0.0f; z -=10.0f)
 {
     floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
     floorBatch.Vertex3f(-10.0f, -10.0f, z);
     
     floorBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
     floorBatch.Vertex3f(10.0f, -10.0f, z);
     
     floorBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
     floorBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
     
     floorBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
     floorBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
 }
 floorBatch.End();

 ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
 for(z = 60.0f; z >= 0.0f; z -=10.0f)
 {
     ceilingBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
     ceilingBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);
     
     ceilingBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
     ceilingBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
     
     ceilingBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
     ceilingBatch.Vertex3f(-10.0f, 10.0f, z);
     
     ceilingBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
     ceilingBatch.Vertex3f(10.0f, 10.0f, z);
 }
 ceilingBatch.End();
 
 
 leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
 for(z = 60.0f; z >= 0.0f; z -=10.0f)
 {
     leftWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
     leftWallBatch.Vertex3f(-10.0f, -10.0f, z);
     
     leftWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
     leftWallBatch.Vertex3f(-10.0f, 10.0f, z);
     
     leftWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
     leftWallBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
     
     leftWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
     leftWallBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);
 }
 leftWallBatch.End();

 rightWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
 for(z = 60.0f; z >= 0.0f; z -=10.0f)
 {
     rightWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
     rightWallBatch.Vertex3f(10.0f, -10.0f, z);
     
     rightWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
     rightWallBatch.Vertex3f(10.0f, 10.0f, z);
     
     rightWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
     rightWallBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
     
     rightWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
     rightWallBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
 }
 rightWallBatch.End();

1.3、纹理绘制

纹理绘制与前文图元绘制流程大致相似,但是这里也稍微有一些改变:

  1. 视图模型矩阵压栈
  2. 使用纹理替换矩阵着色器
  3. 绑定纹理
  4. 批次类绘制

这里左右纹理为同一个纹理,所以只需要绑定一次后进行左右的批次类绘制即可。

//调用,绘制场景
void RenderScene(void)
{
    //用当前清除色,清除窗口
    glClear(GL_COLOR_BUFFER_BIT);
    
    //模型视图压栈
    modelViewMatrix.PushMatrix();
    //Z轴平移viewZ 距离
    modelViewMatrix.Translate(0.0f, 0.0f, viewZ);
    
    //纹理替换矩阵着色器
    /*
     参数1:GLT_SHADER_TEXTURE_REPLACE(着色器标签)
     参数2:模型视图投影矩阵
     参数3:纹理层
     */
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);
    
    //绑定纹理
    /*
     参数1:纹理模式,GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
     参数2:需要绑定的纹理
     */
    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_FLOOR]);
    floorBatch.Draw();
    
    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_CEILING]);
    ceilingBatch.Draw();
    
    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BRICK]);
    leftWallBatch.Draw();
    rightWallBatch.Draw();
    
    //pop
    modelViewMatrix.PopMatrix();
    
    //缓存区交换
    glutSwapBuffers();
}

运行程序就可以得到想要开头看到的效果