綜合demo案例,效果如下
一、主要代碼
1 // 初始化 設置 2 void SetupRC() { 3 4 // 初始化 5 glClearColor(0, 0.3, 0.5, 1); 6 shaderManager.InitializeStockShaders(); 7 // 開啟深度測試 -- 球體轉動 8 glEnable(GL_DEPTH_TEST); 9 10 // 地板的頂點數據 11 floorTriangleBatch.Begin(GL_LINES, 324);// line 方式繪制連接,324個頂點 12 for (GLfloat x = -20.f; x <= 20.f; x += 0.5f) { 13 floorTriangleBatch.Vertex3f(x, -0.5f, 20.f); 14 floorTriangleBatch.Vertex3f(x, -0.5f, -20.f); 15 floorTriangleBatch.Vertex3f(20.f, -0.5f, x); 16 floorTriangleBatch.Vertex3f(-20.f, -0.5f, x); 17 } 18 floorTriangleBatch.End(); 19 20 // 設置大球模型 21 gltMakeSphere(bigSphereBatch, 0.4f, 40, 80);// 半徑,切40 22 23 // 設置小球模型 24 gltMakeSphere(sphereBatch, 0.1f, 13, 26); 25 // 小球們的位置 26 // sphere.SetOrigin(-1.f,0.0f,-1.f); 27 for (int i=0; i<SPHERE_NUM; i++) { 28 // y軸不變,X,Z產生隨機值 29 GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f); 30 GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f); 31 // 設置球的位置 32 spheres[i].SetOrigin(x,0.0f,z); 33 } 34 35 } 36 37 38 39 // 渲染 40 void RenderScene(void) { 41 42 // 清除窗口 顏色、深度緩沖區 43 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 44 45 // 顏色們 46 static GLfloat vFloorColor[] = {0.0, 0.5, 0.5, 1};// 地板顏色 47 static GLfloat vBigSphereColor[] = {0.3, 0.5, 0.5, 1};// 大球顏色 48 static GLfloat vSphereColor[] = {0.5, 0.5, 0.7, 1};// 小球顏色 49 50 // 定時器時間 動畫 --> 大球自傳 51 static CStopWatch rotTimer; 52 float yRot = rotTimer.GetElapsedSeconds() * 60.0f; 53 54 modelViewMatix.PushMatrix();// 壓棧 --> copy 一份棧頂矩陣 --> 單元矩陣 55 56 57 // 觀察者矩陣壓棧 58 /* 59 觀察者的移動要影響到所有繪制物體,所以要 先壓棧 60 */ 61 M3DMatrix44f cameraM; 62 cameraFrame.GetCameraMatrix(cameraM); 63 modelViewMatix.PushMatrix(cameraFrame); 64 65 66 // 地板 67 shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor); 68 floorTriangleBatch.Draw(); 69 70 71 // 大球 72 M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f};// 點光源位置 73 modelViewMatix.Translate(0, 0, -3.0f);// 向屏幕里面(-z)移動 3 --> 只移動一次 74 75 modelViewMatix.PushMatrix();// 壓棧 -- 模型視圖矩陣(經過了一次平移的結果矩陣) 76 modelViewMatix.Rotate(yRot, 0, 1, 0);// yRot:旋轉角度 沿Y軸轉動 77 shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vBigSphereColor);// GLT_SHADER_POINT_LIGHT_DIFF:電光源着色器;vLightPos:光源位置;vBigSphereColor:繪制顏色 78 bigSphereBatch.Draw(); 79 // 繪制大球后 pop出大球的繪制矩陣 80 modelViewMatix.PopMatrix(); 81 82 83 // 隨機擺放的小球們 84 // modelViewMatix.PushMatrix(); 85 // modelViewMatix.MultMatrix(sphere); 86 // shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSphereColor); 87 // sphereBatch.Draw(); 88 // modelViewMatix.PopMatrix(); 89 for (int i=0; i<SPHERE_NUM; i++) { 90 modelViewMatix.PushMatrix(); 91 modelViewMatix.MultMatrix(spheres[i]); 92 shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSphereColor); 93 sphereBatch.Draw(); 94 95 modelViewMatix.PopMatrix(); 96 } 97 98 // 圍繞大球旋轉的小球 99 /* 100 --> 為什么沒有壓棧呢??? --> 此球是繪制的最后一步了,它的繪制不會影響其他(后面沒有其他了),所以沒有必要壓棧 101 壓棧的目的是繪制 不同物體時 不同的矩陣變換 不要彼此影響 102 */ 103 modelViewMatix.Rotate(yRot * -2, 0, 1, 0);// 旋轉弧度 yRot * -2 --> +2、-2 旋轉方向 104 modelViewMatix.Translate(0.8f, 0, 0);// 小球X軸上平移一下,0.8f-->越大距離大球越遠 105 shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSphereColor); 106 sphereBatch.Draw(); 107 108 109 // 觀察者矩陣出棧 110 modelViewMatix.PopMatrix(); 111 112 // pop 出繪制初始的壓棧 113 modelViewMatix.PopMatrix(); 114 115 // 交換緩沖區 116 glutSwapBuffers(); 117 118 // 重新繪制 119 glutPostRedisplay(); 120 }
二、重點總結
1)整體繪制思路:
1、繪制地板
2、繪制大球
3、繪制隨機的50個小球
4、繪制圍繞大球旋轉的小球
5、添加鍵位控制移動 -- 壓棧觀察者矩陣
2)壓棧
RenderScene中,壓棧邏輯:
壓棧一個單元矩陣
--> 壓棧觀察者矩陣 --> 繪制地板
--> 壓棧 繪制大球--> 大球繪制結束 --> 出棧
--> 壓棧 繪制小球們 --> 小球們繪制完成 --> 出棧
--> 繪制旋轉的小球 --> 繪制完成
--> 觀察者矩陣出棧
--> 整體出出棧