OpenGL-综合案例:旋转的大小球

不停的演示正方形和三角形已经有点乏味了,这篇文章我们来一个综合案例,绘制公转自转的大小球

一些main函数的准备工作,这里就不多阐述了,不了解的可以看之前的文章

1.地板绘制

还是熟悉的ChangeSize函数开始:

  • 设置视口glviewport
  • 设置图形投影的方式:因为是立体图形,所以选择透视投影设置透视投影(3d效果)
1 //参数1:垂直方向上的视场角度
2 //参数2:视口纵横比 = w/h
3 //参数3:近裁剪面距离
4 //参数4:远裁剪面距离
5 viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 500.0f);
  • 通过设置的投影方式获得投影矩阵,并将其存入投影矩阵中
1 projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
  • 将模型视图矩阵和投影矩阵放到变换管道中(方便快速进行矩阵相乘)
1 transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

然后来到第二个部分,SetupRC初始化:

设置背景色->初始化着色器->开启深度测试->设置地板的顶点数据

接下来通过RenderScene绘制场景:

设置地板颜色->清理颜色缓冲区和深度缓冲区->绘制地板->交换缓冲区

1     // 绘制地板
2     shaderManager.UseStockShader(GLT_SHADER_FLAT,
3                                  transformPipeline.GetModelViewProjectionMatrix(),
4                                  vFloorColor);
5     floorBatch.Draw();

绘制地板这里我们采用最简单的平面着色器,然后通过我们之前设置的变换管道,获取模型视图投影矩阵(MVP)放入其中,并设置上地板颜色进行绘制,我们的地板就绘制成功了。

 

 

 

2.绘制大球

在地板绘制完成的基础上,我们开始绘制大球,并实现其自转功能

首先是SetupRC函数,初始化大球的顶点数据,这里我们用到gltMakeSphere函数,引用一个三角形批次、设置球半径和组成球体的片段及其堆叠数量,

我们可以将球体想象成围绕成球形的一系列三角形带:

 

1 // 参数iStacks是这些从球体底部堆叠到顶部的三角形的数量。
2 // 参数iSlices是围绕球体排列的三角形对数
3 void gltMakeSphere(GLTriangleBatch& sphereBatch, GLfloat fRadius, GLint iSlices, GLint iStacks);

 

大球的旋转上,首先设置一个定时器,通过这个定时器得到弧度,再通过大球的绘制配合旋转方法实现大球的自转。

1 static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
2 //设置点光源位置
3 M3DVector4f vLightPos = {0,10,10,1};
4 modelViewMatrix.Translate(0.0f, 0.2f, -3.0f);
5 modelViewMatrix.PushMatrix();
6 modelViewMatrix.Rotate(yRot, 0, 1, 0);
7 shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transform Pipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vTorusColor);
8 torusBatch.Draw();
9 modelViewMatrix.PopMatrix();
  • Translate:移动一段距离,便于观察
  • PushMatrix:拷贝矩阵堆栈栈顶并压栈
  • Rotate:大球围绕y轴旋转,实现自转

 

3.绘制小球

小球的绘制和大球步骤是一样的,首先SetupRC函数,初始化小球的顶点数据

 1 // 设置小球球模型
 2     gltMakeSphere(sphereBatch, 0.1f, 13, 26);
 3     // 随机位置放置小球
 4     for (int i = 0; i < NUM_SPHERES; i++) {
 5         
 6         //y轴不变,X,Z产生随机值
 7         GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
 8         GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
 9         
10         //在y方向,将球体设置为0.0的位置,这使得它们看起来是飘浮在眼睛的高度
11         //对spheres数组中的每一个顶点,设置顶点数据
12         spheres[i].SetOrigin(x, 0.0f, z);
13     }

然后RenderScene绘制:

 1 // 画小球
 2     for (int i = 0; i < NUM_SPHERES; i++) {
 3         modelViewMatrix.PushMatrix();
 4         modelViewMatrix.MultMatrix(spheres[i]);
 5         shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
 6                                      transformPipeline.GetProjectionMatrix(), vLightPos, vSphereColor);
 7         sphereBatch.Draw();
 8         modelViewMatrix.PopMatrix();
 9         
10     }

多个静态小球,每绘制一个小球都需要进行push和pop操作。

4.让小蓝球围着大红球转起来

1 // 让小蓝球围绕大球转起来
2     modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
3     modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
4     shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vSphereColor);
5     sphereBatch.Draw();

这个案例的重点和难点,就在RenderScene函数里面的矩阵堆栈的理解。

在OpenGL 的维度:

变换顶点向量 = M_pro * M_view * M_model * V_local

变换顶点向量 = 投影矩阵 ✖ 视图变换矩阵 ✖ 模型矩阵 ✖ 顶点

 

  • 使用PushMatrix方法,会将栈顶信息复制一份,放入栈顶。
  • 使用MultMatrix方法做矩阵相乘时,将该矩阵与栈顶矩阵相乘,覆盖栈顶矩阵。
  • 使用PopMatrix做出栈操作时,移除栈顶矩阵对象。(根据栈的特点,只能pop栈顶) 

 

后续的移动操作就是在增加特殊键位的移动即可

 

 1 void SpeacialKeys(int key,int x,int y){
 2     
 3     float linear = 0.1f;
 4     float angular = float(m3dDegToRad(5.0f));
 5     
 6     if (key == GLUT_KEY_UP) {
 7         cameraFrame.MoveForward(linear);
 8     }
 9     if (key == GLUT_KEY_DOWN) {
10         cameraFrame.MoveForward(-linear);
11     }
12     
13     if (key == GLUT_KEY_LEFT) {
14         cameraFrame.RotateWorld(angular, 0, 1, 0);
15     }
16     if (key == GLUT_KEY_RIGHT) {
17         cameraFrame.RotateWorld(-angular, 0, 1, 0);
18     }
19 
20 }

 

posted @ 2019-08-19 18:49  黑暗的咏叹  阅读(480)  评论(0编辑  收藏  举报