渲染世界的OpenGL<7>基础变换代码分析

(1)移动旋转方块代码分析

这个代码是基于最开始的代码分析当中对方块的移动的代码。
实现每一次移动方块,方块都会进行旋转相应的角度。通过对旋转矩阵的增加,并且将旋转矩阵和移动矩阵进行综合,并且将其作为参数投入到shadermanagement当中,从而使得每一个顶点都会遵循相应的移动矩阵方式对其进行移动。

#pragma comment(lib,"GLTools.lib")

#include <GLTools.h>    // OpenGL toolkit
#include <GLShaderManager.h>
#include <math3d.h>
#include <GL/glut.h>

//渲染队列
GLBatch  squareBatch;
GLShaderManager shaderManager;


GLfloat blockSize = 0.1f;
GLfloat vVerts[] = { -blockSize, -blockSize, 0.0f,
blockSize, -blockSize, 0.0f,
blockSize,  blockSize, 0.0f,
-blockSize,  blockSize, 0.0f };

GLfloat xPos = 0.0f;
GLfloat yPos = 0.0f;


///////////////////////////////////////////////////////////////////////////////
// 初始化渲染场景
void SetupRC()
{
    // 设置背景颜色
    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
    //初始化渲染器管理器
    shaderManager.InitializeStockShaders();

    //对squareBatch进行渲染。
    squareBatch.Begin(GL_TRIANGLE_FAN, 4);
    squareBatch.CopyVertexData3f(vVerts);
    squareBatch.End();
}

// 设置按键对其进行控制
void SpecialKeys(int key, int x, int y)
{
    GLfloat stepSize = 0.025f;

    //设置不同按键
    if (key == GLUT_KEY_UP)
        yPos += stepSize;

    if (key == GLUT_KEY_DOWN)
        yPos -= stepSize;

    if (key == GLUT_KEY_LEFT)
        xPos -= stepSize;

    if (key == GLUT_KEY_RIGHT)
        xPos += stepSize;

    // 碰撞检测
    if (xPos < (-1.0f + blockSize)) xPos = -1.0f + blockSize;

    if (xPos > (1.0f - blockSize)) xPos = 1.0f - blockSize;

    if (yPos < (-1.0f + blockSize))  yPos = -1.0f + blockSize;

    if (yPos > (1.0f - blockSize)) yPos = 1.0f - blockSize;

    glutPostRedisplay();
}





///////////////////////////////////////////////////////////////////////////////
// 正真的渲染函数
//注意其矩阵操作的方法。
void RenderScene(void)
{
    // 清除当前的缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    //设置红色
    GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    //设置当前的矩阵
    //最终矩阵、移动矩阵、旋转矩阵
    M3DMatrix44f mFinalTransform, mTranslationMatrix, mRotationMatrix;

    // 初始化使用相关的移动参数生成相关的矩阵
    m3dTranslationMatrix44(mTranslationMatrix, xPos, yPos, 0.0f);

    // 每一次操作,进行5个单位的旋转
    static float yRot = 0.0f;
    yRot += 5.0f;
    //不断的绕着z轴进行旋转,利用不同的旋转参数生成矩阵
    m3dRotationMatrix44(mRotationMatrix, m3dDegToRad(yRot), 0.0f, 0.0f, 1.0f);
    //利用矩阵乘法生成一个综合矩阵
    m3dMatrixMultiply44(mFinalTransform, mTranslationMatrix, mRotationMatrix);

    //利用上述的参数对相关的点参数进行变换
    shaderManager.UseStockShader(GLT_SHADER_FLAT, mFinalTransform, vRed);
    squareBatch.Draw();

    // 手动更新
    glutSwapBuffers();
}



///////////////////////////////////////////////////////////////////////////////

void ChangeSize(int w, int h)
{
    glViewport(0, 0, w, h);
}

///////////////////////////////////////////////////////////////////////////////
// 主函数
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)
    {
        // Problem: glewInit failed, something is seriously wrong.
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
        return 1;
    }

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

    SetupRC();

    glutMainLoop();
    return 0;
}

(2)模型投影矩阵应用

注意模型投影矩阵的应用
生成透视投影:GLFrustum viewFrustum;
在窗口控制函数中:viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 1000.0f);
最终和模型矩阵综合:m3dMatrixMultiply44(mModelViewProjection,viewFrustum.GetProjectionMatrix(), mModelview);

#pragma comment(lib,"GLTools.lib")
#include <GLTools.h>    // OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>
#include <GLBatch.h>
#include <StopWatch.h>
#include <GL/glut.h>


//  透视投影
GLFrustum           viewFrustum;

// 渲染器管理器
GLShaderManager     shaderManager;

// 渲染队列
GLTriangleBatch     torusBatch;


void ChangeSize(int w, int h)
{
    // 避免下面设置透视的时候出错
    if (h == 0)
        h = 1;

    // 将视口设置到窗口的规模
    glViewport(0, 0, w, h);
    //设置透视投影
    viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 1000.0f);
}


// 渲染窗口
void RenderScene(void)
{
    // 动画设置的秒表
    static CStopWatch rotTimer;
    //得到当前的时间并且计算旋转
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;

    // 清除相关缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // 设置当前的矩阵变量
    M3DMatrix44f mTranslate, mRotate, mModelview, mModelViewProjection;

    // 初始化移动矩阵
    m3dTranslationMatrix44(mTranslate, 0.0f, 0.0f, -2.5f);

    // 初始化旋转矩阵
    m3dRotationMatrix44(mRotate, m3dDegToRad(yRot), 0.0f, 1.0f, 0.0f);

    // 将上述两个矩阵综合进模型矩阵
    m3dMatrixMultiply44(mModelview, mTranslate, mRotate);

    // 将模型矩阵装入到投影矩阵当中
    // 生成最终的模型投影矩阵
    m3dMatrixMultiply44(mModelViewProjection, viewFrustum.GetProjectionMatrix(), mModelview);

    // 对各个顶点进行绘制
    GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
    shaderManager.UseStockShader(GLT_SHADER_FLAT, mModelViewProjection, vBlack);
    torusBatch.Draw();


    // Swap buffers, and immediately refresh
    glutSwapBuffers();
    glutPostRedisplay();
}

// 渲染环境初始化
void SetupRC()
{
    // 背景颜色设置
    glClearColor(0.8f, 0.8f, 0.8f, 1.0f);

    glEnable(GL_DEPTH_TEST);

    shaderManager.InitializeStockShaders();

    // 调用生成花拖的函数。
    gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);

    //正反面都用线框渲染
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}


///
// 主函数
int main(int argc, char* argv[])
{
    gltSetWorkingDirectory(argv[0]);

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(800, 600);
    glutCreateWindow("ModelViewProjection Example");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);


    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }

    SetupRC();

    glutMainLoop();
    return 0;
}

(3)渲染一个简单世界
这里包含了一个完整的渲染顺序
实例化两个MatrixStack,一个作为模型矩阵,一个作为投影矩阵。
然后实例化一个渲染管线。
ChangeSize当中对投影矩阵进行赋值,并且利用两个矩阵堆栈对渲染管线初始化。
RenderScene当中对模型矩阵进行操作,按照先渲染静止物体,在渲染移动物体的原则。
注意这里对地面的动态设置渲染:对于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);
    }
#pragma comment(lib,"GLTools.lib")

#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>

#include <math.h>
#include <stdio.h>

#include <GL/glut.h>





GLShaderManager     shaderManager;          // Shader Manager
GLMatrixStack       modelViewMatrix;        // 模型视图矩阵
GLMatrixStack       projectionMatrix;       // 投影矩阵
GLFrustum           viewFrustum;            // 视景体
GLGeometryTransform transformPipeline;      // 几何变换管线

GLTriangleBatch     torusBatch;
GLBatch             floorBatch;


//
// 渲染环境初始化
void SetupRC()
{
    // 初始化ShaderManager。
    shaderManager.InitializeStockShaders();
    //开启深度测试
    glEnable(GL_DEPTH_TEST);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    //背景颜色为黑色
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    // 创建花拖
    gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);

    //设置地板
    //使用计算方法动态生成
    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();
}


///
// 设置屏幕大小
void ChangeSize(int nWidth, int nHeight)
{
    glViewport(0, 0, nWidth, nHeight);

    // 创建透视矩阵,GLFrustum类的viewFrustum实例会为我们设置投影矩阵
    //载入投影矩阵对象
    viewFrustum.SetPerspective(35.0f, float(nWidth) / float(nHeight), 1.0f, 100.0f);
    //透视矩阵加载到透视矩阵堆栈中
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    //初始化渲染管线
    // 设置变换管线,从而可以使用两个矩阵堆栈
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    //注意:我们本可以在SetupRC当中完成这项工作。但是窗口大小
    //改变的时候,重新设置它们并没有坏处。并且可以一次性完成
    //矩阵和管线的设置。


}


// 绘制两个物体
void RenderScene(void)
{
    // 设置绘制不同物体的颜色。
    static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f };
    static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };

    // 设置秒表计时器
    static CStopWatch   rotTimer;
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;

    // 清除相应的缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


    // 保存当前的矩阵,单位矩阵
    modelViewMatrix.PushMatrix();

    // 使用平面渲染器对其进行渲染
    shaderManager.UseStockShader(GLT_SHADER_FLAT,
        transformPipeline.GetModelViewProjectionMatrix(),
        vFloorColor);
    floorBatch.Draw();

    // 绘制旋转的花拖
    modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);
    modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),
        vTorusColor);
    torusBatch.Draw();

    // 恢复初始的矩阵
    modelViewMatrix.PopMatrix();

    // Do the buffer Swap
    glutSwapBuffers();

    // Tell GLUT to do it again
    glutPostRedisplay();
}


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

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 600);

    glutCreateWindow("OpenGL SphereWorld");

    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }


    SetupRC();
    glutMainLoop();
    return 0;
}

(4)为世界添加一个移动的摄像机

以下程序说明对摄像机的控制,同时也多次渲染了一个球体。
渲染摄像机的步骤:
GLFrame cameraFrame:首先使用角色帧来完成一个摄像机的创建。
M3DMatrix44f mCamera:在render里面新创建一个矩阵。
cameraFrame.GetCameraMatrix(mCamera):找出符合条件的摄像机矩阵。
modelViewMatrix.PushMatrix(mCamera):把摄像机矩阵压入模型矩阵中。
在上述操作之后,在SpecialKey当中,也设置诸多的key对其进行渲染:
cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
cameraFrame.MoveForward(-linear);

对于渲染多个物体:
modelViewMatrix.PopMatrix();多次使用pop来取消之前的矩阵操作,从而之后的操作不会对之前的操作产生影响。

#pragma comment(lib,"GLTools.lib")

#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLFrame.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>
#include <math.h>
#include <stdio.h>
#include <GL/glut.h>



GLShaderManager     shaderManager;          // 渲染管理器
GLMatrixStack       modelViewMatrix;        // 模型矩阵
GLMatrixStack       projectionMatrix;       // 透视矩阵
GLFrustum           viewFrustum;            // 透视
GLGeometryTransform transformPipeline;      // 渲染管线

GLTriangleBatch     torusBatch;
GLBatch             floorBatch;
GLTriangleBatch     sphereBatch;

//设置角色帧,作为相机
GLFrame             cameraFrame;

//
// 渲染环境设置
void SetupRC()
{
    //初始化渲染管理器
    shaderManager.InitializeStockShaders();
    //开启深度测试
    glEnable(GL_DEPTH_TEST);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    // 创建一个花拖
    gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);

    //创建一个球
    gltMakeSphere(sphereBatch, 0.1f, 26, 13);

    //创建地板
    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();
}


///
// 改变窗口大小
void ChangeSize(int nWidth, int nHeight)
{
    glViewport(0, 0, nWidth, nHeight);

    // 设置透视模式,初始化其透视矩阵
    viewFrustum.SetPerspective(35.0f, float(nWidth) / float(nHeight), 1.0f, 100.0f);
    //把透视矩阵加载到透视矩阵对阵中
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

    // 初始化渲染管线。
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}


// 键位设置,通过不同的键位对其进行设置
//控制Camera的移动,从而改变视口。
void SpecialKeys(int key, int x, int y)
{
    //设置移动的分量
    float linear = 0.1f;
    //设置旋转的分量
    float angular = float(m3dDegToRad(5.0f));
    //注意其如何对Camera进行操作
    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.0f, 1.0f, 0.0f);

    if (key == GLUT_KEY_RIGHT)
        cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
}

// Called to draw scene
void RenderScene(void)
{
    //三种渲染颜色
    static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f };
    static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    static GLfloat vSphereColor[] = { 0.0f, 0.0f, 1.0f, 1.0f };

    // 计时器,从而做出基础动画
    static CStopWatch   rotTimer;
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;

    // 清除缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


    // 装载当前的单位矩阵
    modelViewMatrix.PushMatrix();
    //创建一个矩阵作为摄像机矩阵 
    M3DMatrix44f mCamera;
    //这个函数用来检索条件适合的照相机矩阵并且初始化给mCamera。
    cameraFrame.GetCameraMatrix(mCamera);
    //将照相机矩阵压入模型矩阵堆栈
    modelViewMatrix.PushMatrix(mCamera);

    // 绘制地面
    shaderManager.UseStockShader(GLT_SHADER_FLAT,
        transformPipeline.GetModelViewProjectionMatrix(),
        vFloorColor);
    floorBatch.Draw();

    // 绘制花拖进行移动
    modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);

    // 对上面的操作进行保存
    modelViewMatrix.PushMatrix();

    // 旋转一个角度。
    modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),
        vTorusColor);
    torusBatch.Draw();
    modelViewMatrix.PopMatrix(); //去掉Rotate的操作

     // 应用一个其他的球体,并且对它进行移动。
    modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
    modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),
        vSphereColor);
    sphereBatch.Draw();

    // Restore the previous modleview matrix (the identity matrix)
    modelViewMatrix.PopMatrix();
    modelViewMatrix.PopMatrix();
    // 因为是GLUT_DOUBLE,所以需要后台渲染,再交换到前台
    glutSwapBuffers();

    // 手动刷新
    glutPostRedisplay();
}




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

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 600);

    glutCreateWindow("OpenGL SphereWorld");

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

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }


    SetupRC();
    glutMainLoop();
    return 0;
}

(5)对世界渲染更多事物
渲染多个物体所遵循的原则和上面基本一致:
先渲染静态物体
再渲染动态物体
动态物体注意不断pop矩阵堆栈
摄像机矩阵添加到模型视图矩阵队列
投影矩阵添加到投影视图矩阵队列

#pragma comment(lib,"GLTools.lib")

#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLFrame.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>

#include <math.h>
#include <stdio.h>


#include <GL/glut.h>


#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];


GLShaderManager     shaderManager;          // 渲染管理器
GLMatrixStack       modelViewMatrix;        // 模型渲染矩阵
GLMatrixStack       projectionMatrix;       // 投影矩阵
GLFrustum           viewFrustum;            // 视图矩阵
GLGeometryTransform transformPipeline;      // 渲染管线

GLTriangleBatch     torusBatch;
GLBatch             floorBatch;
GLTriangleBatch     sphereBatch;
GLFrame             cameraFrame;

//
// 渲染环境初始化
void SetupRC()
{
    // 渲染器管理器初始化
    shaderManager.InitializeStockShaders();
    //开启深度检测
    glEnable(GL_DEPTH_TEST);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    //设置黑色为背景颜色
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    // 创建花拖
    gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);

    // 创建球体
    gltMakeSphere(sphereBatch, 0.1f, 26, 13);

    //创建地面
    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();

    // 随机分配相关的x、z位置
    for (int i = 0; i < NUM_SPHERES; i++) {
        GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        //注意这个函数,设置其位置
        spheres[i].SetOrigin(x, 0.0f, z);
    }
}


///
// 屏幕改变的时候需要调节的参数
void ChangeSize(int nWidth, int nHeight)
{
    glViewport(0, 0, nWidth, nHeight);

    // 对GLFrustum生成投影矩阵
    viewFrustum.SetPerspective(35.0f, float(nWidth) / float(nHeight), 1.0f, 100.0f);
    //把投影矩阵压入相关的投影矩阵堆栈
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

    // 初始化渲染管线
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}


// 实际渲染的方式
void RenderScene(void)
{
    // 设置相应的颜色参数
    static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f };
    static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    static GLfloat vSphereColor[] = { 0.0f, 0.0f, 1.0f, 1.0f };

    // 计时器的计算
    static CStopWatch   rotTimer;
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;

    // 清楚相关的缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


    // 对模型矩阵压入单位矩阵
    modelViewMatrix.PushMatrix();

    //设置一个Camera矩阵
    M3DMatrix44f mCamera;
    //对于创建的角色帧得到符合条件的摄像机矩阵
    cameraFrame.GetCameraMatrix(mCamera);
    //把得到的摄像机矩阵压入对应的模型矩阵
    modelViewMatrix.PushMatrix(mCamera);

    // 利用平面渲染器渲染地面,同时把模型视图矩阵传递给渲染器
    shaderManager.UseStockShader(GLT_SHADER_FLAT,
        transformPipeline.GetModelViewProjectionMatrix(),
        vFloorColor);
    floorBatch.Draw();

    //对于球体进行相应的渲染
    for (int i = 0; i < NUM_SPHERES; i++) {
        //模型视图矩阵压入矩阵
        //把球体的渲染信息压入模型视图矩阵
        modelViewMatrix.PushMatrix();
        //对于球体进行渲染
        modelViewMatrix.MultMatrix(spheres[i]);                       
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),
            vSphereColor);
        sphereBatch.Draw();
        modelViewMatrix.PopMatrix();
        //每一次渲染之后,都需要对矩阵堆栈进行弹出
        //清理之前的操作矩阵,并且向其中压入新的操作矩阵

    }
    //渲染静态物体结束

    //开始渲染动态物体
    //向模型视图矩阵堆栈传递位置矩阵
    modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);

    // 保存其操作
    modelViewMatrix.PushMatrix();

    // 应用旋转
    modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),
        vTorusColor);
    torusBatch.Draw();
    modelViewMatrix.PopMatrix(); //清空当前旋转操作矩阵

    // 应用另外一个旋转矩阵
    modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
    modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),
        vSphereColor);
    sphereBatch.Draw();

    // 让矩阵堆栈回到初始默认状态,单位矩阵。
    modelViewMatrix.PopMatrix();
    modelViewMatrix.PopMatrix();
    // 交换渲染区
    glutSwapBuffers();

    // 手动渲染
    glutPostRedisplay();
}


// 通过按键来完成对相机的操作。
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.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_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 600);

    glutCreateWindow("OpenGL SphereWorld");

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

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }


    SetupRC();
    glutMainLoop();
    return 0;
}

(6)光线渲染

关于光线的设置。需要设置一个光源矩阵。
并且把光源矩阵和之前得到的 GetCameraMatrix(mCamera)做Transform操作,得到一个结果矩阵。
然后把结果矩阵传入到对应的渲染器当中作为一个重要参数。参考之前的《基础渲染》文章,当中的诸多渲染器方法可供选择,选择一个可行的方式对想要操作的对象进行渲染。

#pragma comment(lib,"GLTools.lib")
#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLFrame.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>

#include <math.h>
#include <stdio.h>
#include <GL/glut.h>


#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];


GLShaderManager     shaderManager;          // Shader Manager
GLMatrixStack       modelViewMatrix;        // Modelview Matrix
GLMatrixStack       projectionMatrix;       // Projection Matrix
GLFrustum           viewFrustum;            // View Frustum
GLGeometryTransform transformPipeline;      // Geometry Transform Pipeline

GLTriangleBatch     torusBatch;
GLBatch             floorBatch;
GLTriangleBatch     sphereBatch;
GLFrame             cameraFrame;

//
// This function does any needed initialization on the rendering
// context. 
void SetupRC()
{

    shaderManager.InitializeStockShaders();

    glEnable(GL_DEPTH_TEST);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);


    gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);


    gltMakeSphere(sphereBatch, 0.1f, 26, 13);

    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();


    for (int i = 0; i < NUM_SPHERES; i++) {
        GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        spheres[i].SetOrigin(x, 0.0f, z);
    }
}


///

void ChangeSize(int nWidth, int nHeight)
{
    glViewport(0, 0, nWidth, nHeight);


    viewFrustum.SetPerspective(35.0f, float(nWidth) / float(nHeight), 1.0f, 100.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}



void RenderScene(void)
{

    static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f };
    static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    static GLfloat vSphereColor[] = { 0.0f, 0.0f, 1.0f, 1.0f };


    static CStopWatch   rotTimer;
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;


    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);



    modelViewMatrix.PushMatrix();

    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.PushMatrix(mCamera);

    // 设置光源位置。注意,光源位置的全局坐标系存储在vLightPos
    //包含了光源位置的x、y、z和w坐标。
    M3DVector4f vLightPos = { 0.0f, 10.0f, 5.0f, 1.0f };
    M3DVector4f vLightEyePos; //最终传入到渲染器的矩阵
    //m3dTransformVector4使用该函数对光源位置进行变换
    m3dTransformVector4(vLightEyePos, vLightPos, mCamera);

    //注意地板的渲染器是平面渲染器
    shaderManager.UseStockShader(GLT_SHADER_FLAT,
        transformPipeline.GetModelViewProjectionMatrix(),
        vFloorColor);
    floorBatch.Draw();
    //而对于其他的模型使用点光源渲染器
    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(), vLightEyePos, vSphereColor);
        //注意传入的参数:模型视图矩阵、投影矩阵、光纤位置、渲染的漫反射颜色

        sphereBatch.Draw();
        modelViewMatrix.PopMatrix();
    }


    modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);


    modelViewMatrix.PushMatrix();


    modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
        transformPipeline.GetProjectionMatrix(), vLightEyePos, vTorusColor);
    torusBatch.Draw();
    modelViewMatrix.PopMatrix(); // 删除之前的参数


    modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
    modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
        transformPipeline.GetProjectionMatrix(), vLightEyePos, vSphereColor);
    sphereBatch.Draw();

    // 弹出之前所做的操作
    modelViewMatrix.PopMatrix();
    modelViewMatrix.PopMatrix();
    // 因为是双渲染管道,需要交换后台和前台的渲染信息。
    glutSwapBuffers();

    //手动渲染
    glutPostRedisplay();
}


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.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_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 600);

    glutCreateWindow("OpenGL SphereWorld");

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

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }


    SetupRC();
    glutMainLoop();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值