// Primitieves.cpp
// OpenGL SuperBible, Chapter 2
// Demonstrates the 7 Geometric Primitives
// Program by Richard S. Wright Jr.
#include
// OpenGL toolkit
#include
#include
#include
#include
#include
#include
#ifdef __APPLE__ #include
#else #define FREEGLUT_STATIC #include
#endif / // An assortment of needed classes GLShaderManager shaderManager; GLMatrixStack modelViewMatrix; GLMatrixStack projectionMatrix; GLFrame cameraFrame; GLFrame objectFrame; GLFrustum viewFrustum; GLBatch pointBatch; GLBatch lineBatch; GLBatch lineStripBatch; GLBatch lineLoopBatch; GLBatch triangleBatch; GLBatch triangleStripBatch; GLBatch triangleFanBatch; GLGeometryTransform transformPipeline; M3DMatrix44f shadowMatrix; GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f }; GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f }; // Keep track of effects step int nStep = 0; /// // This function does any needed initialization on the rendering context. // This is the first opportunity to do any OpenGL related tasks. void SetupRC() { // 设置背景色,刷新后生效 glClearColor(0.7f, 0.7f, 0.7f, 1.0f); shaderManager.InitializeStockShaders();//使用存储着色器必须先初始化 glEnable(GL_DEPTH_TEST);//启动深度测试 -- 绘制z值最小的像素点 // 设置变换管transformPipeline线的矩阵堆栈 试图模型矩阵 投影矩阵 管线可以理解为一些列操作的集合 .SetMatrixStacks(modelViewMatrix, projectionMatrix);//2个矩阵对象也管线产生关联绑定 // GLFrame--帧 就是一张图片,一个照片,所以是照相机对象 cameraFrame.MoveForward(-10.0f);//移动相机,观察点不便,将相机向远处(后面)移动 // // Some points, more or less in the shape of Florida GLfloat vCoast[24][3] = { { 2.80, 1.20, 0.0 }, { 2.0, 1.20, 0.0 }, { 2.0, 1.08, 0.0 }, { 2.0, 1.08, 0.0 }, { 0.0, 0.80, 0.0 }, { -.32, 0.40, 0.0 }, { -0.48, 0.2, 0.0 }, { -.40, 0.0, 0.0 }, { -0.60, -.40, 0.0 }, { -.80, -.80, 0.0 }, { -0.80, -1.4, 0.0 }, { -.40, -1.60, 0.0 }, { 0.0, -1.20, 0.0 }, { .2, -.80, 0.0 }, { 0.48, -.40, 0.0 }, { .52, -.20, 0.0 }, { 0.48, 0.20, 0.0 }, { .80, .40, 0.0 }, { 1.20, 0.80, 0.0 }, { 1.60, 0.60, 0.0 }, { 2.0, .60, 0.0 }, { 2.2,0.80, 0.0 }, { 2.40, 1.0, 0.0 }, { 2.80, 1.0, 0.0 } }; //这里是为绘制的一批顶点绘图对象赋值,可以理解为绘制好了一个自定义的空间 //放到了工具箱(缓冲),等需要的时候在放到场景(窗口)中 //为顶点光栅化变量赋值,用于将顶点光栅化 // Load point batch pointBatch.Begin(GL_POINTS, 24); pointBatch.CopyVertexData3f(vCoast); pointBatch.End(); // Load as a bunch of line segments lineBatch.Begin(GL_LINES, 24); lineBatch.CopyVertexData3f(vCoast); lineBatch.End(); // Load as a single line segment lineStripBatch.Begin(GL_LINE_STRIP, 24); lineStripBatch.CopyVertexData3f(vCoast); lineStripBatch.End(); // Single line, connect first and last points lineLoopBatch.Begin(GL_LINE_LOOP, 24); lineLoopBatch.CopyVertexData3f(vCoast); lineLoopBatch.End(); // For Triangles 三角形, we'll make a Pyramid 金字塔 GLfloat vPyramid[12][3] = { -2.0f, 0.0f, -2.0f, 2.0f, 0.0f, -2.0f, 0.0f, 4.0f, 0.0f, 2.0f, 0.0f, -2.0f, 2.0f, 0.0f, 2.0f, 0.0f, 4.0f, 0.0f, 2.0f, 0.0f, 2.0f, -2.0f, 0.0f, 2.0f, 0.0f, 4.0f, 0.0f, -2.0f, 0.0f, 2.0f, -2.0f, 0.0f, -2.0f, 0.0f, 4.0f, 0.0f }; triangleBatch.Begin(GL_TRIANGLES, 12); triangleBatch.CopyVertexData3f(vPyramid); triangleBatch.End(); // For a Triangle fan, just a 6 sided hex. Raise the center up a bit GLfloat vPoints[100][3]; // Scratch array, more than we need int nVerts = 0; GLfloat r = 3.0f; vPoints[nVerts][0] = 0.0f; vPoints[nVerts][1] = 0.0f; vPoints[nVerts][2] = 0.0f; //如果需要绘制特定几何图形的话,得首先绘制特定几何图形的顶点, //顶点如何绘制呢,就需要相应的数学知识绘制出来即可 for (GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) { nVerts++; vPoints[nVerts][0] = float(cos(angle)) * r; vPoints[nVerts][1] = float(sin(angle)) * r; vPoints[nVerts][2] = -1.5f; } // Close the fan nVerts++; vPoints[nVerts][0] = r; vPoints[nVerts][1] = 0; vPoints[nVerts][2] = 0.0f; // Load it up triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8); triangleFanBatch.CopyVertexData3f(vPoints); triangleFanBatch.End(); // For triangle strips, a little ring or cylinder segment int iCounter = 0; GLfloat radius = 3.0f; for (GLfloat angle = 0.0f; angle <= (2.0f*M3D_PI); angle += 0.3f) { GLfloat x = radius * sin(angle); GLfloat y = radius * cos(angle); // Specify the point and move the Z value up a little vPoints[iCounter][0] = x; vPoints[iCounter][1] = y; vPoints[iCounter][2] = -0.5;//物体模型本身顶点向后 iCounter++; vPoints[iCounter][0] = x; vPoints[iCounter][1] = y; vPoints[iCounter][2] = 0.5;//物体模型本身顶点向前 iCounter++; } // Close up the loop vPoints[iCounter][0] = vPoints[0][0]; vPoints[iCounter][1] = vPoints[0][1]; vPoints[iCounter][2] = -0.5; iCounter++; vPoints[iCounter][0] = vPoints[1][0]; vPoints[iCounter][1] = vPoints[1][1]; vPoints[iCounter][2] = 0.5; iCounter++; // Load the triangle strip triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter); triangleStripBatch.CopyVertexData3f(vPoints); triangleStripBatch.End(); } / void DrawWireFramedBatch(GLBatch* pBatch) { // Draw the batch solid green shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen); pBatch->Draw(); // Draw black outline glPolygonOffset(-1.0f, -1.0f); // Shift depth values glEnable(GL_POLYGON_OFFSET_LINE); // Draw lines antialiased glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Draw black wireframe version of geometry glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glLineWidth(2.5f); shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack); pBatch->Draw(); // Put everything back the way we found it glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable(GL_POLYGON_OFFSET_LINE); glLineWidth(1.0f); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); } /// // Called to draw scene void RenderScene(void) { // 函数原型: // void glClear(GLbitfield mask); // 参数说明: // GLbitfield:可以使用 | 运算符组合不同的缓冲标志位,表明需要清除的缓冲, // 例如glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) // 表示要清除颜色缓冲以及深度缓冲,可以使用以下标志位 // GL_COLOR_BUFFER_BIT : 当前可写的颜色缓冲 // GL_DEPTH_BUFFER_BIT : 深度缓冲 // GL_ACCUM_BUFFER_BIT : 累积缓冲 // GL_STENCIL_BUFFER_BIT : 模板缓冲 // 函数说明: // glClear()函数的作用是用当前缓冲区清除值,也就是glClearColor或者glClearDepth、 // glClearIndex、glClearStencil、glClearAccum等函数所指定的值来清除指定的缓冲区, // 也可以使用glDrawBuffer一次清除多个颜色缓存。比如: // glClearColor(0.0,0.0,0.0,0.0); // glClear(GL_COLOR_BUFFER_BIT); // 第一条语句表示清除颜色设为黑色,第二条语句表示实际完成了把整个窗口清除为黑色的任务, // glClear()的唯一参数表示需要被清除的缓冲区。 // 像素检验、裁剪检验、抖动和缓存的写屏蔽都会影响glClear的操作,其中,裁剪范围限制了清除的区域, // 而glClear命令还会忽略alpha函数、融合函数、逻辑操作、模板、纹理映射和z缓存; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // glTranslatef(1, 0, 0);//向右移动(1,0,0) // glPushMatrix();//保存当前位置 // glTranslatef(0, 1, 0);//如今是(1,1,0)了 // glPopMatrix();//这样,如今又回到(1,0,0)了 modelViewMatrix.PushMatrix(); M3DMatrix44f mCamera; cameraFrame.GetCameraMatrix(mCamera); modelViewMatrix.MultMatrix(mCamera); M3DMatrix44f mObjectFrame; objectFrame.GetMatrix(mObjectFrame);//GLFrame objecctFrame关联mObjectFrame, modelViewMatrix.MultMatrix(mObjectFrame);//modelViewMatrix关联mObjectFrame即modelViewMatrix关联objectFrame shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack); switch (nStep) { case 0: glPointSize(4.0f); pointBatch.Draw(); glPointSize(1.0f); break; case 1: glLineWidth(2.0f); lineBatch.Draw(); glLineWidth(1.0f); break; case 2: glLineWidth(2.0f); lineStripBatch.Draw(); glLineWidth(1.0f); break; case 3: glLineWidth(2.0f); lineLoopBatch.Draw(); glLineWidth(1.0f); break; case 4: DrawWireFramedBatch(&triangleBatch); break; case 5: DrawWireFramedBatch(&triangleStripBatch); break; case 6: DrawWireFramedBatch(&triangleFanBatch); break; } modelViewMatrix.PopMatrix(); // Flush drawing commands glutSwapBuffers(); } // Respond to arrow keys by moving the camera frame of reference void SpecialKeys(int key, int x, int y) { if (key == GLUT_KEY_UP) objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f); if (key == GLUT_KEY_DOWN) objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f); if (key == GLUT_KEY_LEFT) objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f); if (key == GLUT_KEY_RIGHT) objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f); glutPostRedisplay(); } /// // A normal ASCII key has been pressed. // In this case, advance the scene when the space bar is pressed void KeyPressFunc(unsigned char key, int x, int y) { if (key == 32) { nStep++; if (nStep > 6) nStep = 0; } switch (nStep) { case 0: glutSetWindowTitle("GL_POINTS"); break; case 1: glutSetWindowTitle("GL_LINES"); break; case 2: glutSetWindowTitle("GL_LINE_STRIP"); break; case 3: glutSetWindowTitle("GL_LINE_LOOP"); break; case 4: glutSetWindowTitle("GL_TRIANGLES"); break; case 5: glutSetWindowTitle("GL_TRIANGLE_STRIP"); break; case 6: glutSetWindowTitle("GL_TRIANGLE_FAN"); break; } glutPostRedisplay(); } /// // Window has changed size, or has just been created. In either case, we need // to use the window dimensions to set the viewport and the projection matrix. void ChangeSize(int w, int h) { glViewport(0, 0, w, h); // 计算截锥体的角,并设置投影矩阵。 // 透视投影矩阵 // 设置为3D投影模式 viewFrustum.SetPerspective(45.0f, float(w) / float(h), 1.0f, 500.0f); projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); // Description描述 // 加载一个单位矩阵到当前的模型视图矩阵。 // 改变模型视图矩阵会覆盖当前的camera' 的参数,许多情况下你需要用到GL.PushMatrix 和GL.PopMatrix矩阵函数.来保存和恢复。 modelViewMatrix.LoadIdentity(); } /// // Main entry point for GLUT based programs 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("GL_POINTS"); glutReshapeFunc(ChangeSize);//相当于MFC里面的OnSize glutKeyboardFunc(KeyPressFunc);//相当于MFC里面的键盘接受事件消息 glutSpecialFunc(SpecialKeys);//相当于MFC里面的特定键盘接受事件消息 上下左右 glutDisplayFunc(RenderScene);//相当于MFC里面的OnRepint()回调函数,相当于Cocos2d-x里面的update GLenum err = glewInit(); if (GLEW_OK != err) { fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err)); return 1; } SetupRC(); glutMainLoop(); return 0; }