OpenGL--代码解读

// SphereWorld.cpp
// OpenGL SuperBible
// New and improved (performance) sphere world
// Program by Richard S. Wright Jr.

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 

#ifdef __APPLE__
#include 
#else
#define FREEGLUT_STATIC
#include 
#endif

#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()
    {
    // Initialze Shader Manager
    shaderManager.InitializeStockShaders();

    glEnable(GL_DEPTH_TEST);

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

    // This makes a torus
    gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);

    // This make a sphere
    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();    

    // Randomly place the spheres
    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);
        }
    }


///////////////////////////////////////////////////
// Screen changes size or is initialized
void ChangeSize(int nWidth, int nHeight)
    {
    glViewport(0, 0, nWidth, nHeight);

    // Create the projection matrix, and load it on the projection matrix stack
    viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

    // Set the transformation pipeline to use the two matrix stacks 
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    }


// Called to draw scene
void RenderScene(void)
    {
    // Color values
    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 };

    // Time Based animation
    static CStopWatch   rotTimer;
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;

    // Clear the color and depth buffers
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


    // Save the current modelview matrix (the identity matrix)
    modelViewMatrix.PushMatrix();   

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

    // Transform the light position into eye coordinates
    M3DVector4f vLightPos = { 0.0f, 10.0f, 5.0f, 1.0f };
    M3DVector4f vLightEyePos;
    m3dTransformVector4(vLightEyePos, vLightPos, mCamera);

    // Draw the ground
    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();
        }

    // Draw the spinning Torus
    modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);

    // Save the Translation
    modelViewMatrix.PushMatrix();

        // Apply a rotation and draw the torus
        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(); // "Erase" the Rotation from before

    // Apply another rotation, followed by a translation, then draw the sphere
    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();

    // Restore the previous modleview matrix (the identity matrix)
    modelViewMatrix.PopMatrix();
    modelViewMatrix.PopMatrix();    
    // Do the buffer Swap
    glutSwapBuffers();

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


// Respond to arrow keys by moving the camera frame of reference
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;
    }

上面是源码,我分析下各个函数各行代码的作用,帮助自己理解下OpenGL的大致结构。
首先是一些头文件的包含,因为会用到OpenGL的一些API。
GLShaderManager是着色管理器,没有着色管理器,就没法着色;作色存储器还提供存储着色器,能够进行一些初步和基本的渲染操作。
在Mac和Windows|Linux上,我们将会采用不同的处理器宏定义

#ifdef __APPLE__
#include 
#else
#define FREEGLUT_STATIC
#include 
#endif

main()函数作为程序的入口函数,得先从这边来分析。

gltSetWorkingDirectory(argv[0]);

上函数是用来设置当前工作目录。

//传递命令行参数并初始化GLUT库
glutInit(&argc, argv);
//告诉GLUT库,在创建窗口时要使用哪种类型的显示模式
//GLUT_DOUBLE表示使用双缓冲窗口,一般用来生成动画效果
//GLUT_RGB表示使用RGB颜色模式
//GLUT_DEPTH表示我们可以进行深度测试
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
//指明GLUT窗口的大小,并以OpenGL SphereWorld为标题创建窗口。
glutInitWindowSize(800,600);
glutCreateWindow("OpenGL SphereWorld");

GLUT内部运行一个本地消息循环,拦截适当的消息,然后调用相应的回调函数。我们必须为窗口改变大小而设置一个回调函数,以便能够设置视点,还要注册一个函数来包含OpenGL渲染代码。如下:

glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);

初始化OpenGL驱动程序,并检查初始化是否出现问题

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

在任何OpenGL函数起作用之前都得创建一个渲染环境,在这个函数里面我们会进行预加载纹理,建立几何图形、渲染器等工作。

SetupRC();

开始上面讲过的本地消息循环,并结束main函数。

glutMainLoop();    
return 0;

glutMainLoop函数被调用之后,在主窗口被关闭之前都不会返回,一个应用程序只需要调用一次。这个函数负责处理所有操作系统特定的消息、按键动作等,直到我们关闭程序为止。它还能确保我们的这些回调函数被正确地调用。
ChangeSize函数中:

glViewport(x, y, w, h)

定义窗口与视口之间的关系,x参数和y参数代表窗口中视口的左下角坐标,w和h代表视口的宽带和高度,如下图所示:
OpenGL--代码解读_第1张图片

glViewport(0, 0, nWidth, nHeight);

SetupRC中:
glClearColor是用来设置背景颜色,该函数不会立即清除背景,而是设置在以后颜色缓冲区被清除时(调用glClear函数)使用的颜色。

glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

当设置OpenGL窗口时,我们制定要一个双缓冲渲染环境。这就意味着将在后台缓冲区进行渲染,然后结束的时候交换到前台缓冲区。这种形式能够防止观察者可能看到伴随着动画帧与动画帧之间闪烁的渲染过程。OpenGL有一个特定的函数来完成上述工作:

glutSwapBuffers();

刷新显示:告诉窗口需要更新内容

glutPostRedisplay

该函数来告诉GLUT发生了某些变化,应该对场景重新进行渲染

你可能感兴趣的:(OpengGL)