-
我们首先来看一下效果,大红球自转,小蓝球围绕着大红球转
QQ20200718-171301-HD.gif
- 首先我们要定义一些需要用到的全局属性:
GLShaderManager shaderManager; //着色器管理器
GLMatrixStack modelViewMatrix; //模型视图矩阵
GLMatrixStack projectionMatrix; //投影矩阵
GLFrustum viewFrustum; //视景体
GLGeometryTransform transformPipeline; //几何图形变换管道
GLTriangleBatch torusBatch; //打球
GLTriangleBatch sphereBatch; //小球
GLBatch floorBatch; //地板
//角色帧 照相机角色帧
GLFrame cameraFrame;
//添加附加随机球数量
#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];
-
main
函数是程序的入口出:
int main(int argc, char* argv[]) {
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 800);
glutCreateWindow("OpenGL SphereWorld");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpeacialKeys);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
return 0;
}
- 在
SetupRC()
函数中初始化一些数据
void SetupRC() {
//1.初始化
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
shaderManager.InitializeStockShaders();
//2.开启深度测试
glEnable(GL_DEPTH_TEST);
//3.设置地板顶点数据
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();
//4.设置大球模型
gltMakeSphere(torusBatch, 0.4f, 40, 80);
//5.设置小球模型
gltMakeSphere(sphereBatch, 0.2f, 30, 60);
//6.随机位置放置小球
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, 这使得他们看起来是飘浮在眼镜的高度
//对spheres数组中的每一个顶点,设置顶点数据
spheres[i].SetOrigin(x, 0.0f, z);
}
}
- 调用
ChangeSize
函数初始化屏幕大小和创建投影矩阵
//屏幕更改大小或已初始化
void ChangeSize(int nWidth, int nHeight) {
//1.设置视口
glViewport(0, 0, nWidth, nHeight);
//2.创建投影矩阵
viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.f);
//viewFrustum.GetProjectionMatrix() 获取viewFrustum投影矩阵
//将其加载到投影矩阵堆栈上
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//3.设置变换管道以使用两个矩阵堆栈(变换矩阵modelViewMatrix, 投影矩阵projectionMatrix)
//初始化GLGeometryTransform的实例transformPipeline,通过将它的内部指针设置为模型视图矩阵堆栈和投影矩阵堆栈实例,来完成初始化
//这个操作也可以在SetupRC函数中完成,但是在窗口大小改变时或者窗口创建时设置他们并没有坏处,而且这样可以一次性完成矩阵和管线的设置。
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
- 调用
RenderScene
函数进行绘制场景和球转动的动画效果
//进行调用以绘制场景
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);
//压栈 有push就有pop 要一一对应
modelViewMatrix.PushMatrix();
//3.5 加入观察者,平移10步
M3DMatrix44f mCamara;
cameraFrame.GetCameraMatrix(mCamara);
modelViewMatrix.PushMatrix(mCamara);
//4.绘制地面
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vFloorColor);
floorBatch.Draw();
//5. 获取光源位置
M3DVector4f vLightPos = {0.0f, 10.0f, 5.0f, 1.0f};
//6.使得大球位置平移 3.0 向屏幕里面
modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
//7.压栈(复制栈顶)
modelViewMatrix.PushMatrix();
//8.大球自转
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
//9.指定合适的着色器(点光源着色器)
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor);
torusBatch.Draw();
//10.绘制完毕还要pop
modelViewMatrix.PopMatrix();
//11.画小球
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();
}
//12.让一个小蓝球围绕大球公转自转
modelViewMatrix.Rotate(yRot * -2.0f, 0.0, 1.0f, 0.0f);
modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLightPos, vSphereColor);
sphereBatch.Draw();
//有几个push就有几个pop
modelViewMatrix.PopMatrix();
modelViewMatrix.PopMatrix();
//12.执行缓冲区交换
glutSwapBuffers();
//重新绘制
glutPostRedisplay();
}
- 我们通过调用
SpeacialKeys
函数可以通过控制键盘的上下左右键来控制视图的方向和移动距离
void SpeacialKeys(int key, int x, int y) {
//移动步长
float linear = 0.1f;
//旋转度数
float angular = float(m3dDegToRad(5.0f));
if (key == GLUT_KEY_UP) {
//MoveForward 平移
cameraFrame.MoveForward(linear);
}
if (key == GLUT_KEY_DOWN) {
cameraFrame.MoveForward(-linear);
}
if (key == GLUT_KEY_LEFT) {
//RotateWorld旋转
cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
}
if (key == GLUT_KEY_RIGHT) {
cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
}
}
- 至此,我们就完成了这个动画的小案例,如果想看代码实现,请点击这里OpenGL_Ball_Demo
网友评论