OpenGL 没有纹理的星系

386 阅读1分钟

前言

在上一篇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;
}

效果: