OpenGL 球体公转+自转案例

2020-07-23  本文已影响0人  _涼城
声明变量

声明一个着色器管理器实例,为模型视图矩阵和投影矩阵声明GLMatrixStack实例,使用GLFrustum类构造投影矩阵,最后用GLGeometryTransform类声明一个管线实例管理矩阵堆栈。

GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrustum viewFrustum;
GLGeometryTransform transformPipeline;
初始化工程
绘制地板
绘制地板流程.png
声明批次类容器实例
GLBatch floorBatch;
批次容器拷贝顶点坐标
 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();
平面着色器绘制地板
static GLfloat vFloorColor[] = { 0.0f,1.0f,0.0f,1.0f };
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor);
floorBatch.Draw();
绘制自转球
绘制自转球流程图.png
声明批次类容器实例
GLTriangleBatch  torusBatch; 
//角度
GLfloat yRot;
设置大球模型
gltMakeSphere(torusBatch, 0.4f, 40, 80);
RenderScene
  static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    //2.基于时间动画
  static CStopWatch    rotTimer;
  float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
    //** 压栈
  modelViewMatrix.PushMatrix();
    //4.获取光源位置
  M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f};
    //5.使得大球位置平移(3.0)向屏幕里面
  modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
    //6.压栈(复制栈顶)
  modelViewMatrix.PushMatrix();
    //7.大球自转
  modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
    //8.指定合适的着色器(点光源着色器)
  shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
                                 transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor);
  torusBatch.Draw();
    //9.绘制完毕则Pop
  modelViewMatrix.PopMatrix();
  modelViewMatrix.PopMatrix();
  glutSwapBuffers();
  //提交重新渲染
  glutPostRedisplay();
绘制静态球
绘制静态球流程图.png
声明批次类容器实例
GLTriangleBatch sphereBatch;
//随机球个数
#define NUM_SPHERES 50
//随机球顶点数组
GLFrame spheres[NUM_SPHERES];
初始化
 //设置小球模型
    gltMakeSphere(sphereBatch, 0.1f, 13, 26);
//绘制小球顶点坐标
    for (int i = 0; i < NUM_SPHERES; i++) {
          //y轴一致
        GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        spheres[i].SetOrigin(x,0.0f,z);
    }
RenderScene

/*
 绘制小球
*/
for (int i = 0 ; i < NUM_SPHERES; i++) {
    modelViewMatrix.PushMatrix();
    modelViewMatrix.MultMatrix(spheres[I]);
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSmallSphereColor);
    sphereBatch.Draw();
    modelViewMatrix.PopMatrix();
}
绘制公转球
绘制公转球流程图.png
RenderScene
/*
  绘制运动的小球
*/
    modelViewMatrix.PushMatrix();
    modelViewMatrix.Rotate(yRot * -2, 0, 1, 0);
    modelViewMatrix.Translate(0.8f, 0.0f,0.0f);
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSmallSphereColor);
    sphereBatch.Draw();
    modelViewMatrix.PopMatrix();
设置特殊键位调整观察者位置
调整观察者位置
//移动(移动只是计算了X,Y移动的距离,以及碰撞检测)
void SpecialKeys(int key, int x, int y)
{
    float linear = 0.1f;
    float angular = float(m3dDegToRad(5.0f));
    if (key == GLUT_KEY_UP) {
        cameraFrame.MoveForward(linear);
    }
    if (key == GLUT_KEY_DOWN) {
        cameraFrame.MoveForward(-linear);
    }
    if (key == GLUT_KEY_LEFT) {
        cameraFrame.RotateWorld(angular, 0, 1, 0);
    }
    if (key == GLUT_KEY_RIGHT) {
       cameraFrame.RotateWorld(-angular, 0, 1, 0);
    }

}
渲染
 //在渲染前,调整观察者位置
 M3DMatrix44f mCamera;
 cameraFrame.GetCameraMatrix(mCamera);
 modelViewMatrix.PushMatrix(mCamera);
最后附上完整代码

#include "GLTools.h"
#include "GLShaderManager.h"
#include "math3d.h"
#include <GLFrame.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <GLFrustum.h>
#include <StopWatch.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrustum viewFrustum;
GLGeometryTransform transformPipeline;
GLTriangleBatch torusBatch;
GLTriangleBatch sphereBatch;

GLBatch floorBatch;
GLfloat yRot;

//观察者
GLFrame cameraFrame;

//随机球
#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];

void SetupRC()
{
     //设置清屏颜色(背景颜色)
    glClearColor(0.0f, 0.0f, 0.0f, 1);
    //没有着色器,在OpenGL 核心框架中是无法进行任何渲染的。初始化一个渲染管理器。
    //在前面的课程,我们会采用固管线渲染,后面会学着用OpenGL着色语言来写着色器
    shaderManager.InitializeStockShaders();

    //投影变换矩阵 & 移动变换矩阵  > 变换管道 > 快速去矩阵相乘 > 遍历
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

    //绘制地板
    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();

    //绘制大球
    gltMakeSphere(torusBatch, 0.4f, 40, 80);

    //绘制小球本身坐标
    gltMakeSphere(sphereBatch, 0.1f, 13, 26);
    //绘制小球顶点坐标
    for (int i = 0; i < NUM_SPHERES; i++) {
          //y轴一致
        GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        spheres[i].SetOrigin(x,0.0f,z);
    }

}

//移动(移动只是计算了X,Y移动的距离,以及碰撞检测)
void SpecialKeys(int key, int x, int y)
{
    float linear = 0.1f;
    float angular = float(m3dDegToRad(5.0f));
    if (key == GLUT_KEY_UP) {
        cameraFrame.MoveForward(linear);
    }
    if (key == GLUT_KEY_DOWN) {
        cameraFrame.MoveForward(-linear);
    }
    if (key == GLUT_KEY_LEFT) {
        cameraFrame.RotateWorld(angular, 0, 1, 0);
    }
    if (key == GLUT_KEY_RIGHT) {
       cameraFrame.RotateWorld(-angular, 0, 1, 0);
    }

}

//进行调用以绘制场景
void RenderScene(void)
{

    static GLfloat vFloorColor[] = { 0.0f,1.0f,0.0f,1.0f };
    static GLfloat vBigSphereColor[] = {1.0f,0.0f,0.0f,1.0f};
    static GLfloat vSmallSphereColor[] = {0.0f,0.0f,1.0f,1.0f};
    //定时器
    static CStopWatch rotTimer;
    float yRot = rotTimer.GetElapsedSeconds() * 60.f;

     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    //    //颜色值
     glEnable(GL_DEPTH_TEST);
    M3DVector4f vLightPos = {
        0.0,10.0,5.0,1.0
     };
    modelViewMatrix.PushMatrix();
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.PushMatrix(mCamera);
//    //基于时间的动画
    shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor);
    floorBatch.Draw();

//    //绘制旋转的
    modelViewMatrix.Translate(0.0, 0.0, -3.0f);
    modelViewMatrix.PushMatrix();
    modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);

    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vBigSphereColor);
    torusBatch.Draw();
    //出栈
    modelViewMatrix.PopMatrix();

    /*
     绘制小球
     */
    for (int i = 0 ; i < NUM_SPHERES; i++) {
        modelViewMatrix.PushMatrix();
        modelViewMatrix.MultMatrix(spheres[I]);
        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSmallSphereColor);
        sphereBatch.Draw();
        modelViewMatrix.PopMatrix();
    }

    /*
     绘制运动的小球
     */
    modelViewMatrix.PushMatrix();
    modelViewMatrix.Rotate(yRot * -2, 0, 1, 0);
    modelViewMatrix.Translate(0.8f, 0.0f,0.0f);
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSmallSphereColor);
    sphereBatch.Draw();
    modelViewMatrix.PopMatrix();

    //出栈
    modelViewMatrix.PopMatrix();
    modelViewMatrix.PopMatrix();
    glDisable(GL_DEPTH_TEST);
    glutSwapBuffers();
    glutPostRedisplay();
}

// 屏幕改变大小或初始化
void ChangeSize(int w, int h)
{
    glViewport(0, 0, w, h);
    //创建投影矩阵,并将它载入投影矩阵堆栈中
    viewFrustum.SetPerspective(35.0f, float(w) / (float)h, 1.0f, 100.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    //设置变换管线以使用两个矩阵堆栈
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

int main(int argc, char* argv[])
{
    gltSetWorkingDirectory(argv[0]);

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(600, 600);
    glutCreateWindow("Move Block with Arrow Keys");

    GLenum err = glewInit();
    if (GLEW_OK != err)
    {

        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
        return 1;
    }

    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);

    SetupRC();

    glutMainLoop();
    return 0;
}
上一篇下一篇

猜你喜欢

热点阅读