七、OpenGL综合应用:大球自转,小球公转,移动观察者

608 阅读2分钟

这是我们将要实现的效果

通过分析,需要通过以下步骤实现

  • 绘制绿色方格地板;
  • 绘制中心位置的红色大球,并实现其自转;
  • 绘制随机位置的50个静态小球和一个围绕红色大球公转的蓝色球;
  • 实现动态蓝色球绕红色大球的公转;
  • 实现移动观察者,观察红色大球自转及蓝色球公转的效果;

一、绘制地板

ChangeSize 设置视口和投影方式:设定投影投影矩阵并矩阵堆栈;

 glViewport(0, 0, w, h);
 // 创建投影矩阵(透视投影)
 viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 100.f);
 // 获取viewFrustum投影矩阵,并将其加载到投影矩阵堆栈上
 projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
 /* 设置变换管道以使用两个矩阵堆栈(变换矩阵modelViewMatrix ,投影矩阵projectionMatrix)
 * 初始化 GLGeometryTransform 的实例transformPipeline,通过将它的内部指针设置为模型视图矩阵堆栈和 投影矩阵堆栈实例,来完成初始化
 * 这个操作也可以在SetupRC函数中完成,在窗口大小改变时或者窗口创建时设置,可以一次性完成矩阵和管线的设置。
 */
 transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

SetupRC() :准备绘制地板的顶点数据;

 // 初始化
 glClearColor(0.f, 0.f, 0.f, 1.f);
 shaderManager.InitializeStockShaders();

 // 开启深度测试
 glEnable(GL_DEPTH_TEST);

 // 设置地板顶点数据,由324个矩阵组成
 floorBatch.Begin(GL_LINES, 324);
 for (GLfloat x = -20.f; x <= 20.f; x += 0.5f) {
    floorBatch.Vertex3f(x, -0.55f, 20.f);
    floorBatch.Vertex3f(x, -0.55f, -20.f);
    floorBatch.Vertex3f(20.f, -0.55f, x);
    floorBatch.Vertex3f(-20.f, -0.55f, x);
 }
 floorBatch.End();

RenderScence():绘制绿色地板

 // 清除颜色缓存区和深度缓冲区
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 // 地板的颜色
 static GLfloat vFloorColor[] = {0.f, 1.f, 0.f, 1.f};
 shaderManager.UseStockShader(GLT_SHADER_FLAT,
                             transformPipeline.GetModelViewProjectionMatrix(),
                             vFloorColor);
 floorBatch.Draw();

 // 执行缓存区交换
 glutSwapBuffers();

二、绘制红色大球

 // 清除颜色缓存区和深度缓冲区
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 //    // 地板的颜色
 //    static GLfloat vFloorColor[] = {0.f, 1.f, 0.f, 1.f};
  // 红色大球的颜色
 static GLfloat vTorusColor[] = {1.f, 0.f, 0.f, 1.f};

 // 动画定时器
 static CStopWatch rotTimer;
 float  yPot = rotTimer.GetElapsedSeconds() * 60.f;
 // 压栈
 modelViewMatrix.PushMatrix();

 //    // 绘制地板
 //    shaderManager.UseStockShader(GLT_SHADER_FLAT,
 //                                 transformPipeline.GetModelViewProjectionMatrix(),
 //                                 vFloorColor);
 //    floorBatch.Draw();

  // 获取光源位置
 M3DVector4f vLightPods = {0.f, 10.f, 5.f, 1.f};
 // 使得红色大球位置向屏幕里面平移(3.0)
 modelViewMatrix.Translate(0.f, 0.f, -3.f);
 // 压栈(复制栈顶)
 modelViewMatrix.PushMatrix();
 // 红色大球自转
 modelViewMatrix.Rotate(yPot, 0.f, 1.f, 0.f);
 // 指定着色器(点光源着色器)
 shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,
                             transformPipeline.GetModelViewMatrix(),
                             transformPipeline.GetProjectionMatrix(),
                             vLightPods,
                             vTorusColor);
 torusBatch.Draw();

 // 绘制完毕出栈Pop(PushMatrix与PopMatrix一一对应)
 modelViewMatrix.PopMatrix();
 modelViewMatrix.PopMatrix();

 // 执行缓存区交换
 glutSwapBuffers();

 glutPostRedisplay();

三、绘制绿色球

绘制50个随机球

   // 绘制随机位置的50个小球
for (int i = 0; i < NUM_SPHERES; i++) {
    modelViewMatrix.PushMatrix();
    modelViewMatrix.MultMatrix(spheres[i]);
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,
                                 transformPipeline.GetModelViewMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightPods,
                                 vSphereColor);
    sphereBatch.Draw();
    modelViewMatrix.PopMatrix();
}

绘制蓝色大球并围绕红色球公转

  //绘制静态小球
 for (int i = 0; i < NUM_SPHERES; i++) {
    modelViewMatrix.PushMatrix();
    modelViewMatrix.MultMatrix(spheres[i]);        
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSpereColor);
    sphereBatch.Draw();
    modelViewMatrix.PopMatrix();
 }

 // 矩阵堆栈记录旋转,平移操作
 modelViewMatrix.Rotate(yRot * -1.0f, 0, 1, 0);
 modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
 shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSpereColor);
 sphereBatch.Draw();

四、移动观察者

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

 float linear = 0.1f;
 float angular = 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(angular, 0, 1, 0);
 }
 if (key == GLUT_KEY_RIGHT) {
    cameraFrame.RotateWorld(-angular, 0, 1, 0);
 }

 }