My OpenGL thematic learning directory, hope to learn with you exchange progress!

  • OpenGL Learning (I) – Terminology understanding
  • OpenGL learning (2) — Xcode build OpenGL environment
  • OpenGL learning (three) – OpenGL base rendering
  • OpenGL learning (4) – front & back culling and depth testing
  • OpenGL Learning (5) – Cropping and Blending
  • OpenGL Learning (6) – Base textures
  • OpenGL Learning (7) — Summary of basic change Comprehensive Exercise practice
  • OpenGL ES Learning (8)
  • OpenGL learning (nine) — OpenGL ES preliminary exploration (next) GLKit
  • OpenGL learning (10) – GLSL syntax introduction
  • OpenGL learning (11) – using GLSL to load pictures
  • OpenGL learning (12) — OpenGL ES texture flipping strategy comparison

One, foreword

The following I summarized some recent learning OpenGL commonly used in some functions, add more comments, not only to their own learning a consolidated summary, but also to prevent the future forgotten can quickly view the record, at the same time, I hope to help more friends in learning OpenGL.

Xcode has not yet built an OpenGL environment for friends can refer to my article to build OpenGL learning (2) — Xcode built OpenGL environment. There are also some basic OpenGL articles that I summarized earlier, which can be viewed in the table of contents at the top of the article.

Second, code + comments summary

1. Imported header files:

#include "GLTools.h"	// OpenGL toolkit
#include "GLMatrixStack.h"
#include "GLFrame.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLGeometryTransform.h"
#include "StopWatch.h"

#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
Copy the code

2, some common global variable declaration:

GLShaderManager		shaderManager;// Fix the pipeline manager

GLMatrixStack		modelViewMatrix;// Model view matrix stack

GLMatrixStack		projectionMatrix;// Projection view matrix stack

GLFrame				cameraFrame;// Observer position

GLFrame             objectFrame;// World coordinates

GLFrustum			viewFrustum;// Projection mode, technical name: viewframe. To construct the projection matrix.

GLBatch             triangleBatch;// A simple batch container is a simple container class for GLTools.

GLTriangleBatch     CC_Triangle;// Triangle batch class

GLTriangleBatch     sphereBatch;/ / the ball

GLTriangleBatch     torusBatch;/ / ring

GLTriangleBatch     cylinderBatch;/ / cylindrical

GLTriangleBatch     coneBatch;/ / cone

GLTriangleBatch     diskBatch;/ / disk

GLGeometryTransform	transformPipeline; // Transform pipe is used to manage projection and model matrix

GLfloat vGreen[] = {0.0 f.1.0 f.0.0 f.1.0 f };// Define a color value, green

Copy the code

3, main function: program entry Settings

int main(int argc,char *argv[]) {
    // Set the current working directory for MAC OS X
    /* 'GLTools' function' glSetWorkingDrectory 'sets the current working directory. In fact, this is not necessary in Windows because the working directory is the same directory as the program executable by default. But on Mac OS X, this program changes the current working folder to the '/Resource' folder in the application bundle. The 'GLUT' priority setting does this automatically, but the method is more secure. * /
    gltSetWorkingDirectory(argv[0]);
    
   
    // Initialize GLUT library. This function simply passes command arguments and initializes GLUT library
    glutInit(&argc, argv);
    
    /* Initialize the double buffer window, where GLUT_DOUBLE, GLUT_RGBA, GLUT_DEPTH, GLUT_STENCIL indicate the double buffer window, RGBA color mode, depth test, and template buffer, respectively. Double-cached Windows, where a drawing command is actually executed off-screen from the cache and then quickly converted to a window view, are often used to generate animation effects; --GLUT_DEPTH ': flag allocates a depth cache as part of the display, so we can perform a depth test; GLUT_STENCIL: Make sure we also have a template cache available. Depth and template testing will be covered in more detail */
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    
    //GLUT window size, window title
    glutInitWindowSize(800.600);
    glutCreateWindow("Triangle");
    
    /* GLUT internally runs a local message loop that intercepts the appropriate message. Then call the callback function that we registered at different times. We registered two callback functions: 1) a callback for window resizing and 2) a callback that contains OpenGL rendering */
    // Register the remodeling function
    glutReshapeFunc(changeSize);
    // Register the display function
    glutDisplayFunc(RenderScene);
    
    glutSpecialFunc(SpeacialKeys);
    
    /* Initialize a GLEW library to ensure that the OpenGL API is fully available to the program. Before attempting to do any rendering, check to make sure there are no problems with driver initialization */
    GLenum status = glewInit();
    if(GLEW_OK ! = status) {printf("GLEW Error:%s\n",glewGetErrorString(status));
        return 1;
        
    }
    
    // Set up our render environment
    setupRC();
    
    glutMainLoop();

    return  0;    
}
Copy the code

ChangeSize (int w, int h);

Resize function, a callback function set for window resizing to receive new width & height when the window resizes. The glutReshapeFunc function is registered in the main function: glutReshapeFunc(changeSize); // Register the remodeling function

/* Receives new width & height when the window size changes. * /
void changeSize(int w,int h) {
    /* 1. Set the window coordinate x,y parameter represents the coordinate of the lower left corner of the view in the window, width and height are represented by pixels, usually x and y are 0 */
    // Prevent h from going to 0
    if(h == 0){
        h = 1;
    }
    glViewport(0.0, w, h);

    / / 2,
    // If you are drawing a solid shape, you also need to set perspective projection
    // Perspective projection
    // Parameter 1: Field of view Angle from vertex direction (Angle value)
    // Parameter 2: aspect ratio of width and height
    // Parameter 3: fNear
    // Parameter 4: fFar
    viewFrustum.SetPerspective(35.0 f.float(w) / float(h), 1.0 f.500.0 f);
    
    / / 3.
    // We just set it up but it doesn't work, we need to convert it to a matrix and take the result back.
    // load a matrix into the projectionMatrix stack projectionMatrix, and get the projectionMatrix GetProjectionMatrix() from our viewbody viewFrustum
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    
    / / 4.
    // The model view matrix is used for rotation, translation, etc. There is no change here, so just load a element matrix.
    // Add a cell matrix to the modelViewMatrix stack
    modelViewMatrix.LoadIdentity();
}
Copy the code

5, KeyPressFunc click the space function:

Each time you click on a space, switch the title of the window and re-render the graphics

// Click space to toggle rendering graphics
void KeyPressFunc(unsigned char key, int x, int y) {
    if(key == 32) {
        nStep++;
        if(nStep > 4)
            nStep = 0;
    }
    
    switch(nStep) {
        case 0:
            glutSetWindowTitle("Sphere");
            break;
        case 1:
            glutSetWindowTitle("Torus");
            break;
        case 2:
            glutSetWindowTitle("Cylinder");
            break;
        case 3:
            glutSetWindowTitle("Cone");
            break;
        case 4:
            glutSetWindowTitle("Disk");
            break;
    }
    
    glutPostRedisplay();
}
Copy the code

SpecialKeys function

Click up, down, left, and right on the keyboard to change the world coordinate system (not the object itself)

// Move the world coordinate system up, down, left, and right
void SpecialKeys(int key, int x, int y) {
    if(key == GLUT_KEY_UP)
        // Move the world coordinate system instead of moving objects.
        // Move the world coordinate system to -5.0 in the X direction
        objectFrame.RotateWorld(m3dDegToRad(5.0 f), 1.0 f.0.0 f.0.0 f);
    
    if (key == GLUT_KEY_DOWN)
        objectFrame.RotateWorld(m3dDegToRad(5.0 f), 1.0 f.0.0 f.0.0 f);
    
    if (key == GLUT_KEY_LEFT)
        objectFrame.RotateWorld(m3dDegToRad(5.0 f), 0.0 f.1.0 f.0.0 f);
    
    if (key == GLUT_KEY_RIGHT)
        objectFrame.RotateWorld(m3dDegToRad(5.0 f), 0.0 f.1.0 f.0.0 f);
    
    glutPostRedisplay();
}
Copy the code

SetupRC()

Do the necessary initialization to set up our render environment, called in the main function. This is usually used to describe what the shape we want to render looks like. The real time to draw is not here, but in the RenderScene() function, which WE’ll talk about later.

// Place the necessary initialization in the context
void SetupRC(a) {
    // 1. Set the background color
    glClearColor(0.7 f.0.7 f.0.7 f.1.0 f );

    // 2. Initialize the fixed shader manager
    shaderManager.InitializeStockShaders();

    // 3. Enable depth testing when drawing stereo graphics
    glEnable(GL_DEPTH_TEST);

    // Manage matrix stack with GLGeometryTransform
    // Manage the model view matrix stack and projection matrix stack using transformPipeline.
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

    // 5. For obvious effect, move the observer position Z 15 units to the screen
    // Parameter: indicates the distance from the screen. Negative numbers are moving behind the screen; Positive, move to the front of the screen
    cameraFrame.MoveForward(15.0 f);

/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- GLTriangleBatch type -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -

    // Use the triangle batch class of type "GLTriangleBatch" to construct the graphics object. The GLTriangleBatch type encapsulates many commonly used stereo graphics.
    / / 1, the ball
    /* gltMakeSphere(GLTriangleBatch& sphereBatch, GLfloat fRadius, GLint iSlices, GLint iStacks); Parameter 1: sphereBatch, triangle batch class object parameter 2: fRadius, sphere radius parameter 3: iSlices, the number of triangle strips stacked from the bottom of the sphere to the top; It is suggested that the number of fragments of a sphere with good symmetry is twice the number of stacked fragments, that is, iStacks = 2 * iSlices. Parameter 4 is twice the number of parameter 3. The spheres are drawn around the z-axis so that + Z is the vertex of the sphere and -z is the bottom of the sphere. * /
    gltMakeSphere(sphereBatch, 3.0.10.20);

    // 2, torus
    /* gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor); Parameter 1: torusBatch, triangle batch class object parameter 2: majorRadius, the radius from the center of the doughnut to the outer edge parameter 3: minorRadius, the radius from the center of the doughnut to the inner edge parameter 4: numMajor, the number of triangles along the main radius parameter 5: NumMinor, the number of triangles along the inner smaller radius */
    gltMakeTorus(torusBatch, 3.0 f.0.75 f.15.15);
    
    // 3
    /* void gltMakeCylinder(GLTriangleBatch& cylinderBatch, GLfloat baseRadius, GLfloat topRadius, GLfloat fLength, GLint numSlices, GLint numStacks); Parameter 1: cylinderBatch, triangle batch class object parameter 2: baseRadius, baseRadius parameter 3: topRadius, head radius parameter 4: fLength, circular length parameter 5: numSlices, number of triangle pairs around the z-axis parameter 6: NumStacks, the number of triangles that stack the bottom of a cylinder into the top ring */
    gltMakeCylinder(cylinderBatch, 2.0 f.2.0 f.3.0 f.15.2);
    
    / / 4, cone
    /* void gltMakeCylinder(GLTriangleBatch& cylinderBatch, GLfloat baseRadius, GLfloat topRadius, GLfloat fLength, GLint numSlices, GLint numStacks); Parameter 1: cylinderBatch, triangle batch class object parameter 2: baseRadius, baseRadius parameter 3: topRadius, head radius parameter 4: fLength, circular length parameter 5: numSlices, number of triangle pairs around the z-axis parameter 6: NumStacks, the number of triangles that stack the bottom of a cylinder into the top ring */
    // A cylinder extends from 0 to the positive direction of the Z axis.
    // The radius of one end is 0, and the radius of the other end can be specified.
    gltMakeCylinder(coneBatch, 2.0 f.0.0 f.3.0 f.13.2);
    
    // 5
    /* void gltMakeDisk(GLTriangleBatch& diskBatch, GLfloat innerRadius, GLfloat outerRadius, GLint nSlices, GLint nStacks);  Parameter 1:diskBatch, triangle batch object parameter 2:innerRadius, innerRadius parameter 3:outerRadius, outerRadius parameter 4:nSlices, number of triangle pairs around the Z axis of the disk 5:nStacks, number of triangles from the outer network to the inner circle of the disk */
    gltMakeDisk(diskBatch, 1.5 f.3.0 f.13.3);


/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- GLBatch type -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
// When using GLTriangleBatch code above, comment out the following code before running. The two pieces of code were originally separate, but were written together for convenience.

// Above is the triangle batch class of type "GLTriangleBatch", below we use the most basic triangle batch class of type "GLBatch" to draw the pyramid.
    // First create the triangle batch class and tell it how many vertices we need,
    
    The function BeginMesh(GLuint nMaxVerts)// specifies how many vertices there are
    CC_Triangle.BeginMesh(300);// Specify 300 vertices
    
    // 2. Create a vertex
    M3DVector3f m[] = {
        0.5.0.0.0.0.0.5.0.0.0.0.0.0.0.5.0.0
    };
    
    // 3. Copy the vertices to add them
    // Parameter 1: indicates the vertex coordinate value
    // parameter 2: indicates the normal coordinate value, NULL if no
    // Parameter 3: indicates the texture coordinate value, NULL if no
    CC_Triangle.AddTriangle(m, NULL.NULL);
    //CC_Triangle.CopyVertexData3f
    
    CC_Triangle.End();
    
    CC_Triangle.Draw();
// --------------------------------------------------------------
}
Copy the code

RenderScene() :

The function RenderScene() is called when the glutPostRedisplay() method is called for any change. GlutDisplayFunc (RenderScene) is registered in the main function.

Let me explain the code in detail:

  • (1) PushMatrix();

modelViewMatrix.PushMatrix(); If the parentheses of PushMatix() are empty, the matrix at the top of the stack is copied and pushed to the top. If it is not empty, such as the element matrix in parentheses, then it means pushing a element matrix to the top of the stack.

  • (2) Matrix multiplication MultMatrix(mObjectFrame)

The matrix in the modelViewMatrix stack is multiplied by the mOjbectFrame matrix and stored in the modelViewMatrix matrix stack. modelViewMatrix.MultMatrix(mObjectFrame); Copy the top matrix of the modelview matrix stack, multiply it by the new matrix, and assign the result to the top matrix.

  • (3) PopMatrix();

modelViewMatrix.PopMatrix(); Take the top matrix off the stack and restore it to the original matrix stack so that it does not affect subsequent operations.

Here is a flow chart of “Matrix loading, multiplying, and unloading” summarized by myself:

  • (4) cameraFrame. GetCameraMatrix (mCamera) :

cameraFrame.GetCameraMatrix(mCamera); This syntax is a little different from OC, which means that the matrix is taken from the observer frame cameraFrame and assigned to mCamera. Objectframe.getmatrix (mObjectFrame); . CameraFrame and mCamera are structures of type GLFrame.

Let’s look at the RenderScene() code:

// Call scene
void RenderScene(void) {
    //1. Clear a specific cache or group of caches
    /* A buffer is a block of storage space containing image information. The red, green, blue, and alpha components are often referenced together as color caches or pixel caches. More than one buffer in OpenGL (color cache, depth cache, and template cache) clears the cache to preset values: GL_COLOR_BUFFER_BIT: indicates the currently active buffer for color writing GL_DEPTH_BUFFER_BIT: indicates the depth buffer GL_STENCIL_BUFFER_BIT: indicates the template buffer */
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    // Model view matrix stack stack
    modelViewMatrix.PushMatrix();
    // Get the camera matrix
    M3DMatrix44f mCamera;
    // Get the matrix from camereaFrame to mCamera
    cameraFrame.GetCameraMatrix(mCamera);
    // The matrix of the modelview stack is multiplied by the mCamera matrix and stored in the modelViewMatrix matrix stack
    modelViewMatrix.MultMatrix(mCamera);
    
    // Create the matrix mObjectFrame
    M3DMatrix44f mObjectFrame;
    // Get the matrix from ObjectFrame into mOjectFrame
    objectFrame.GetMatrix(mObjectFrame);
    // Multiply the matrix in the modelViewMatrix stack by the mOjbectFrame matrix and store it in the modelViewMatrix stack
    modelViewMatrix.MultMatrix(mObjectFrame);
    
    // Use a flat shader
    // Parameter 1: type
    // Parameter 2: Obtain the model view matrix via transformPipeline
    // Parameter 3: color
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
    
    // Determine which graph you are currently drawing
// Note that the address passed here is &sphereBatch
    switch(nStep) {
        case 0:
            DrawWireFramedBatch(&sphereBatch);/ / the ball
            break;
        case 1:
            DrawWireFramedBatch(&torusBatch);/ / torus
            break;
        case 2:
            DrawWireFramedBatch(&cylinderBatch);/ / cylindrical
            break;
        case 3:
            DrawWireFramedBatch(&coneBatch);/ / cone
            break;
        case 4:
            DrawWireFramedBatch(&diskBatch);/ / disk
            break;
    }
    
    // When I'm done drawing, I need to pop out the matrix at the top of the stack
    modelViewMatrix.PopMatrix();
    
    // Flush drawing commands
    glutSwapBuffers();
}
Copy the code

DrawWireFramedBatch ();

void DrawWireFramedBatch(GLTriangleBatch* pBatch) {
    // Flat shader, draw triangle
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
   
    // The parameters to be passed correspond to different graphs Batch
    pBatch->Draw();
    
    // Draw the black outline
    glPolygonOffset(1.0 f.1.0 f);
    
    // Enable line segment smoothing
    glEnable(GL_LINE_SMOOTH);
    
    // Enable the blending function
    glEnable(GL_BLEND);
    
    // Color mix
    // The source color is multiplied by its alpha value, and the target color is multiplied by 1.0 minus the alpha value of the source color, so that the larger the alpha value of the source color is, the larger the proportion of the source color is, and the smaller the proportion of the target color is. In this case, we can simply interpret the alpha value of the source color as "opacity". This is the most common way to mix.
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    // Use the program point size mode to set the point size
    glEnable(GL_POLYGON_OFFSET_LINE);
    
    // Set the back of the polygon to wireframe mode
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    
    // Line width
    glLineWidth(2.5 f);
    
    // Flat shader draws lines
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
    
    pBatch->Draw();
    
    // Restore polygon mode and depth test
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glDisable(GL_POLYGON_OFFSET_LINE);
    glLineWidth(1.0 f);
    glDisable(GL_BLEND);
    glDisable(GL_LINE_SMOOTH);
}
Copy the code

The above summary refers to and partly extracts the following articles, thanks very much to the following authors for sharing! :

1. OpenGL Super Dictionary 5th Edition

2. OpenGL Programming Guide (Eighth Edition)

Reprint please note the original source, shall not be used for commercial communication – any more