11、OpenGL初探之基础演练-实现球的自转加公转

实现效果:

能随着观察者的不断移动,都能观察到小球的公转加自转

最终图片效果:

图1效果图
图2效果图

大体实现思路及步骤拆分:

1、先实现绿色方格地板部分

2、实现固定自转的红色大球和一个中型的蓝球,以及位置随机的50个小蓝球

3、实现中型蓝球绕红色大球的公转

4、实现移动观察者(camera)仍能观察红球自转及蓝球围绕红球公转

下面开始代码部分


一、先定义一些变量

GLShaderManager shaderManager; // 定义一个着色器管理器

GLMatrixStack modelViewMatrix; // 定义一个模型视图矩阵

GLMatrixStack projectionMatrix; // 定义一个投影矩阵

GLFrustum viewFrustum; // 视景体

GLGeometryTransform transformPipeline; // 几何图形变换管道

GLTriangleBatch    torusBatch;            //批次类  -大球

GLTriangleBatch    sphereBatch;            //批次类  -小球

GLBatch                floorBatch;          //简单的批次类  -地板

//角色帧 照相机角色帧

GLFrame  cameraFrame;

GLFrame  objectFrame;

//**4、添加附加随机球

#define NUM_SPHERES50

GLFrame spheres[NUM_SPHERES];

二、在主函数中初始化一些特殊键位操作以及设置窗口默认参数,注册变化函数

int  main (int  argc,  char* argv[])

{

//1、设置当前工作目录,针对MAC OS X    /*     `GLTools`函数`glSetWorkingDrectory`用来设置当前工作目录。实际上在Windows中是不必要的,因为工作目录默认就是与程序可执行执行程序相同的目录。但是在Mac OS X中,这个程序将当前工作文件夹改为应用程序捆绑包中的`/Resource`文件夹。`GLUT`的优先设定自动进行了这个中设置,但是这样中方法更加安全。     */

    gltSetWorkingDirectory(argv[0]);

//2.初始化一个GLUT库

    glutInit(&argc, argv);

/* 3、     初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指     双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区         

 --GLUT_DOUBLE`:双缓存窗口,是指绘图命令实际上是离屏缓存区执行的,然后迅速转换成窗口视图,这种方式,经常用来生成动画效果;     

--GLUT_DEPTH`:标志将一个深度缓存区分配为显示的一部分,因此我们能够执行深度测试;     

--GLUT_STENCIL`:确保我们也会有一个可用的模板缓存区。     深度、模板测试后面会细致讲到    

 */

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

//3、GLUT窗口大小、窗口标题

    glutInitWindowSize(800,600);

    glutCreateWindow("OpenGL SphereWorld");

/*4、      GLUT 内部运行一个本地消息循环,拦截适当的消息。然后调用我们不同时间注册的回调函数。我们一共注册2个回调函数: 

    1)为窗口改变大小而设置的一个回调函数   

    2)包含OpenGL 渲染的回调函数     */

    glutReshapeFunc(ChangeSize);//注册函数,在窗口改变大小的时候调用

    glutDisplayFunc(RenderScene);//注册渲染函数

    glutSpecialFunc(SpeacialKeys);//注册特殊函数

/* 5、     初始化一个GLEW库,确保OpenGL API对程序完全可用。     在试图做任何渲染之前,要检查确定驱动程序的初始化过程中没有任何问题     */

    GLenumerr =glewInit();

    if(GLEW_OK!= err) {

        fprintf(stderr,"GLEW Error: %s\n",glewGetErrorString(err));

        return1;

    }

//6、设置我们的渲染环境

   SetupRC();

 //7、这是一个无限执行的循环,它会负责一直处理窗口和操作系统的用户输入等操作。(注意:不会执行在glutMainLoop()之后的所有命令。)

    glutMainLoop(); 

    return 0;

}

三、开始设置我们的渲染环境

void    SetupRC()

{

    //1.设置清屏颜色(背景颜色)

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

  //2.初始化着色器

 //没有着色器,在OpenGL 核心框架中是无法进行任何渲染的。初始化一  个渲染管理器。目前我们使用固定管线渲染,后面会用OpenGL着色语言来写着色器

   shaderManager.InitializeStockShaders();

 //3.修改物体的初始坐标,往后移动5.0f的距离也就是z为-5,z轴垂直屏幕指向我们观察者为正,z为-5,就是往屏幕里面移动5

    objectFrame.MoveForward(5.0f);

    //4.开启深度测试,3D图像渲染需要开启深度测试

    glEnable(GL_DEPTH_TEST);

  //5.开始设置地板的顶点数据

   floorBatch.Begin(GL_LINES, 324);  

  for(GLfloat x = -20.0; x <= 20.0f; x+= 0.5) {       

      floorBatch.Vertex3f(x, -0.55f, 20.0f);       

      floorBatch.Vertex3f(x, -0.55f, -20.0f);                        

      floorBatch.Vertex3f(20.0f, -0.55f, x);       

      floorBatch.Vertex3f(-20.0f, -0.55f, x);  

  }    floorBatch.End();

  //6.设置大球模型

    gltMakeSphere(torusBatch, 0.4f, 40, 80);

 //7.设置小球模型

    gltMakeSphere(torusBatch, 0.1f, 26, 13);

//8、随机位置放置小球

   for (int i = 0; i < NUM_SPHERES; 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);   

 }

四、进行调用以绘制场景

void   RenderScene (void)

{

    //1.初始化颜色值(地板,大球,小球颜色)

    static   GLfloat  vFloorColor[] = {0.0f,1.0f,0.0f,1.0f};//地板颜色

    static  GLfloat   vTorusColor[] = {1.0f,0.0f,0.0f,1.0f};//初始化大球颜色

    static  GLfloat   vSphereColor[] = {0.0f,0.0f,1.0f,1.0f};//初始化小球颜色

    //2.基于时间动画

    static    CStopWatch    rotTimer;

    float yRot = rotTimer.GetElapsedSeconds() *60.0f;

    //3.清除颜色缓存区和深度缓冲区,防止残存的颜色和深度值影响渲染

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //4、加入objectFrame,用于特殊键位操作观察者位置移动

    modelViewMatrix.PushMatrix(objectFrame);

    //5.获取光源位置

    M3DVector4fvLightPos = {0.0f,10.0f,5.0f,1.0f};

    //6.绘制地面

    shaderManager.UseStockShader(GLT_SHADER_FLAT,

                                 transformPipeline.GetModelViewProjectionMatrix(),

                                 vFloorColor);

    floorBatch.Draw();

    //7.使得大球位置平移(3.0)向屏幕里面

    modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);

    //8.压栈(复制栈顶)

    modelViewMatrix.PushMatrix();

    //9.大球自转

    modelViewMatrix.Rotate(yRot,0.0f,1.0f,0.0f);

    //10.指定合适的着色器(点光源着色器)    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),

                                 transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor);

    torusBatch.Draw();

    //11.绘制完毕则出栈Pop

    modelViewMatrix.PopMatrix();

    //12.画小球

    for(inti =0; i< NUM_SPHERES; i++) {

        modelViewMatrix.PushMatrix();// 压栈,开始执行变换

        modelViewMatrix.MultMatrix(spheres[i]);

        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),

                                     transformPipeline.GetProjectionMatrix(), vLightPos, vSphereColor);

        sphereBatch.Draw();//批次类开启绘制

        modelViewMatrix.PopMatrix();//出栈

    }

    //13. 让一个小篮球围绕大球公众自转

    modelViewMatrix.Rotate(yRot * -2.0f,0.0f,1.0f,0.0f);//旋转矩阵

    modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);//平移

    shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vSphereColor);

    sphereBatch.Draw();

    modelViewMatrix.PopMatrix();//出栈

    //14.执行缓存区交换

    glutSwapBuffers();

    //15 发送重新渲染

    glutPostRedisplay();

}

五、屏幕大小更改或者已经初始化

void ChangeSize(int nWidth ,int nHeight)

{

    //1.设置视口或者视口大小更改后重新设置视口

    glViewport(0,0, nWidth, nHeight);

    //2.创建投影矩阵

    viewFrustum.SetPerspective(35.0f,float(nWidth)/float(nHeight),1.0f,100.0f);

    //viewFrustum.GetProjectionMatrix()  获取viewFrustum投影矩阵

    //并将其加载到投影矩阵堆栈上

    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

    //3.设置变换管道以使用两个矩阵堆栈(变换矩阵modelViewMatrix ,投影矩阵projectionMatrix)

    //初始化GLGeometryTransform 的实例transformPipeline.通过将它的内部指针设置为模型视图矩阵堆栈 和 投影矩阵堆栈实例,来完成初始化

    //当然这个操作也可以在SetupRC 函数中完成,但是在窗口大小改变时或者窗口创建时设置它们并没有坏处。而且这样可以一次性完成矩阵和管线的设置。

    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

}

六、特殊键位操作

void SpeacialKeys(int key,int x,int y){

    //设定移动步长

    float      linear =0.1f;

    //设定旋转度数

    float    angular =  float(m3dDegToRad(5.0f));//角度转弧度

    if(key ==GLUT_KEY_UP) {//键盘上的方向键  up键

        //MoveForward 平移

        objectFrame.MoveForward(linear);

    }

    if(key ==GLUT_KEY_DOWN) {//键盘上的方向键  down键

        objectFrame.MoveForward(linear);

    }

    if(key ==GLUT_KEY_LEFT) {//键盘上的方向键  left键

        //RotateWorld 旋转

        objectFrame.RotateWorld(angular,0,1,0);

    }

    if(key ==GLUT_KEY_RIGHT) {//键盘上的方向键  right键

        objectFrame.RotateWorld(angular,0,1,0);    }

}

七、最终效果视频地址优酷传送门:小球自转公转效果图


[溪浣双鲤的技术摸爬滚打之路](https://www.jianshu.com/p/3fbecd65faae)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342