前言
在上一篇OpenGL 深度测试基础上修改main.cpp
文件,完成此demo
。
代码
本篇主要是相关矩阵变换的使用,场景比前几篇更加复杂。其中涉及到蓝球公转时因矩阵变换不遵循交换律,所以要先旋转后平移,详见世界坐标变换要先缩放、后旋转、再平移的原因。详细代码如下:
#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;
}
效果: