第二十节—纹理隧道
2020-09-05 本文已影响0人
L_Ares
本文为L_Ares个人写作,包括图片皆为个人亲自操作,以任何形式转载请表明原文出处。
本节为代码,主要综合了之前的一些知识。绘制出一条带有纹理的隧道
//
// main.cpp
// 10隧道
//
// Created by EasonLi on 2020/9/4.
// Copyright © 2020 EasonLi. All rights reserved.
//
#include <stdio.h>
#pragma mark - 引用类
//工具类。包含大多数的GLTool中类似C语言的函数
#include "GLTools.h"
//着色器管理器类,包含一些初级的操作
#include "GLShaderManager.h"
//参考帧。坐标等
#include "GLFrame.h"
//设置投影矩阵类
#include "GLFrustum.h"
//矩阵堆栈类
#include "GLMatrixStack.h"
//三角形批次类
#include "GLBatch.h"
//矩阵堆栈管道类
#include "GLGeometryTransform.h"
//GLUT库
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
#pragma mark - 常用变量
//着色器管理器
GLShaderManager shaderManager;
//模型视图矩阵堆栈
GLMatrixStack modelViewMatrixStack;
//投影矩阵堆栈
GLMatrixStack projectionMatrixStack;
//视景体
GLFrustum viewFrustum;
//矩阵堆栈管理管道
GLGeometryTransform transformPipeline;
//三角形批次类
//地板的批次类
GLBatch floorBatch;
//天花板批次类
GLBatch ceilingBatch;
//左墙面
GLBatch leftWallBatch;
//右墙面
GLBatch rightWallBatch;
//深度值初始值
GLfloat viewZ = -65.f;
//纹理标识符号
//墙面
#define TEXTURE_BRICK 0
//地板
#define TEXTURE_FLOOR 1
//纹理天花板
#define TEXTURE_CEILING 2
//纹理数量
#define TEXTURE_COUNT 3
//纹理标记数组
GLuint nTextures[TEXTURE_COUNT];
//纹理名字数组
const char *textureName[TEXTURE_COUNT] = {"brick.tga","floor.tga","ceiling.tga"};
#pragma mark - 函数
//窗口第一次创建或者大小改变时调用
void ChangeSize(int w , int h)
{
if (h == 0) {
h = 1;
}
//设置视口大小
glViewport(0, 0, w, h);
//通过视景体来设置投影方式
viewFrustum.SetPerspective(88.f, float(w)/float(h), 1.f, 160.f);
//获取投影矩阵并放置到投影矩阵堆栈栈顶
projectionMatrixStack.LoadMatrix(viewFrustum.GetProjectionMatrix());
//设置矩阵堆栈变换管道
transformPipeline.SetMatrixStacks(modelViewMatrixStack, projectionMatrixStack);
}
/**
将.tga文件加载成纹理
函数功能包含了读取、加载、设置纹理
参数:
(1).minFilter:缩小过滤模式
(2).maxFilter:放大过滤模式
(3).wrapMode:环绕方式
*/
bool LoadMyTextures (GLenum minFilter,GLenum maxFilter,GLenum wrapMode)
{
//读取tga文件返回的是字节类型的纹理的数据,所以定义一个字节类型变量
GLbyte *nByte;
//定义变量:宽、高、每个纹理单元存储的颜色成分数量
int nWidth,nHeight,nComponent;
//定义变量:载入纹理要用的像素模式
GLenum nFormat;
//生成纹理标记,分配纹理对象
glGenTextures(TEXTURE_COUNT, nTextures);
//利用循环设置纹理数组中的各纹理的参数
for (int i = 0; i < TEXTURE_COUNT; i++) {
//绑定纹理对象
glBindTexture(GL_TEXTURE_2D, nTextures[i]);
//加载.tga文件
nByte = gltReadTGABits(textureName[i], &nWidth, &nHeight, &nComponent, &nFormat);
if (nByte == NULL) {
return false;
}
//设置纹理过滤模式和环绕模式
//纹理过滤器,放大过滤
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, maxFilter);
//缩小过滤
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
//设置环绕模式
//S轴环绕,横向轴
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
//T轴环绕,纵向轴
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
//载入纹理
glTexImage2D(GL_TEXTURE_2D, 0, nComponent, nWidth, nHeight, 0, nFormat, GL_UNSIGNED_BYTE, nByte);
//为纹理生成一组mipmap
glGenerateMipmap(GL_TEXTURE_2D);
//释放纹理原始数据
free(nByte);
}
return true;
}
//绘制地板
//depth:地板多长,就是地板深度
void DrawFloor (GLfloat depth)
{
//设置地板的三角形批次类
//参数:
//(1).绘制地板要用的图元类型
//(2).绘制地板要多少顶点
//(3).要用到几组纹理坐标
floorBatch.Begin(GL_TRIANGLE_STRIP, 28,1);
//利用循环画地板
for (GLfloat z = depth; z >= 0.f; z-=10.f) {
//设置纹理坐标和顶点坐标
floorBatch.MultiTexCoord2f(0, 0.f, 0.f);
floorBatch.Vertex3f(-10.f, -10.f, z);
floorBatch.MultiTexCoord2f(0, 1.f, 0.f);
floorBatch.Vertex3f(10.f, -10.f, z);
floorBatch.MultiTexCoord2f(0, 0.f, 1.f);
floorBatch.Vertex3f(-10.f, -10.f, z - 10.f);
floorBatch.MultiTexCoord2f(0, 1.f, 1.f);
floorBatch.Vertex3f(10.f, -10.f, z - 10.f);
}
floorBatch.End();
}
//绘制天花板
void DrawCeiling (GLfloat depth)
{
//设置天花板三角形批次类
ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28,1);
for (GLfloat z = depth; z >= 0.f; z-=10.f) {
ceilingBatch.MultiTexCoord2f(0, 0.f, 0.f);
ceilingBatch.Vertex3f(-10.f, 10.f, z);
ceilingBatch.MultiTexCoord2f(0, 0.f, 1.f);
ceilingBatch.Vertex3f(-10.f, 10.f, z - 10.f);
ceilingBatch.MultiTexCoord2f(0, 1.f, 0.f);
ceilingBatch.Vertex3f(10.f, 10.f, z);
ceilingBatch.MultiTexCoord2f(0, 1.f, 1.f);
ceilingBatch.Vertex3f(10.f, 10.f, z - 10.f);
}
ceilingBatch.End();
}
//绘制左墙面
void DrawLeftWall (GLfloat depth)
{
leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28,1);
for (GLfloat z = depth; z >= 0.f; z-=10.f) {
leftWallBatch.MultiTexCoord2f(0, 0.f, 0.f);
leftWallBatch.Vertex3f(-10.f, -10.f, z);
leftWallBatch.MultiTexCoord2f(0, 0, 1.f);
leftWallBatch.Vertex3f(-10.f, 10.f, z);
leftWallBatch.MultiTexCoord2f(0, 1.f, 0.f);
leftWallBatch.Vertex3f(-10.f, -10.f, z - 10.f);
leftWallBatch.MultiTexCoord2f(0, 1.f, 1.f);
leftWallBatch.Vertex3f(-10.f, 10.f, z - 10.f);
}
leftWallBatch.End();
}
//绘制右墙面
void DrawRightWall (GLfloat depth)
{
rightWallBatch.Begin(GL_TRIANGLE_STRIP, 28.f,1);
for (GLfloat z = depth; z >= 0.f; z-=10) {
rightWallBatch.MultiTexCoord2f(0, 0.f, 0.f);
rightWallBatch.Vertex3f(10.f, -10.f, z);
rightWallBatch.MultiTexCoord2f(0, 0, 1.f);
rightWallBatch.Vertex3f(10.f, 10.f, z);
rightWallBatch.MultiTexCoord2f(0, 1.f, 0.f);
rightWallBatch.Vertex3f(10.f, -10.f, z - 10.f);
rightWallBatch.MultiTexCoord2f(0, 1.f, 1.f);
rightWallBatch.Vertex3f(10.f, 10.f, z - 10.f);
}
rightWallBatch.End();
}
//设置渲染环境
void SetUpRC ()
{
//设置清屏颜色
glClearColor(0.0f, 0.0f, 0.0f, 1.f);
//初始化着色器管理器
shaderManager.InitializeStockShaders();
bool result;
//设置纹理信息
result = LoadMyTextures(GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE);
if (result) {
//绘制地板
DrawFloor(60.f);
//绘制天花板
DrawCeiling(60.f);
//绘制左墙面
DrawLeftWall(60.f);
//绘制右墙面
DrawRightWall(60.f);
}else{
printf("读取不到纹理");
}
}
//渲染
void RenderScene ()
{
//清空缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//压栈
modelViewMatrixStack.PushMatrix();
modelViewMatrixStack.Translate(0.f, 0.f, viewZ);
//设置着色器
//地板
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE,transformPipeline.GetModelViewProjectionMatrix(),0);
//绑定纹理
glBindTexture(GL_TEXTURE_2D, nTextures[TEXTURE_FLOOR]);
//地板绘制
floorBatch.Draw();
//天花板
glBindTexture(GL_TEXTURE_2D, nTextures[TEXTURE_CEILING]);
ceilingBatch.Draw();
//左侧墙面
glBindTexture(GL_TEXTURE_2D, nTextures[TEXTURE_BRICK]);
leftWallBatch.Draw();
rightWallBatch.Draw();
//出栈
modelViewMatrixStack.PopMatrix();
//交换缓冲区
glutSwapBuffers();
}
//特殊键位
void SpecialKeys (int key , int x , int y)
{
switch (key) {
case GLUT_KEY_UP:
viewZ += 1.f;
break;
case GLUT_KEY_DOWN:
viewZ -= 1.f;
break;
}
glutPostRedisplay();
}
//右键选择
void RightButtonMenu (int value)
{
for (int i = 0; i < TEXTURE_COUNT; i++) {
//更改纹理前,记得绑定纹理,OpenGL这才会知道你要修改哪个纹理
glBindTexture(GL_TEXTURE_2D, nTextures[i]);
switch (value) {
case 0:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
break;
case 1:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
break;
case 2:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
break;
case 3:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
break;
case 4:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
break;
case 5:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
break;
case 6:
//设置各向异性过滤
//定义变量存储各向异性过滤的最大数量
GLfloat fMax;
//获取各向异性过滤最大数量
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fMax);
//设置纹理参数
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fMax);
break;
case 7:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f);
break;
}
}
glutPostRedisplay();
}
//关闭纹理
void ShutDownTexture ()
{
glDeleteTextures(TEXTURE_COUNT, nTextures);
}
#pragma mark - main
int main (int argc,char *argv[])
{
//设置工作目录和项目目录在同一文件夹下/Resource
//glut的初始化已经设置过了,手动保证安全
gltSetWorkingDirectory(argv[0]);
//glut初始化
glutInit(&argc, argv);
//初始化显示模式
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
//初始化窗口大小
glutInitWindowSize(600, 600);
//创建窗口并命名
glutCreateWindow("隧道");
//注册函数
//重塑函数
glutReshapeFunc(ChangeSize);
//渲染函数
glutDisplayFunc(RenderScene);
//特殊键位函数
glutSpecialFunc(SpecialKeys);
//右键菜单栏
glutCreateMenu(RightButtonMenu);
glutAddMenuEntry("GL_NEAREST",0);
glutAddMenuEntry("GL_LINEAR",1);
glutAddMenuEntry("GL_NEAREST_MIPMAP_NEAREST",2);
glutAddMenuEntry("GL_NEAREST_MIPMAP_LINEAR", 3);
glutAddMenuEntry("GL_LINEAR_MIPMAP_NEAREST", 4);
glutAddMenuEntry("GL_LINEAR_MIPMAP_LINEAR", 5);
glutAddMenuEntry("Anisotropic Filter", 6);
glutAddMenuEntry("Anisotropic Off", 7);
//连接到右键的点击事件上
glutAttachMenu(GLUT_RIGHT_BUTTON);
//初始化glew库
GLenum status = glewInit();
if (status != GLEW_OK) {
printf("glew init error : %s \n",glewGetErrorString(status));
return 1;
}
//设置渲染环境
SetUpRC();
//建立本地信息循环
glutMainLoop();
//关闭纹理
ShutDownTexture();
return 0;
}
效果图如下图1.1所示:
1.1.png纹理的.tga文件在这里:
纹理tga文件
提取码:uhtv。
本节结束。