OpenGL代码学习(13)--球体、花托、圆柱、圆锥、圆盘

注意:需要在配置好OpenGL的编程环境中运行下列代码,环境配置文章可参考:

OpenGL在Mac项目上的配置

下面的代码,直接放置在main.cpp文件中即可:

#include "GLTools.h"
#include "GLMatrixStack.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLGeometryTransform.h"
#include "math.h"
#include <GLUT/GLUT.h>

GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrame cameraFrame;
GLFrame objectFrame;
GLFrustum viewFrustum;

GLTriangleBatch sphereBatch;
GLTriangleBatch torusBatch;
GLTriangleBatch cylinderBatch;
GLTriangleBatch coneBatch;
GLTriangleBatch diskBatch;

GLGeometryTransform transformPipeline;

GLfloat vGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
GLfloat vBlack[] = {0.0f, 0.0f, 0.0f, 1.0f};

int nStep = 0;

// 程序初始化环境
void SetupRC() {
    // 设置背景为灰色背景
    glClearColor(0.7f, 0.7f, 0.7f, 1.0f);
    
    // 初始化着色器
    shaderManager.InitializeStockShaders();
    
    // 开启深度测试
    glEnable(GL_DEPTH_TEST);
    
    // 设置变化管线,管理模型视图堆栈和投影堆栈
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    
    // 照相机位置往后移动15
    cameraFrame.MoveForward(-15.0f);
    
    // 初始化球体的三角形批次,后面参数依次是,球半径、片段数、堆叠数
    gltMakeSphere(sphereBatch, 3.0f, 10, 20);
    
    // 初始化花托的三角形批次,后面参数依次是,外半径、内半径、片段数、堆叠数
    gltMakeTorus(torusBatch, 3.0f, 0.75f, 150, 15);
    
    // 初始化圆柱的三角形批次,后面参数依次是,底部半径、顶部半径、高度、片段数、堆叠数
    gltMakeCylinder(cylinderBatch, 2.0f, 2.0f, 3.0f, 13, 2);
    
    // 初始化圆锥的三角形批次,后面参数依次是,底部半径、顶部半径、高度、片段数、堆叠数
    gltMakeCylinder(coneBatch, 2.0f, 0.0f, 3.0f, 13, 2);
    
    // 初始化圆盘的三角形批次,后面参数依次是,内半径、外半径、片段数、堆叠书
    gltMakeDisk(diskBatch, 1.5f, 3.0f, 13, 3);
}

// 画三角形批次共用方法
void DrawWireFramedBatch(GLTriangleBatch *pBatch) {
    // 画物体表面 画绿色
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
    pBatch->Draw();
    
    // 设置多边形偏移
    glPolygonOffset(-1.0f, -1.0f);
    
    // 开启线段的抗锯齿
    glEnable(GL_LINE_SMOOTH);
    
    // 开启混合颜色模式
    glEnable(GL_BLEND);
    
    // 设置颜色混合方程式
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    // 设置多边形模式为线段
    glEnable(GL_POLYGON_OFFSET_LINE);
    
    // 设置多边形模式为前后面的线段
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    
    // 设置线宽
    glLineWidth(2.5f);
    
    // 画物体线段 黑色
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
    pBatch->Draw();
    
    // 以下为还原渲染环境,养成还原环境的好习惯
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glDisable(GL_POLYGON_OFFSET_LINE);
    glLineWidth(1.0f);
    glDisable(GL_BLEND);
    glDisable(GL_LINE_SMOOTH);
}

// 窗口渲染调用
void RenderScene(void) {
    // 清除缓存区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    // 模型堆栈压栈,顶部是单位矩阵
    modelViewMatrix.PushMatrix();
    
    // 获取照相机位置矩阵
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    
    // 单位矩阵 x 照相机位置矩阵 = 照相机位置矩阵
    modelViewMatrix.MultMatrix(mCamera);
    
    // 获取物体位置矩阵
    M3DMatrix44f mObjectFrame;
    objectFrame.GetMatrix(mObjectFrame);
    
    // 照相机位置矩阵 x 物体位置矩阵 = 物体在相机下的位置矩阵
    modelViewMatrix.MultMatrix(objectFrame);
    
    // 设置着色器为黑色
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
    
    // 根据不同状态,画不同的对象
    switch (nStep) {
        case 0:
            DrawWireFramedBatch(&sphereBatch);
            break;
        case 1:
            DrawWireFramedBatch(&torusBatch);
            break;
        case 2:
            DrawWireFramedBatch(&cylinderBatch);
            break;
        case 3:
            DrawWireFramedBatch(&coneBatch);
            break;
        case 4:
            DrawWireFramedBatch(&diskBatch);
            break;
    }
    
    // 出栈,还原栈顶为单位矩阵
    modelViewMatrix.PopMatrix();
    
    // 双缓冲区模式,后台缓冲区切换到前台进行显示
    glutSwapBuffers();
}

// 特殊按键点击响应
void SpecialKeys(int key, int x, int y) {
    // 按上下左右方向键,对物体进行旋转,m3dDegToRad用来角度转弧度
    switch (key) {
        case GLUT_KEY_UP:
            // angle=-5, x=1, y=0, z=0 表示绕x轴正方向顺时针旋转(从x轴正方向看去)
            objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
            break;
        case GLUT_KEY_DOWN:
            // angle=5, x=1, y=0, z=0 表示绕x轴正方向逆时针旋转(从x轴正方向看去)
            objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
            break;
        case GLUT_KEY_LEFT:
            // angle=-5, x=0, y=1, z=0 表示绕y轴正方向顺时针旋转(从y轴正方向看去)
            objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
            break;
        case GLUT_KEY_RIGHT:
            // angle=5, x=0, y=1, z=0 表示绕y轴正方向逆时针旋转(从y轴正方向看去)
            objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
            break;
    }
    // 触发渲染
    glutPostRedisplay();
}

// 普通按键点击响应
void KeyPresssFunc(unsigned char key, int x, int y) {
    // key = 32 是空格键,5次空格键一次循环
    if (key == 32) {
        nStep++;
        if (nStep > 4) {
            nStep = 0;
        }
    }
    // 切换窗口标题
    switch (nStep) {
        case 0:
            glutSetWindowTitle("Sphere");
            break;
        case 1:
            glutSetWindowTitle("Torus");
            break;
        case 2:
            glutSetWindowTitle("Cylinder");
            break;
        case 3:
            glutSetWindowTitle("Cone");
            break;
        case 4:
            glutSetWindowTitle("Disk");
            break;
    }
    // 触发渲染
    glutPostRedisplay();
}

// 窗口变化回调
void ChangeSize(int w, int h) {
    // 设置视口
    glViewport(0, 0, w, h);
    // 防止除数为0导致错误
    if (h <= 0) {
        h = 1;
    }
    // 设置投影矩阵,参数分别为:投影视角、宽高比、近点距离、远点距离
    viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
    
    // 投影矩阵堆栈顶部载入当前设置的投影矩阵
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    // 模型矩阵堆栈载入单位矩阵
    modelViewMatrix.LoadIdentity();
}

// 程序入口
int main(int argc, char *argv[]) {
    // 针对Mac OS 设置当前工作目录路径
    gltSetWorkingDirectory(argv[0]);
    
    // 初始化GLUT
    glutInit(&argc, argv);
    
    // 设置渲染模式,双缓冲、颜色、深度测试、模式
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
     
    // 初始化窗口大小
    glutInitWindowSize(800, 720);
    
    // 创建窗口并命名
    glutCreateWindow("Sphere");
    
    // 驱动程序初始化是否成功
    GLenum err = glewInit();
    if (err != GLEW_OK) {
        fprintf(stderr, "GLEW Erroe:%s\n", glewGetErrorString(err));
        return 1;
    }
    
    // 窗口大小变化回调函数设置
    glutReshapeFunc(ChangeSize);
    
    // 普通键盘按钮点击监听回调函数设置
    glutKeyboardFunc(KeyPresssFunc);
    
    // 特殊键盘按钮点击监听回调函数设置
    glutSpecialFunc(SpecialKeys);
    
    // 窗口渲染回调函数设置
    glutDisplayFunc(RenderScene);
    
    // 程序初始化环境
    SetupRC();
    
    // 主消息循环
    glutMainLoop();
    
    return 0;
}

效果图如下:

OpenGL代码学习(13)--球体、花托、圆柱、圆锥、圆盘

 

 OpenGL代码学习(13)--球体、花托、圆柱、圆锥、圆盘

 

 OpenGL代码学习(13)--球体、花托、圆柱、圆锥、圆盘

 

 OpenGL代码学习(13)--球体、花托、圆柱、圆锥、圆盘

 

 OpenGL代码学习(13)--球体、花托、圆柱、圆锥、圆盘

 

上一篇:2017ACM暑期多校联合训练 - Team 1 1011 HDU 6043 KazaQ's Socks (找规律)


下一篇:OpenGL代码学习(10)--颜色混合