隧道-几何球体 渲染

隧道:

建立顶点坐标系(0, 0 ,z),即视窗正中心位置

地板图

 

                         假设 (-10.0f,-10.0f,z)--------------->  A点

                                 (10.0f,-10.0f,z)--------------->  B点

                                 (10.0f,-10.0f,z - 10.0f)--------------->  C点

                                (-10.0f,-10.0f,z - 10.0f)--------------->  D点

                         由A,B,C,D 4个顶点需要组成的表面需要渲染,4点对于的纹理如下

                         A点   -------------------->   (0,0) ;

                         B点  -------------------->   (1,0) 

                         C点  -------------------->   (1,1) 

                         D点  -------------------->   (0,1) 

 

天花板

 

 

 

            顶点坐标   ------->   纹理坐标           

           (-10.0f,10.0f,z) -------->   (0,0)

           (10.0f,10.0f,z) -------->   (1,0)

           (10.0f,10.0f,z - 10.0f) -------->   (1,1)

           (-10.0f,10.0f,z - 10.0f) -------->   (0,1)

左边墙

 

 

 

 

 

            

           顶点坐标   ------->   纹理坐标           

           (-10.0f,-10.0f,z) -------->   (0,0)

           (-10.0f,-10.0f,z - 10.0f) -------->   (1,0)

           (-10.0f,10.0f,z - 10.0f) -------->   (1,1)

           (-10.0f,10.0f,z ) -------->   (0,1)

 

右墙壁

 

 

 

            顶点坐标   ------->   纹理坐标           

           (10.0f,-10.0f,z) -------->   (0,0)

           (10.0f,-10.0f,z - 10.0f) -------->   (1,0)

           (10.0f,10.0f,z - 10.0f) -------->   (1,1)

           (10.0f,10.0f,z ) -------->   (0,1)

 

基于linux环境的OpenGL环境搭建:

(23条消息) 配置OpenGL(Linux)_码上看世界的博客-CSDN博客_linux opengl

            

复制代码
#include <GLShaderManager.h>
/*
 `#include<GLShaderManager.h>` 移入了GLTool 着色器管理器(shader Mananger)类。没有着色器,我们就不能在OpenGL(核心框架)进行着色。着色器管理器不仅允许我们创建并管理着色器,还提供一组“存储着色器”,他们能够进行一些初步䄦基本的渲染操作。
 */

/*
 `#include<GLTools.h>`  GLTool.h头文件包含了大部分GLTool中类似C语言的独立函数
*/
#include "GLTools.h"    
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLGeometryTransform.h"
#include <math.h>
#include "StopWatch.h"


 
#include <GL/freeglut.h>


GLShaderManager shaderManager;// 着色器管理器
GLMatrixStack       modelViewMatix;// 模型视图矩阵
GLMatrixStack       projectionMatrix;// 投影矩阵
GLFrustum           viewFrustum;// 视景体 透视投影 - GLFrustum类
GLGeometryTransform transformPipeline;// 几何变换管道

//// 设置角色帧,作为相机
//GLFrame  cameraFrame;// 观察者位置
//GLTriangleBatch     torusBatch;

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


// 深度初始值,-65。
GLfloat viewZ = -65.0f;

// 纹理标识符号
#define TEXTURE_BRICK   0 //墙面
#define TEXTURE_FLOOR   1 //地板
#define TEXTURE_CEILING 2 //纹理天花板

#define TEXTURE_COUNT   3 //纹理个数

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

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


// 右键菜单栏选项 不同过滤方式
void ProcessMenu(int value) {
    
    GLint iLoop;
    
    for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++) {
        
        /* 绑定纹理 glBindTexture
         参数1:GL_TEXTURE_2D
         参数2:需要绑定的纹理对象
         */
        glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
        
        /* 配置纹理参数 glTexParameteri
         参数1:纹理模式
         参数2:纹理参数
         参数3:特定纹理参数
         */
        switch(value) {
            case 0:
                // GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST(最邻近过滤)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
                break;
                
            case 1:
                // GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_LINEAR(线性过滤)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                break;
                
            case 2:
                // GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST_MIPMAP_NEAREST(选择最邻近的Mip层,并执行最邻近过滤)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
                break;
                
            case 3:
                // GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST_MIPMAP_LINEAR(在Mip层之间执行线性插补,并执行最邻近过滤)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
                break;
                
            case 4:
                // GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_NEAREST_MIPMAP_LINEAR(选择最邻近Mip层,并执行线性过滤)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
                break;
                
            case 5:
                // GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER(缩小过滤器),GL_LINEAR_MIPMAP_LINEAR(在Mip层之间执行线性插补,并执行线性过滤,又称为三线性过滤)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
                break;
                
            case 6:
                
                // 设置各向异性过滤
                GLfloat fLargest;
                // 获取各向异性过滤的最大数量
                glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
                // 设置纹理参数(各向异性采样)
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
                break;
                
            case 7:
                // 设置各向同性过滤,数量为1.0表示(各向同性采样)
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
                break;
                
        }
    }
    
    // 重绘
    glutPostRedisplay();
}

// 键盘上下左右 事件
void SpecialKeys(int key, int x, int  y) {
    
    if(key == GLUT_KEY_UP)
        //移动的是深度值,Z
        viewZ += 0.5f;
    
    if(key == GLUT_KEY_DOWN)
        viewZ -= 0.5f;
    
    // 更新窗口,即可回调到RenderScene函数里
    glutPostRedisplay();
}

// 初始化设置
void SetupRC() {
    
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);// 黑色
    shaderManager.InitializeStockShaders();
    
    
    GLbyte *pBytes;
    GLint iWidth, iHeight, iComponents;
    GLenum eFormat;
    
    // 生成纹理标记
    /* 分配纹理对象 glGenTextures
     参数1:纹理对象的数量
     参数2:纹理对象标识数组
     */
    glGenTextures(TEXTURE_COUNT, textures);
    
    
    // 设置纹理
    for (GLint i = 0; i < TEXTURE_COUNT; i++) {
        
        // 绑定纹理对象
        /*绑定纹理对象 glBindTexture
         参数1:纹理模式,GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D
         参数2:需要绑定的纹理对象id
         */
        glBindTexture(GL_TEXTURE_2D, textures[i]);
        
        
        // 加载 读取 tga 文件数据
        /* 加载 tga 文件
         参数1:纹理文件名称
         参数2:文件宽度变量地址
         参数3:文件高度变量地址
         参数4:文件组件变量地址
         参数5:文件格式变量地址
         
         返回值:pBytes,指向图像数据的指针
         */
        pBytes = gltReadTGABits(textureFiles[i], &iWidth, &iHeight, &iComponents, &eFormat);
        
        
        // 设置纹理参数
        // 设置放大缩小 过滤方式 GL_TEXTURE_MAG_FILTER(放大过滤器,GL_NEAREST(最邻近过滤);GL_TEXTURE_MIN_FILTER(缩小过滤器,GL_NEAREST(最邻近过滤)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        
        // 设置环绕方式
        // GL_TEXTURE_WRAP_S(2D:s、t轴环绕),GL_CLAMP_TO_EDGE --> 环绕模式强制对范围之外的纹理坐标沿着合法的纹理单元的最后一行或一列进行采样
        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
         参数1:纹理维度,GL_TEXTURE_2D
         参数2:mip贴图层次
         参数3:纹理单元存储的颜色成分(从读取像素图中获得)
         参数4:加载纹理宽度
         参数5:加载纹理的高度
         参数6:为纹理贴图指定一个边界宽度 0
         参数7、8:像素数据的数据类型, GL_UNSIGNED_BYTE无符号整型
         参数9:指向纹理图像数据的指针
         */
        glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
        //        glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
        
        
        //  生成纹理对象 glGenerateMipmap
        /* 为纹理对象生成一组完整的 mipmap
         参数1:纹理维度,GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_2D
         */
        glGenerateMipmap(GL_TEXTURE_2D);
        
        // 释放原始纹理数据,不再需要纹理原始数据了
        free(pBytes);
    }
    
    
    // 设置隧道的上下左右4个面
    GLfloat z;// 深度,隧道的深度
    
    // 地板 -- 图 ‘地板’
    /*
     GLTools库中的容器类,GBatch -->  void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0);
     参数1:图元枚举值
     参数2:顶点数
     参数3:纹理数 --> 1组或者2组纹理坐标
     */
    floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for(z = 60.0f; z >= 0.0f; z -=10.0f) {
        
        // 纹理坐标与顶点的对应
        floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);// 纹理坐标   (参数1:默认为0,x,y)       四个点形成一个纹理范围(x,y)
        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();
}

// 渲染
void RenderScene(void) {
    
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 压栈
    modelViewMatix.PushMatrix();
    // z轴上平移
    modelViewMatix.Translate(0.0f, 0.0f, viewZ);
    
    // 纹理替换矩阵着色器
    /*
     参数1:GLT_SHADER_TEXTURE_REPLACE(着色器标签)
     参数2:模型视图投影矩阵
     参数3:纹理层
     */
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(),0);
    
    // 绑定纹理
    /*
     --> 为何又绑定一次???
     --> 为防止纹理 ID 绑定错误,状态机机制,在共同开发过程中,可能出现绑定的纹理出现变化
     */
    // 地板
    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();
    
    // 出栈
    modelViewMatix.PopMatrix();
    
    // 交换缓冲区
    glutSwapBuffers();
}

// 视口  窗口大小改变时接受新的宽度和高度,其中0,0代表窗口中视口的左下角坐标,w,h代表像素
void ChangeSize(int w,int h) {
    // 防止h变为0
    if(h == 0)
        h = 1;
    
    // 设置视口窗口尺寸
    glViewport(0, 0, w, h);
    
    // setPerspective 函数的参数是一个从顶点方向看去的视场角度(用角度值表示)
    // 设置透视模式,初始化其透视矩阵
    viewFrustum.SetPerspective(80.0f, GLfloat(w)/GLfloat(h), 1.0f, 120.0f);
    
    //4.把 透视矩阵 加载到 透视矩阵对阵中
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    //5.初始化渲染管线
    transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
}

// 关闭渲染环境
void ShutdownRC(void) {
    // 删除纹理
    glDeleteTextures(TEXTURE_COUNT, textures);
}

int main(int argc,char* argv[]) {
    
    //设置当前工作目录,针对MAC OS X
    
    gltSetWorkingDirectory(argv[0]);
    
    //初始化GLUT库
    
    glutInit(&argc, argv);
    /* 初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
     双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区
     */
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
    
    //GLUT窗口大小,标题窗口
    glutInitWindowSize(800,600);
    glutCreateWindow("Tunnel - 隧道");
    
    //注册回调函数
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    
    
    glutSpecialFunc(SpecialKeys);// 注册键盘特殊键位(上下左右键) 处理点击事件
    
    // 创建右键 Menu
    // 添加菜单入口,改变过滤器
    glutCreateMenu(ProcessMenu);
    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);
    
    
    
    //驱动程序的初始化中没有出现任何问题。
    GLenum err = glewInit();
    if(GLEW_OK != err) {
        
        fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
        return 1;
    }
    
    //调用SetupRC
    SetupRC();
    
    glutMainLoop();
    
    // 启动循环,关闭纹理
    ShutdownRC();
    
    return 0;
}
复制代码

 

        隧道代码:https://gitee.com/wang-guoqiang-xy/openGL-tunnel.git 

 

 

球体转动-纹理:

           渲染顺序:1.地面下物体  2.地面   3.地面上物体 

 

复制代码
#include <GLShaderManager.h>
/*
 `#include<GLShaderManager.h>` 移入了GLTool 着色器管理器(shader Mananger)类。没有着色器,我们就不能在OpenGL(核心框架)进行着色。着色器管理器不仅允许我们创建并管理着色器,还提供一组“存储着色器”,他们能够进行一些初步䄦基本的渲染操作。
 */

/*
 `#include<GLTools.h>`  GLTool.h头文件包含了大部分GLTool中类似C语言的独立函数
*/
#include "GLTools.h"    
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLGeometryTransform.h"
#include <math.h>
#include "StopWatch.h"


 
#include <GL/freeglut.h>


///
/*
 整体绘制思路:
 1、绘制地板
 2、绘制大球
 3、绘制随机的50个小球
 4、绘制围绕大球旋转的小球
 5、添加键位控制移动 -- 压栈观察者矩阵
 */

GLShaderManager     shaderManager;
// 两个矩阵
GLMatrixStack       modelViewMatix;// 模型视图矩阵
GLMatrixStack       projectionMatrix;// 投影矩阵
GLFrustum           viewFrustum;// 透视投影 - GLFrustum类
GLGeometryTransform transformPipeline;// 几何图形变换管道

GLBatch             floorTriangleBatch;// 地板
GLTriangleBatch     bigSphereBatch;// 大球体
GLTriangleBatch     sphereBatch;// 小球体

// 设置角色帧,作为相机
GLFrame  cameraFrame;// 观察者位置


// 小球门
//GLFrame sphere;
#define SPHERE_NUM  50
GLFrame spheres[SPHERE_NUM];// 50个小球


// 纹理 3个
GLuint textures[3];


// 绘制球体视图
void drawSpheres (GLfloat yRot) {
    
    // 设置点光源位置
    static GLfloat vLightPos[] = {0.0f, 3.0f, 0.0f, 1.0f};
    // 漫反射颜色 白色
    static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };
    
    
    // 绘制 小球们
    // 绑定纹理
    glBindTexture(GL_TEXTURE_2D, textures[2]);// 小球上贴的纹理
    for (int i = 0; i < SPHERE_NUM; i++) {
        
        modelViewMatix.PushMatrix();
        modelViewMatix.MultMatrix(spheres[i]);// 小球位置
        modelViewMatix.Rotate(yRot, 0, 1, 0);
        // GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF:纹理点光源着色器;vLightPos:光源位置;vBigSphereColor:绘制颜色
        shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                     modelViewMatix.GetMatrix(),
                                     transformPipeline.GetProjectionMatrix(),
                                     vLightPos,
                                     vWhite,
                                     0);
        sphereBatch.Draw();
        
        modelViewMatix.PopMatrix();
    }
    
    
    // 绘制大球
    modelViewMatix.Translate(0, 0.2f, -2.5f);// y轴上靠近镜面一点 Z轴距离再远一些
    //
    modelViewMatix.PushMatrix();
    // 大球沿Y轴  旋转弧度:yRot 自传
    modelViewMatix.Rotate(yRot, 0, 1, 0);
    // 绑定纹理
    glBindTexture(GL_TEXTURE_2D, textures[1]);
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                 modelViewMatix.GetMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightPos,
                                 vWhite,
                                 0);
    bigSphereBatch.Draw();
    modelViewMatix.PopMatrix();
    
    
    // 绘制沿大球转的小球
    modelViewMatix.PushMatrix();
    modelViewMatix.Rotate(yRot * -2, 0, 1, 0);
    modelViewMatix.Translate(0.8f, 0.0f, 0.0f);// 小球在X方向上偏移一定位置 不然会看不见小球
    glBindTexture(GL_TEXTURE_2D, textures[2]);
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                 modelViewMatix.GetMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightPos,
                                 vWhite,
                                 0);
    sphereBatch.Draw();
    modelViewMatix.PopMatrix();
    
}

// 设置纹理
bool LoadTGATexture(const char *textureName, GLenum minFilter, GLenum magFilter, GLenum wrapModel) {
    
    GLbyte *pBits;
    int nWidth, nHeight, nComponents;
    GLenum eFormat;
    
    // 读取纹理
    pBits = gltReadTGABits(textureName, &nWidth, &nHeight, &nComponents, &eFormat);
    if (!pBits) {
        return false;
    }
    
    //  设置过滤方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
    
    // 设置环绕方式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapModel);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapModel);
    
    // 载入纹理
    glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB, nWidth, nHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBits);
    
    //  使用完毕释放pbit
    free(pBits);
    
    
    // 只有minFilter 等于以下四种模式,才可以生成Mip贴图
    // GL_NEAREST_MIPMAP_NEAREST具有非常好的性能,并且闪烁现象非常弱
    // GL_LINEAR_MIPMAP_NEAREST常常用于对游戏进行加速,它使用了高质量的线性过滤器
    // GL_LINEAR_MIPMAP_LINEAR 和GL_NEAREST_MIPMAP_LINEAR 过滤器在Mip层之间执行了一些额外的插值,以消除他们之间的过滤痕迹。
    // GL_LINEAR_MIPMAP_LINEAR 三线性Mip贴图。纹理过滤的黄金准则,具有最高的精度。
    if (minFilter == GL_LINEAR_MIPMAP_LINEAR ||
        minFilter == GL_LINEAR_MIPMAP_NEAREST ||
        minFilter == GL_NEAREST_MIPMAP_LINEAR ||
        minFilter == GL_NEAREST_MIPMAP_NEAREST) {
        
        // 加载mip 纹理生成所有的mip 层
        // 参数:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    
    return true;
}

// 初始化 设置
void SetupRC() {
    
    // 设置清屏颜色到颜色缓存区
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    
    // 初始化着色器管理器
    shaderManager.InitializeStockShaders();
    
    // 开启深度测试 背面剔除
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    // 设置大球
    gltMakeSphere(bigSphereBatch, 0.4f, 40, 80);
    
    // 设置小球
    gltMakeSphere(sphereBatch, 0.1f, 26, 13);
    
    // 地板 纹理 --> 4个顶点对应纹理图的4个坐标
    GLfloat texSize = 10.0f;
    floorTriangleBatch.Begin(GL_TRIANGLE_FAN, 4,1);
    floorTriangleBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    floorTriangleBatch.Vertex3f(-20.f, -0.41f, 20.0f);
    
    floorTriangleBatch.MultiTexCoord2f(0, texSize, 0.0f);
    floorTriangleBatch.Vertex3f(20.0f, -0.41f, 20.f);
    
    floorTriangleBatch.MultiTexCoord2f(0, texSize, texSize);
    floorTriangleBatch.Vertex3f(20.0f, -0.41f, -20.0f);
    
    floorTriangleBatch.MultiTexCoord2f(0, 0.0f, texSize);
    floorTriangleBatch.Vertex3f(-20.0f, -0.41f, -20.0f);
    floorTriangleBatch.End();
    
    
    // 小球们的位置 随机小球顶点坐标数据
    for (int i = 0; i < SPHERE_NUM; i++) {
        
        // y轴不变,X,Z产生随机值
        GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
        GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
        
        // 在y方向,将球体设置为0.0的位置,这使得它们看起来是飘浮在眼睛的高度
        // 对spheres数组中的每一个顶点,设置顶点数据
        spheres[i].SetOrigin(x, 0.0f, z);
    }
    
    
    // 设置纹理
    // 生成纹理标记
    glGenTextures(3, textures);
    
    // 绑定纹理 设置纹理参数
    glBindTexture(GL_TEXTURE_2D, textures[0]);
    LoadTGATexture("marble.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);
    
    // GL_CLAMP_TO_EDGE 纹理坐标约束在0~1,超出部分边缘重复(边缘拉伸效果)
    glBindTexture(GL_TEXTURE_2D, textures[1]);
    LoadTGATexture("marslike.tga", GL_LINEAR_MIPMAP_LINEAR,
                   GL_LINEAR, GL_CLAMP_TO_EDGE);
    
    glBindTexture(GL_TEXTURE_2D, textures[2]);
    LoadTGATexture("moonlike.tga", GL_LINEAR_MIPMAP_LINEAR,
                   GL_LINEAR, GL_CLAMP_TO_EDGE);
}



// 渲染
void RenderScene(void) {
    
    // 清除窗口 颜色、深度缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    //    // 颜色们
    //    static GLfloat vFloorColor[] = {0.0, 0.5, 0.5, 1};// 地板颜色
    //    static GLfloat vBigSphereColor[] = {0.3, 0.5, 0.5, 1};// 大球颜色
    //    static GLfloat vSphereColor[] = {0.5, 0.5, 0.7, 1};// 小球颜色
    
    // 地板颜色 --> 镜面透明效果 alpha设置一定透明度
    static GLfloat vFloorColor[] = {1.0, 1.0, 0.0, 0.7f};
    
    // 定时器时间 动画 --> 大球自传
    static CStopWatch rotTimer;
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
    
    
    // 压栈 --> copy 一份栈顶矩阵 --> 单元矩阵
    modelViewMatix.PushMatrix();
    
    
    // 观察者矩阵压栈
    /*
     观察者的移动要影响到所有绘制物体,所以要 先压栈
     */
    M3DMatrix44f cameraM;
    cameraFrame.GetCameraMatrix(cameraM);
    modelViewMatix.MultMatrix(cameraM);
    
    
    // 镜面内部分
    // 压栈 --> 原因:镜面部分绘制后要继续绘制地板上面的视图
    modelViewMatix.PushMatrix();
    // 镜面内的小球门
    // 绘制镜面内部分(镜面内的小球门)
    
    // 沿Y轴翻转
    modelViewMatix.Scale(1.0f, -1.0f, 1.0f);
    // 视图距离地板面设定一定间隔 -- 避免粘在一起 就不像镜面了
    modelViewMatix.Translate(0, 0.8, 0);
    
    // 此时绘制镜面部分为顺时针旋转,将顺时针旋转设为正面 --> 正背面 观察者只能看到正面
    glFrontFace(GL_CW);
    // 绘制视图
    drawSpheres(yRot);
    
    // 恢复逆时针转为正面
    glFrontFace(GL_CCW);
    //
    modelViewMatix.PopMatrix();
    
    
    // 绘制镜面
    // 开启混合
    glEnable(GL_BLEND);
    // 指定混合方程式
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    //  绑定地面(镜面)纹理
    glBindTexture(GL_TEXTURE_2D, textures[0]);
    /* 纹理调整着色器 --> 将一个基本色乘以一个取自纹理的单元nTextureUnit的纹理
     参数1:GLT_SHADER_TEXTURE_MODULATE
     参数2:模型视图投影矩阵
     参数3:颜色
     参数4:纹理单元(第0层的纹理单元)
     */
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE,
                                 transformPipeline.GetModelViewProjectionMatrix(),
                                 vFloorColor,
                                 0);
    floorTriangleBatch.Draw();
    // 取消混合
    glDisable(GL_BLEND);
    
    
    // 绘制镜面外的球
    drawSpheres(yRot);
    
    modelViewMatix.PopMatrix();
    
    
    //
    glutSwapBuffers();
    
    //
    glutPostRedisplay();
}

// 视口  窗口大小改变时接受新的宽度和高度,其中0,0代表窗口中视口的左下角坐标,w,h代表像素
void ChangeSize(int w,int h) {
    // 防止h变为0
    if(h == 0)
        h = 1;
    
    // 设置视口窗口尺寸
    glViewport(0, 0, w, h);
    
    // setPerspective 函数的参数是一个从顶点方向看去的视场角度(用角度值表示)
    // 设置透视模式,初始化其透视矩阵
    viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 100.0f);
    
    //4.把 透视矩阵 加载到 透视矩阵对阵中
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    //5.初始化渲染管线
    transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
}



// 移动
void SpecialKeys(int key, int x, int y) {
    
    float linear = 0.1f;// 步长
    float angle = float(m3dDegToRad(5.0f));// 旋转度数
    if (key == GLUT_KEY_UP) {// 平移
        cameraFrame.MoveForward(linear);
    }
    if (key == GLUT_KEY_DOWN) {
        cameraFrame.MoveForward(-linear);
    }
    if (key == GLUT_KEY_LEFT) {// 旋转
        cameraFrame.RotateWorld(angle, 0, 1.f, 0);
    }
    if (key == GLUT_KEY_RIGHT) {
        cameraFrame.RotateWorld(-angle, 0, 1.f, 0);
    }
    
    
    //  这里为何不需要 glutPostRedisplay(); 重新渲染 --> rendersence里的定时器会定时进行渲染,所以这里就没有必要了
    
}

//删除纹理
void ShutdownRC(void)
{
    glDeleteTextures(3, textures);
}

int main(int argc,char* argv[]) {
    
    //设置当前工作目录,针对MAC OS X
    
    gltSetWorkingDirectory(argv[0]);
    
    //初始化GLUT库
    
    glutInit(&argc, argv);
    /* 初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
     双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区
     */
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    
    //GLUT窗口大小,标题窗口
    glutInitWindowSize(800,600);
    glutCreateWindow("纹理球体转动");
    
    //注册回调函数
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    // 特殊键位控制移动
    glutSpecialFunc(SpecialKeys);
    
    
    //驱动程序的初始化中没有出现任何问题。
    GLenum err = glewInit();
    if(GLEW_OK != err) {
        
        fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
        return 1;
    }
    
    //调用SetupRC
    SetupRC();
    
    glutMainLoop();
    
    ShutdownRC();
    
    return 0;
}
复制代码

 

 

          运动小球代码:https://gitee.com/wang-guoqiang-xy/motion-ball---render.git

 

posted @   求途  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示