實現(xiàn)效果:
能隨著觀察者的不斷移動,都能觀察到小球的公轉(zhuǎn)加自轉(zhuǎn)
最終圖片效果:
大體實現(xiàn)思路及步驟拆分:
1欲芹、先實現(xiàn)綠色方格地板部分
2卿啡、實現(xiàn)固定自轉(zhuǎn)的紅色大球和一個中型的藍球,以及位置隨機的50個小藍球
3菱父、實現(xiàn)中型藍球繞紅色大球的公轉(zhuǎn)
4颈娜、實現(xiàn)移動觀察者(camera)仍能觀察紅球自轉(zhuǎn)及藍球圍繞紅球公轉(zhuǎn)
下面開始代碼部分
一、先定義一些變量
GLShaderManager shaderManager; // 定義一個著色器管理器
GLMatrixStack modelViewMatrix; // 定義一個模型視圖矩陣
GLMatrixStack projectionMatrix; // 定義一個投影矩陣
GLFrustum viewFrustum; // 視景體
GLGeometryTransform transformPipeline; // 幾何圖形變換管道
GLTriangleBatch ? ?torusBatch;? ? ? ? ? ? //批次類 ?-大球
GLTriangleBatch? ? sphereBatch;? ? ? ? ? ? //批次類 ?-小球
GLBatch? ? ? ? ? ? ? ? floorBatch;? ? ? ? ? //簡單的批次類 ?-地板
//角色幀 照相機角色幀
GLFrame? cameraFrame;
GLFrame? objectFrame;
//**4滞伟、添加附加隨機球
#define NUM_SPHERES50
GLFrame spheres[NUM_SPHERES];
二揭鳞、在主函數(shù)中初始化一些特殊鍵位操作以及設置窗口默認參數(shù),注冊變化函數(shù)
int ?main (int ?argc, ?char* argv[])
{
//1梆奈、設置當前工作目錄野崇,針對MAC OS X? ? /*?? ? `GLTools`函數(shù)`glSetWorkingDrectory`用來設置當前工作目錄。實際上在Windows中是不必要的亩钟,因為工作目錄默認就是與程序可執(zhí)行執(zhí)行程序相同的目錄乓梨。但是在Mac OS X中鳖轰,這個程序?qū)斍肮ぷ魑募A改為應用程序捆綁包中的`/Resource`文件夾。`GLUT`的優(yōu)先設定自動進行了這個中設置扶镀,但是這樣中方法更加安全蕴侣。?? ? */
? ? gltSetWorkingDirectory(argv[0]);
//2.初始化一個GLUT庫
? ? glutInit(&argc, argv);
/* 3、 ? ? 初始化雙緩沖窗口臭觉,其中標志GLUT_DOUBLE昆雀、GLUT_RGBA、GLUT_DEPTH蝠筑、GLUT_STENCIL分別指?? ? 雙緩沖窗口狞膘、RGBA顏色模式、深度測試什乙、模板緩沖區(qū)? ? ??? ?
?--GLUT_DOUBLE`:雙緩存窗口挽封,是指繪圖命令實際上是離屏緩存區(qū)執(zhí)行的,然后迅速轉(zhuǎn)換成窗口視圖臣镣,這種方式辅愿,經(jīng)常用來生成動畫效果;?? ??
--GLUT_DEPTH`:標志將一個深度緩存區(qū)分配為顯示的一部分忆某,因此我們能夠執(zhí)行深度測試点待;?? ??
--GLUT_STENCIL`:確保我們也會有一個可用的模板緩存區(qū)。?? ? 深度褒繁、模板測試后面會細致講到?? ?
?*/
? ? glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
//3亦鳞、GLUT窗口大小、窗口標題
? ? glutInitWindowSize(800,600);
? ? glutCreateWindow("OpenGL SphereWorld");
/*4棒坏、 ? ? ?GLUT 內(nèi)部運行一個本地消息循環(huán)燕差,攔截適當?shù)南ⅰH缓笳{(diào)用我們不同時間注冊的回調(diào)函數(shù)坝冕。我們一共注冊2個回調(diào)函數(shù):?
? ? 1)為窗口改變大小而設置的一個回調(diào)函數(shù)???
? ? 2)包含OpenGL 渲染的回調(diào)函數(shù)?? ? */
? ? glutReshapeFunc(ChangeSize);//注冊函數(shù)徒探,在窗口改變大小的時候調(diào)用
? ? glutDisplayFunc(RenderScene);//注冊渲染函數(shù)
? ? glutSpecialFunc(SpeacialKeys);//注冊特殊函數(shù)
/* 5、 ? ? 初始化一個GLEW庫,確保OpenGL API對程序完全可用喂窟。?? ? 在試圖做任何渲染之前测暗,要檢查確定驅(qū)動程序的初始化過程中沒有任何問題?? ? */
? ? GLenumerr =glewInit();
? ? if(GLEW_OK!= err) {
? ? ? ? fprintf(stderr,"GLEW Error: %s\n",glewGetErrorString(err));
? ? ? ? return1;
? ? }
//6、設置我們的渲染環(huán)境
? ?SetupRC();
?//7磨澡、這是一個無限執(zhí)行的循環(huán)碗啄,它會負責一直處理窗口和操作系統(tǒng)的用戶輸入等操作。(注意:不會執(zhí)行在glutMainLoop()之后的所有命令稳摄。)
? ? glutMainLoop();?
? ??return?0;
}
三稚字、開始設置我們的渲染環(huán)境
void ? ?SetupRC()
{
? ? //1.設置清屏顏色(背景顏色)
? ? glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
? //2.初始化著色器
?//沒有著色器,在OpenGL 核心框架中是無法進行任何渲染的。初始化一 ?個渲染管理器胆描。目前我們使用固定管線渲染瘫想,后面會用OpenGL著色語言來寫著色器
? ?shaderManager.InitializeStockShaders();
?//3.修改物體的初始坐標,往后移動5.0f的距離也就是z為-5昌讲,z軸垂直屏幕指向我們觀察者為正国夜,z為-5,就是往屏幕里面移動5
? ? objectFrame.MoveForward(5.0f);
? ??//4.開啟深度測試短绸,3D圖像渲染需要開啟深度測試
? ? glEnable(GL_DEPTH_TEST);
? //5.開始設置地板的頂點數(shù)據(jù)
? ?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();
? //6.設置大球模型
? ??gltMakeSphere(torusBatch, 0.4f, 40, 80);
?//7.設置小球模型
? ??gltMakeSphere(torusBatch, 0.1f, 26, 13);
//8车吹、隨機位置放置小球
? ?for (int i = 0; i < NUM_SPHERES; i++) {?? ? ? ???
? ? ? //y軸不變,X,Z產(chǎn)生隨機值? ? ? ??
? ? ?GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);? ? ??
? ? ?GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);?? ? ? ?? ? ? ??
? ? //在y方向醋闭,將球體設置為0.0的位置礼搁,這使得它們看起來是飄浮在眼睛的高度? ? ? ?
? ? //對spheres數(shù)組中的每一個頂點,設置頂點數(shù)據(jù) ? ? ? ?
? ? spheres[i].SetOrigin(x, 0.0f, z);? ?
?}
四目尖、進行調(diào)用以繪制場景
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.清除顏色緩存區(qū)和深度緩沖區(qū),防止殘存的顏色和深度值影響渲染
? ? glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
? ? //4扎运、加入objectFrame瑟曲,用于特殊鍵位操作觀察者位置移動
? ? modelViewMatrix.PushMatrix(objectFrame);
? ??//5.獲取光源位置
? ? M3DVector4fvLightPos = {0.0f,10.0f,5.0f,1.0f};
? ??//6.繪制地面
? ? shaderManager.UseStockShader(GLT_SHADER_FLAT,
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? transformPipeline.GetModelViewProjectionMatrix(),
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? vFloorColor);
? ? floorBatch.Draw();
? ? //7.使得大球位置平移(3.0)向屏幕里面
? ? modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
? ? //8.壓棧(復制棧頂)
? ? modelViewMatrix.PushMatrix();
? ? //9.大球自轉(zhuǎn)
? ? modelViewMatrix.Rotate(yRot,0.0f,1.0f,0.0f);
? ? //10.指定合適的著色器(點光源著色器)? ? shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor);
? ? torusBatch.Draw();
? ? //11.繪制完畢則出棧Pop
? ? modelViewMatrix.PopMatrix();
? ? //12.畫小球
? ? for(inti =0; i< NUM_SPHERES; i++) {
? ? ? ? modelViewMatrix.PushMatrix();// 壓棧,開始執(zhí)行變換
? ? ? ? modelViewMatrix.MultMatrix(spheres[i]);
? ? ? ? shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? transformPipeline.GetProjectionMatrix(), vLightPos, vSphereColor);
? ? ? ? sphereBatch.Draw();//批次類開啟繪制
? ? ? ? modelViewMatrix.PopMatrix();//出棧
? ? }
? ? //13. 讓一個小籃球圍繞大球公眾自轉(zhuǎn)
? ? modelViewMatrix.Rotate(yRot * -2.0f,0.0f,1.0f,0.0f);//旋轉(zhuǎn)矩陣
? ? modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);//平移
? ? shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vSphereColor);
? ? sphereBatch.Draw();
? ? modelViewMatrix.PopMatrix();//出棧
? ??//14.執(zhí)行緩存區(qū)交換
? ? glutSwapBuffers();
? ? //15 發(fā)送重新渲染
? ? glutPostRedisplay();
}
五豪治、屏幕大小更改或者已經(jīng)初始化
void?ChangeSize(int?nWidth ,int?nHeight)
{
? ? //1.設置視口或者視口大小更改后重新設置視口
? ? glViewport(0,0, nWidth, nHeight);
? ? //2.創(chuàng)建投影矩陣
? ? viewFrustum.SetPerspective(35.0f,float(nWidth)/float(nHeight),1.0f,100.0f);
? ? //viewFrustum.GetProjectionMatrix()? 獲取viewFrustum投影矩陣
? ? //并將其加載到投影矩陣堆棧上
? ? projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
? ? //3.設置變換管道以使用兩個矩陣堆棧(變換矩陣modelViewMatrix 洞拨,投影矩陣projectionMatrix)
? ? //初始化GLGeometryTransform 的實例transformPipeline.通過將它的內(nèi)部指針設置為模型視圖矩陣堆棧 和 投影矩陣堆棧實例,來完成初始化
? ? //當然這個操作也可以在SetupRC 函數(shù)中完成负拟,但是在窗口大小改變時或者窗口創(chuàng)建時設置它們并沒有壞處烦衣。而且這樣可以一次性完成矩陣和管線的設置。
? ? transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
六掩浙、特殊鍵位操作
void?SpeacialKeys(int?key,int?x,int?y){
? ??//設定移動步長
? ? float ? ? ?linear =0.1f;
? ? //設定旋轉(zhuǎn)度數(shù)
? ? float ? ?angular = ?float(m3dDegToRad(5.0f));//角度轉(zhuǎn)弧度
? ? if(key ==GLUT_KEY_UP) {//鍵盤上的方向鍵 ?up鍵
? ? ? ? //MoveForward 平移
? ? ? ? objectFrame.MoveForward(linear);
? ? }
? ? if(key ==GLUT_KEY_DOWN) {//鍵盤上的方向鍵 ?down鍵
? ? ? ? objectFrame.MoveForward(linear);
? ? }
? ??if(key ==GLUT_KEY_LEFT) {//鍵盤上的方向鍵 ?left鍵
? ? ? ? //RotateWorld 旋轉(zhuǎn)
? ? ? ? objectFrame.RotateWorld(angular,0,1,0);
? ? }
? ? if(key ==GLUT_KEY_RIGHT) {//鍵盤上的方向鍵 ?right鍵
? ? ? ? objectFrame.RotateWorld(angular,0,1,0); ? ?}
}
七花吟、最終效果視頻地址優(yōu)酷傳送門:小球自轉(zhuǎn)公轉(zhuǎn)效果圖
[溪浣雙鯉的技術摸爬滾打之路](http://www.reibang.com/p/3fbecd65faae)