在上一篇OpenGL 深度測試基礎上修改main.cpp
文件,完成此demo
。bash
本篇主要是相關矩陣變換的使用,場景比前幾篇更加複雜。其中涉及到藍球公轉時因矩陣變換不遵循交換律,因此要先旋轉後平移,詳見世界座標變換要先縮放、後旋轉、再平移的緣由。詳細代碼以下:oop
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLGeometryTransform.h"
#include <math.h>
#include <GLUT/GLUT.h>
#include "GLTools.h"
#include "StopWatch.h"
#include <stdio.h>
GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
//視景體
GLFrustum viewFrustum;
GLGeometryTransform transformPipeline;
GLFrame cameraFrame;
GLTriangleBatch sunBatch;
GLTriangleBatch earthBatch;
GLTriangleBatch otherStarsBatch;
GLBatch theMilkyWayBatch;
#define NUMBER_STARS 100
GLFrame stars[NUMBER_STARS];
static GLfloat vTheMilkyWayColor[] = {0.57f,0.53f,0.62f,1.0f};
static GLfloat vSunColor[] = {0.96f,0.92f,0.23f,1.0f};
static GLfloat vEarthColor[] = {0.18f,0.23f,0.53f,1.0f};
static GLfloat vOtherStarsColor[] = {0.80f,0.69f,0.68f,1.0f};
void setupRC() {
glClearColor(0.27f, 0.24f, 0.34f, 1.0f);
shaderManager.InitializeStockShaders();
cameraFrame.MoveForward(10.0f);
glEnable(GL_DEPTH_TEST);
//星帶
theMilkyWayBatch.Begin(GL_LINES, 500);
for (GLfloat x = -30.0f; x <= 30.0f; x += 1) {
theMilkyWayBatch.Vertex3f(x, -0.5f, 30.0f);
theMilkyWayBatch.Vertex3f(x, -0.5f, -30.0f);
theMilkyWayBatch.Vertex3f(30.0f, -0.5f, x);
theMilkyWayBatch.Vertex3f(-30.0f, -0.5f, x);
}
theMilkyWayBatch.End();
//太陽
gltMakeSphere(sunBatch, 0.4f, 50, 100);
//地球
gltMakeSphere(earthBatch, 0.1f, 50, 100);
//其餘星體位置
gltMakeSphere(otherStarsBatch, 0.1f, 50, 100);
for (int i = 0; i < NUMBER_STARS; i++) {
GLfloat x = ((GLfloat)(rand() % 500 -200)) * 0.12f;
GLfloat z = ((GLfloat)(rand() % 500 -200)) * 0.12f;
stars[i].SetOrigin(x, 0.0f, z);
}
}
void changeSize(int w, int h) {
glViewport(0, 0, w, h);
//設置透視投影
viewFrustum.SetPerspective(30.0f, float(w) / float(h), 2.0f, 400.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
void renderScene() {
//清理緩衝區
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// //照相機矩陣
modelViewMatrix.PushMatrix(cameraFrame);
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vTheMilkyWayColor);
theMilkyWayBatch.Draw();
//太陽
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 30.0f;
M3DMatrix44f vLightPos = {0.0f,20.0f,10.0f,1.0f};
modelViewMatrix.Translate(0.0f, 0.0f, -5.0f);
modelViewMatrix.PushMatrix();
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,modelViewMatrix.GetMatrix(),projectionMatrix.GetMatrix(),vLightPos,vSunColor);
sunBatch.Draw();
modelViewMatrix.PopMatrix();
//繪製地球
modelViewMatrix.PushMatrix();
//要先旋轉後平移,矩陣乘法不遵循交換律要將旋轉後的矩陣平移
modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
modelViewMatrix.Translate(0.7f, 0.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,modelViewMatrix.GetMatrix(),projectionMatrix.GetMatrix(),vLightPos,vEarthColor);
earthBatch.Draw();
modelViewMatrix.PopMatrix();
//其餘星體
for (int i = 0; i < NUMBER_STARS; i++) {
modelViewMatrix.PushMatrix();
modelViewMatrix.MultMatrix(stars[i]);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,modelViewMatrix.GetMatrix(),projectionMatrix.GetMatrix(),vLightPos,vOtherStarsColor);
otherStarsBatch.Draw();
modelViewMatrix.PopMatrix();
}
modelViewMatrix.PopMatrix();
glutSwapBuffers();
glutPostRedisplay();
}
void specialKeys(int key,int x,int y){
float step = 0.4f;
float angular = float(m3dDegToRad(2.0f));
if (key == GLUT_KEY_UP) {
cameraFrame.MoveForward(-step);
}
if (key == GLUT_KEY_DOWN) {
cameraFrame.MoveForward(step);
}
if (key == GLUT_KEY_LEFT) {
cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
}
if (key == GLUT_KEY_RIGHT) {
cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
}
}
int main(int argc, char* argv[]) {
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(600, 600);
glutCreateWindow("dowZhang");
glutReshapeFunc(changeSize);
glutDisplayFunc(renderScene);
glutSpecialFunc(specialKeys);
GLenum err = glewInit();
if (GLEW_OK != err) {
return 1;
}
setupRC();
glutMainLoop();
return 0;
}
複製代碼
效果:post