首先我们看个gif动画

整体流程是main->ChangeSize->SetupRC->RenderScene
通用设置
- main函数:程序入口,调用设置窗口、初始化视图以及函数监听等
int main(int argc,char* argv[]) { //设置当前工作目录,针对MAC OS X gltSetWorkingDirectory(argv[0]); //初始化GLUT库 glutInit(&argc, argv); /*初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指 双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区*/ glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL); //GLUT窗口大小,标题窗口 glutInitWindowSize(800,600); 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 SetupRC(); glutMainLoop(); return 0; } - SetupRC函数:设置背景颜色(黑色)、初始化着色器、开启深度测试
glClearColor(0.0f,0.0f,0.0f,1.0f); //初始化着色管理器 shaderManager.InitializeStockShaders(); //开启深度测试 glEnable(GL_DEPTH_TEST); - ChangeSize函数:设置窗口大小、创建投影矩阵、加载矩阵到堆栈上、设置 变换管道
void ChangeSize(int w,int h) { //设置视口 glViewport(0,0, w, h); //创建投影矩阵 viewFrustum.SetPerspective(35.0f, (float)w/(float)h, 1.0f, 100.0f); //加载到投影矩阵堆栈上 projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); //设置变换管道 transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix); } - RenderScene函数:清空缓存背景色
//清除一个或一组特定的缓冲区 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
绘制地板
- SetupRC函数:负责准备地板的顶点数据
//设置地板数据 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(); - RenderScene函数:负责绘制地板
//绘制地板 shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor); floorBatch.Draw();
需要注意的是压栈和出栈要配对使用
绘制大球
- SetupRC函数:设置大球模型
//设置大球模型gltMakeSphere(torusBatch, 0.4f, 40, 80); - RenderScene函数:主要是绘制大图
//获取光源位置 M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f}; //大球向屏幕里面平移-5 modelViewMatrix.Translate(0.0f, 0.0f, -5.0f); //大球入栈 modelViewMatrix.PushMatrix(); //大球自传(围绕y轴) modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f); //指定合适的着色器(点光源着色器) shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor); //绘制大球 torusBatch.Draw(); //大球pop出栈 modelViewMatrix.PopMatrix();
绘制小球
- SetupRC函数:设置环绕大球公转的小球以及随机生成其他小球
//设置小球 gltMakeSphere(sphereBatch, 0.2, 10, 20); //设置随机生成的小球 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); } - RenderScene函数:绘制随机小球以及公转小球
//绘制随机小球 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(); } //设置公转小球压栈 modelViewMatrix.PushMatrix(); //设置小球自传 modelViewMatrix.Rotate(yRot * -2.0f, 0, 1.0f, 0.0); //设置小球公转(就是平移) modelViewMatrix.Translate(0.8f, 0.0f, 0.0f); shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSphereColor); sphereBatch.Draw(); //公转小球出栈 modelViewMatrix.PopMatrix();
设置观察者
观察者设置主要是为了可以通过上下左右键控制窗口移动
- RenderScene函数:设置观察者,要放在设置地板代码前面
//加入观察者 M3DMatrix44f mCamera; cameraFrame.GetCameraMatrix(mCamera); modelViewMatrix.PushMatrix(mCamera); - 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); } }