开场白
本文主要介绍用OpenGL实现的效果:大球自转,小球围绕大球公转的效果。如图:
![](https://img.haomeiwen.com/i20196568/95805a058142652e.gif)
示例代码地址
本例中使用的是以调整观察者位置的方式进行移动的,也可以修改成调整物体的方式,代码中有相关代码,只是注释了。
主要代码
渲染方法:
void RenderScene(void) {
// 1
//地板颜色
static GLfloat vFloorColor[] = {0.0, 1.0, 0.0, 1.0};
//打球颜色
static GLfloat vTorusColor[] = {1, 0, 0, 1};
//小球颜色
static GLfloat vSphereColor[] = {0, 0, 1, 1};
//2
//此处需要使用静态变量 原因CStopWatch中有一个成员变量m_LastCount,需要记录,当调用GetElapsedSeconds时,内部实现是当前的秒数与m_LastCount中的秒数进行插值
static CStopWatch rotTimer;
//旋转度数
float yRot = rotTimer.GetElapsedSeconds() * 60;
//3
//清除一个或一组特定的缓冲区
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//4.观察者
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
//入栈-保存观察者位置
modelViewMatrix.PushMatrix(mCamera);
// modelViewMatrix.PushMatrix(objectFrame);
//5渲染地板
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vFloorColor);
floorBatch.Draw();
//光源
M3DVector4f vLightPos = {0.0f, 10.0f, 5.0f, 1.0f};
//6渲染大球
modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
modelViewMatrix.PushMatrix();
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor);
torusBatch.Draw();
modelViewMatrix.PopMatrix();
//7渲染50个(NUM_SPHERES)随机小球
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, vSphereColor);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
}
//8渲染一个小球绕着打球旋转
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);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLightPos, vSphereColor);
sphereBatch.Draw();
//出栈-与上面观察者的入栈 保持出入栈一致
modelViewMatrix.PopMatrix();
//将在后台缓冲区进行渲染,然后在结束时交换到前台
glutSwapBuffers();
//9触发重新绘制
glutPostRedisplay();
}
}
代码简要逻辑:
- 定义了地板、大球和小球的颜色
- 定义一个定时器变量rotTimer。这个地方一定要使用static静态方式,因为RenderScene在不停的调用,需要拿到上次的值。
- 清空缓冲区
- 定义观察者矩阵,并加入到modelView矩阵堆栈中
- 绘制地板
- 绘制大球,并自转
- 绘制50个随机小球
- 绘制绕大球公转的小球
- 触发重新绘制方法
modelViewMatrix栈变换流程
![](https://img.haomeiwen.com/i20196568/7e0fb2d011fa77e9.png)
这张图表达了整个代码中modeViewMatrix矩阵变化的过程:
- modelViewMatrix在初始化的时候会默认加入一个单元矩阵
- 加入观察者矩阵
- 准备渲染大球的时候,调用
modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
,此时会把栈顶元素取出进行矩阵乘法,然后替换栈顶元素。然后将栈顶元素再入栈一次,目的是保存之前的状态。因为栈顶元素会被后面的旋转操作修改。 - 旋转处理,与第三不类似,但是不用保存状态。
- 大球绘制后,出栈。此时栈顶是camero矩阵移动后的结果。
- 开始绘制随机50个小球,入栈出栈,与之前操作没什么区别
- 开始绘制公转小球
网友评论