美文网首页OpenGL初探
第十五节—综合代码

第十五节—综合代码

作者: L_Ares | 来源:发表于2020-09-01 00:05 被阅读0次

本文为L_Ares个人写作,包括图片皆为个人亲自操作,以任何形式转载请表明原文出处。

本节作为前几节知识的综合训练。只放代码,里面有非常详细的注释了,效果图如文章末尾"效果图"所示。

建议电脑配置不高的同学们不要把球的数据绘制的太多,数据可以随意减少的,2020款最新MacPro32+512G的电脑,跑时间长一点还是会发热的。


//
//  main.cpp
//  08综合
//
//  Created by EasonLi on 2020/8/30.
//  Copyright © 2020 EasonLi. All rights reserved.
//

#include <stdio.h>

#pragma mark - 引用类

//GLTools工具类。包含了绝大多数GLTool中类似C语言的函数
#include "GLTools.h"
//着色器管理器
#include "GLShaderManager.h"
//参考帧。表示世界坐标系中任意物体的位置与方向
#include "GLFrame.h"
//三角形批次类。容器类
#include "GLBatch.h"
//矩阵堆栈类
#include "GLMatrixStack.h"
//管道类。管理模型视图投影矩阵堆栈的
#include "GLGeometryTransform.h"
//矩阵投影工具类
#include "GLFrustum.h"
//一个计时器
#include "StopWatch.h"
//3d数学库
#include "math3d.h"

//宏定义根据不同的系统引入不同的GLUT
//Windows用静态的,MacOS用glut/glut.h
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

#pragma mark - 公共变量
//着色器管理器
GLShaderManager shaderManager;

//容器类
//地板线条的三角形批次类容器
GLBatch floorBatch;
//大球容器类
GLTriangleBatch bigSphereBatch;
//小球容器类
GLTriangleBatch smallSphereBatch;

//参考帧
//观察者参考帧
GLFrame cameraFrame;

//矩阵堆栈类
//模型视图矩阵堆栈
GLMatrixStack modelViewMatrixStack;
//投影视图矩阵堆栈
GLMatrixStack projectionMatrixStack;

//矩阵投影工具类
GLFrustum viewFrustum;

//矩阵堆栈管道
GLGeometryTransform transformPipeline;

//常规属性
//地板颜色
GLfloat vGreen[] = {0.f,1.f,0.f,1.f};
//大球颜色
GLfloat vRed[] = {1.f,0.f,0.f,1.f};
//小球颜色
GLfloat vBlue[] = {0.f,0.f,1.f,1.f};

//小球的数量
#define SMALL_SPHERE_NUM 50
//定义一个小球数组
GLFrame spheresNum[SMALL_SPHERE_NUM];

#pragma mark - 函数
//设置窗口尺寸等关联信息
void ChangeSize(int w,int h)
{
    
    //设置视口
    glViewport(0, 0, w, h);
    
    //创建投影矩阵
    viewFrustum.SetPerspective(36.f, float(w)/float(h), 1.f, 500.f);
    
    //将投影矩阵加载到投影矩阵堆栈中
    projectionMatrixStack.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    //设置矩阵堆栈变换管道来管理矩阵堆栈
    //GLGeometryTransform的初始化:
    //通过将GLGeometryTransform对象的内部指针分别设置成modelViewMatrixStack和projectionMatrixStack来完成初始化。
    transformPipeline.SetMatrixStacks(modelViewMatrixStack, projectionMatrixStack);
    
}

//设置渲染环境
void SetUpRC()
{
    
    /**********************公共**********************/
    //设置清屏颜色,避免残留的屏幕颜色对渲染造成影响
    glClearColor(0.f, 0.f, 0.f, 1.f);
    
    //初始化着色器管理器
    shaderManager.InitializeStockShaders();
    
    //因为要用到立体图形了,需要立体的效果,所以开启深度测试
    glEnable(GL_DEPTH_TEST);
    /***********************************************/
    
    
    
    /********************设置地板********************/
    //设置地板的图元和顶点数量
    floorBatch.Begin(GL_LINES, 324);
    //利用for循环设置坐标
    //x坐标的范围随意去定,每次+0.5控制的是没两条平行线之间的距离
    //值越小,平行线密度越大
    for (GLfloat x = -20.f; x <= 20.f; x += 0.5f) {
        //设置纵向的线
        //因为我们要的是地板的效果,所以发生变化的是x和z,y是不变的,这才是一个地板
        //平面的效果
        floorBatch.Vertex3f(x, -0.5f, 20.f);
        floorBatch.Vertex3f(x, -0.5f, -20.f);
        
        //设置横向的线
        floorBatch.Vertex3f(20.f, -0.5f, x);
        floorBatch.Vertex3f(-20.f, -0.5f, x);
    }
    //完成地板批次类的设置
    floorBatch.End();
    /***********************************************/
    
    
    
    /********************设置大球*********************/
    //直接用系统给的就行
    gltMakeSphere(bigSphereBatch, 0.5f, 50, 100);
    /***********************************************/
    
    
    
    /********************设置小球*********************/
    //直接用系统给的就行
    gltMakeSphere(smallSphereBatch, 0.1f, 13, 26);
    //利用for循环随机放置小球位置
    for (int i = 0; i < SMALL_SPHERE_NUM; i++) {
        
        //因为还是同一平面的问题,从我们的角度来看,就是Y轴不变,那么X,Z轴随机坐标
        GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
        GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
        
        //对数组中的每一个顶点都设置顶点数据
        //Y就给0,看起来效果像是飘起来的
        spheresNum[i].SetOrigin(x, 0.f, z);
        
    }
    /***********************************************/
    
}

//渲染
void RenderScene()
{
    
    /**********************公共**********************/
    //清空缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    //定义一个矩阵用来存储观察者矩阵
    M3DMatrix44f mCamera;
    //获取观察者矩阵并且放入上面定义的观察者矩阵
    cameraFrame.GetCameraMatrix(mCamera);
    //把观察者矩阵压入模型视图矩阵堆栈,做好乘法,矩阵变换,放在栈顶
    modelViewMatrixStack.PushMatrix(mCamera);
    /***********************************************/
    
    
    
    /********************绘制地板********************/
    //使用着色器
    shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vGreen);
    //利用地板的三角形批次类绘制
    floorBatch.Draw();
    /***********************************************/
    
    
    
    /********************绘制大球********************/
    //定义一个静态的定时器,全局都要用。
    static CStopWatch timer;
    //设置每秒的旋转角度
    float yRot = timer.GetElapsedSeconds() * 60.f;
    //给定一个光源位置,因为光源是向量,所以如下定义
    M3DVector4f lightPos = {0.f,10.f,5.f,1.f};
    //给大球一个平移,这样保证大球不在原点位置,不然和观察者重叠了
    modelViewMatrixStack.Translate(0.f, 0.f, -3.f);
    /**现在模型视图矩阵堆栈里面从栈底到栈顶有如下几个矩阵:*/
    //观察者mv平移矩阵
    //压栈。因为后面要绘制其他的东西,大球就画自己的,画完就出栈,不要影响其他的绘制
    modelViewMatrixStack.PushMatrix();
    /**现在模型视图矩阵堆栈里面从栈底到栈顶有如下几个矩阵:*/
    //观察者mv平移矩阵-->观察者mv平移矩阵
    //设置大球自转
    modelViewMatrixStack.Rotate(yRot, 0.f, 1.f, 0.f);
    //设置成点光源着色器
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),lightPos,vRed);
    //利用大球的三角形批次类绘制
    bigSphereBatch.Draw();
    /**现在模型视图矩阵堆栈里面从栈底到栈顶有如下几个矩阵:*/
    //观察者mv平移矩阵
    modelViewMatrixStack.PopMatrix();
    /***********************************************/
    
    
    
    /********************绘制随机小球******************/
    //还是利用for循环把随机出来的小球绘制出来
    for (int i = 0; i < SMALL_SPHERE_NUM; i++) {
        //压栈完成后
        /**现在模型视图矩阵堆栈里面从栈底到栈顶有如下几个矩阵:*/
        //观察者mv平移矩阵-->观察者mv平移矩阵
        modelViewMatrixStack.PushMatrix();
        //直接给数组中的每一个小球参考帧矩阵都做矩阵变换
        /**完成后,现在模型视图矩阵堆栈里面从栈底到栈顶有如下几个矩阵:*/
        //观察者mv平移矩阵-->观察者mv平移和小球位置矩阵
        modelViewMatrixStack.MultMatrix(spheresNum[i]);
        //设置着色器
        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),lightPos,vBlue);
        //利用小球的三角形批次类绘制
        smallSphereBatch.Draw();
        //出栈
        /**完成后,现在模型视图矩阵堆栈里面从栈底到栈顶有如下几个矩阵:*/
        //观察者mv平移矩阵
        modelViewMatrixStack.PopMatrix();
        
    }
    /***********************************************/
    
    
    
    /********************绘制公转小球******************/
    //设置绕大球公转(其实就是绕着Y轴公转,因为大球中心线和Y轴是同平面中的平行关系)
    //现在的mv矩阵堆栈中只有观察者mv矩阵,旋转后就变成了观察者mv旋转矩阵
    modelViewMatrixStack.Rotate(yRot * 2.f, 0.f, 1.f, 0.f);
    //再把小球拉出来点,拉出的距离必须比大球大,不然就不是绕着大球公转了
    //平移后变成观察者mv旋转平移矩阵
    modelViewMatrixStack.Translate(1.f, 0.f, 0.f);
    //着色器设置
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),lightPos,vBlue);
    //小球三角形批次类绘制
    smallSphereBatch.Draw();
    /***********************************************/
    
    
    
    /**********************公共**********************/
    //出栈。回复到最初的原始堆栈
    modelViewMatrixStack.PopMatrix();
    //交换缓冲区
    glutSwapBuffers();
    glutPostRedisplay();
    /***********************************************/
    
    
}

//特殊键位
void SpecialKeys(int key,int x,int y)
{
    
    //设置前后是移动,左右是旋转
    //前后每次移动的步长
    float nStep = 0.1f;
    //左右每次旋转的角度
    float nRot = float(m3dDegToRad(5.f));
    
    //判断键位,这里用观察者视角来做变化,也可以用物体做变化
    //如果用物体的话,定义一个物体的参考帧objFrame,RenderScene中直接把objFrame
    //压栈到模型视图矩阵堆栈就行了,就不要把观察者矩阵加进去了,一样能实现效果
    switch (key) {
            
        case GLUT_KEY_UP:
            cameraFrame.MoveForward(nStep);
            break;
            
        case GLUT_KEY_DOWN:
            cameraFrame.MoveForward(-nStep);
            break;
        case GLUT_KEY_RIGHT:
            cameraFrame.RotateWorld(-nRot, 0.f, 1.f, 0.f);
            break;
        case GLUT_KEY_LEFT:
            cameraFrame.RotateWorld(nRot, 0.f, 1.f, 0.f);
            break;
            
    }
    //这里就不用发送重新渲染的信号了,因为RenderScene中有个定时器,已经在
    //RenderScene中一直的重新渲染了,加上也无所谓
    glutPostRedisplay();
    
}

#pragma mark - main
int main(int argc,char *argv[])
{
    
    //设置工作目录和项目目录都到/Resouce下面
    //GLUT优先级已经设置过,手动保证安全
    gltSetWorkingDirectory(argv[0]);
    
    //GLUT初始化
    glutInit(&argc, argv);
    
    //初始化显示模式
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    
    //设置窗口尺寸
    glutInitWindowSize(600, 600);
    
    //创建窗口并命名
    glutCreateWindow("综合");
    
    //注册相关函数
    //重塑函数
    glutReshapeFunc(ChangeSize);
    //渲染函数
    glutDisplayFunc(RenderScene);
    //特殊键位函数
    glutSpecialFunc(SpecialKeys);
    
    //初始化Glew库
    GLenum status = glewInit();
    if (status != GLEW_OK) {
        printf("glew init error : %s \n",glewGetErrorString(status));
        return 1;
    }
    
    //设置渲染环境
    SetUpRC();
    
    //构建本地循环
    glutMainLoop();
    
    return 0;
    
}


效果图如下,大球是自转的,就是看的不清楚,小球是围绕大球公转的,大球的自转后面加入纹理后可以看的很清楚。

效果图.png

相关文章

  • 第十五节—综合代码

    本文为L_Ares个人写作,包括图片皆为个人亲自操作,以任何形式转载请表明原文出处。 本节作为前几节知识的综合训练...

  • 第二十一节—纹理填充卫星图

    本文为L_Ares个人写作,包括图片皆为个人亲自操作,以任何形式转载请表明原文出处。 本节是对第十五节的卫星图代码...

  • 7.0 践行打卡 D5

    1.运动 kp运动 2.阅读 《墨菲定律》第十章 第五节:工作成瘾综合症~工作狂是一种心理疾病 曾经的“工作狂”意...

  • 《文心》读书笔记

    第十三节 触发 第十四节 书声 第十五节 读古书的小风波 第十六 现代的习字 1、读书贵有新得,作文贵有新味。最重...

  • 作文笔记(人物篇)

    少年得到《郝广才 · 作文有意思》第十五节与第十六节作文课笔记 点个赞再走呗

  • 精彩纷呈宋王朝(第三部,第十章,第十五节)

    第十章 浩气长存岳武穆 第十五节 说死因(下) 那么杀谁?够份量的将帅有张...

  • 第十五节

    大家都愣住了,从下面望上去,那人简直和画上的关二爷一样。听到喊话都乖乖地把袋子里的核桃倒在了地上。不知谁说了一句:...

  • 第十五节

    新定式 第一定式,用的最好。

  • 第十五节

    1、研究30岁左右的成功者,70多岁的成功者:前者注重工作平衡;后者注重一直工作,男主外女主内。但是,他们都经历过...

  • 第十五节

    感觉画着画着就想吐了。这头发,不好弄啊

网友评论

    本文标题:第十五节—综合代码

    本文链接:https://www.haomeiwen.com/subject/htrmsktx.html