opengl超级宝典(第五版)阅读笔记 3 基本图元的使用

基本图元有 GL_POINTS GL_LINES GL_LINE_STRIP GL_LINE_LOOP GL_TRIANGLES GL_TRIANGLE_LOOP GL_TRIANGLE_FAN.
后面将一 一对其进行简单的介绍
1.GL_POINTS
I. 创建点集

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 },
{ -.48, 0.2, 0.0 },{ -.40, 0.0, 0.0 },
{ -.60, -.40, 0.0 },{ -.80, -.80, 0.0 },
{ -.80, -1.4, 0.0 },{ -.40, -1.60, 0.0 },
{ 0.0, -1.20, 0.0 },{ .2, -.80, 0.0 },
{ .48, -.40, 0.0 },{ .52, -.20, 0.0 },
{ .48, .20, 0.0 },{ .80, .40, 0.0 },
{ 1.20, .80, 0.0 },{ 1.60, .60, 0.0 },
{ 2.0, .60, 0.0 },{ 2.2, .80, 0.0 },
{ 2.40, 1.0, 0.0 },{ 2.80, 1.0, 0.0 } };

II. 加载点图

GLBatch pointBatch;
pointBatch.Begin(GL_POINTS, 24);
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();
III. 改变点的大小
glPointSize(4.0f);

IV. 绘制

pointBatch.Draw();

V效果图
在这里插入图片描述
2.GL_LINES
这是线段,把数组里面的0-1相连 2-3相连 ,以此类推。
绝大部分操作都和上面一样的,只需替换GL_POINTS成GL_LINES即可,
效果图如下:
在这里插入图片描述
3.GL_LINE_STRIP GL_LINE_LOOP
GL_LINE_STRIP是把数组中的端点依次连接起来,但是首尾不相连,而GL_LINE_LOOP首尾相连。
效果图分别如下:
在这里插入图片描述
在这里插入图片描述
4.GL_TRIANGLES
绘制立体图形的时候如果边缘部分不能显示出来会很没有立体感,如下图所示
在这里插入图片描述
因此,需要绘制出来边缘部分,其主要代码如下:
//通过偏移值绘制边缘部分

    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);      // 设置偏移值
           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);//关闭直线的抗锯齿处理
    }

然后我们创建好三角形坐标

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

通过DrawWireFramedBatch(&triangleBatch);绘制出来图形,效果如下:
在这里插入图片描述

5.GL_TRIANGLE_LOOP
上面绘制多个三角形的时候,每个三角形都使用了三个顶点,而实际上,相邻的三角形之间还存在着重复边,而GL_TRIANGLE_LOOP会绘制数组中连续的三个点作为三角形 0,1,2 1,2,3 2,3,4…
我们创建好三角形的坐标

   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++;
   //加载扇形带的图元
   triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
   triangleStripBatch.CopyVertexData3f(vPoints);
   triangleStripBatch.End();

绘制三角形带 DrawWireFramedBatch(&triangleStripBatch);
效果图如下:
在这里插入图片描述

6.GL_TRIANGLE_FAN
原理和上面一样,但是三角形的应对规则变了,变为 0,1,2 0,2,3 0,3,4 0,4,5… 看起来就是以第一个点为中心的扇形环
创建三角形扇的坐标

       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;//每个点的坐标就是cosr和sinr
              vPoints[nVerts][1] = float(sin(angle)) * r;
              vPoints[nVerts][2] = -0.5f;
       }
       // 保证闭合
       nVerts++;
       vPoints[nVerts][0] = r;
       vPoints[nVerts][1] = 0;
       vPoints[nVerts][2] = 0.0f;
       // 加载三角形扇,顶点+6个端点+最后一个保证闭合的初始点=8个点
       triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
       triangleFanBatch.CopyVertexData3f(vPoints);
       triangleFanBatch.End();

绘制三角形扇
DrawWireFramedBatch(&triangleFanBatch);
效果图如下:
在这里插入图片描述

完整代码还加入了按键控制旋转,以及空格切换图形,具体代码和注释如下:

#include <GLTools.h>  // OpenGL toolkit  
#include <GLMatrixStack.h>  
#include <GLFrame.h>  
#include <GLFrustum.h>  
#include <GLBatch.h>  
#include <GLGeometryTransform.h>
#define FREEGLUT_STATIC  //在windows和linux上,使用freeglut静态版本,需要添加这一行,否则会出现错误
#include <glut.h>
#pragma comment(lib,"gltools.lib")//要加上这一行链接一下gltools库
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);//开启深度测试
       transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);//设置变换管线以使用两个矩阵的堆栈
       cameraFrame.MoveForward(-15.0f);//把摄像机往后挪一挪,否则看不到图像
       //////////////////////////////////////////////////////////////////////  
       // 一系列点的坐标
       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 },
       { -.48, 0.2, 0.0 },{ -.40, 0.0, 0.0 },
       { -.60, -.40, 0.0 },{ -.80, -.80, 0.0 },
       { -.80, -1.4, 0.0 },{ -.40, -1.60, 0.0 },
       { 0.0, -1.20, 0.0 },{ .2, -.80, 0.0 },
       { .48, -.40, 0.0 },{ .52, -.20, 0.0 },
       { .48,  .20, 0.0 },{ .80,  .40, 0.0 },
       { 1.20, .80, 0.0 },{ 1.60, .60, 0.0 },
       { 2.0, .60, 0.0 },{ 2.2, .80, 0.0 },
       { 2.40, 1.0, 0.0 },{ 2.80, 1.0, 0.0 } };
       // 加载好点图 
       pointBatch.Begin(GL_POINTS, 24);
       pointBatch.CopyVertexData3f(vCoast);
       pointBatch.End();
       // 加载好线段图
       lineBatch.Begin(GL_LINES, 24);
       lineBatch.CopyVertexData3f(vCoast);
       lineBatch.End();
       // 加载好连续的线的图
       lineStripBatch.Begin(GL_LINE_STRIP, 24);
       lineStripBatch.CopyVertexData3f(vCoast);
       lineStripBatch.End();
       // 加载好首尾相连的连续的线的图
       lineLoopBatch.Begin(GL_LINE_LOOP, 24);
       lineLoopBatch.CopyVertexData3f(vCoast);
       lineLoopBatch.End();
       // 金字塔的点的坐标 ,四个面
       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();
       //初始化三角形扇的坐标
       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;//每个点的坐标就是cosr和sinr
              vPoints[nVerts][1] = float(sin(angle)) * r;
              vPoints[nVerts][2] = -0.5f;
       }
       // 保证闭合
       nVerts++;
       vPoints[nVerts][0] = r;
       vPoints[nVerts][1] = 0;
       vPoints[nVerts][2] = 0.0f;
       // 加载三角形扇,顶点+6个端点+最后一个保证闭合的初始点=8个点
       triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
       triangleFanBatch.CopyVertexData3f(vPoints);
       triangleFanBatch.End();
       // 创建一个环装的三角形带
       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++;
       //加载扇形带的图元
       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);      // 设置偏移值
       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)
{
       //  用之前设置好的背景色来清除三个缓冲区 
       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);//颜色缓冲区,深度缓冲区,模板缓冲区
       modelViewMatrix.PushMatrix();//保存当前的模型视图矩阵,默认为单位矩阵
       M3DMatrix44f mCamera;
       cameraFrame.GetCameraMatrix(mCamera);
       modelViewMatrix.MultMatrix(mCamera);
       M3DMatrix44f mObjectFrame;
       objectFrame.GetMatrix(mObjectFrame);
       modelViewMatrix.MultMatrix(mObjectFrame);
       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);//设置视口为窗口大小,可以调整这里的值来看结果有什么不同
       viewFrustum.SetPerspective(30.0f, float(w) / float(h), 1.0f, 500.0f);//设置透视投影矩阵,参数分别为,从顶点方向看去的视场角度,高宽比,到近裁减面和远裁减面的距离
       projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());//获得投影矩阵
       modelViewMatrix.LoadIdentity();//加载单位矩阵
}
///////////////////////////////////////////////////////////////////////////////  
// Main entry point for GLUT based programs  
int main(int argc, char* argv[])
{
       gltSetWorkingDirectory(argv[0]);//设置工作目录,argv[0]为当前的程序名
       glutInit(&argc, argv);//初始化glut
       glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);//设置显示模式 双缓冲 RGBA颜色格式 深度缓冲区 模板缓冲区
       glutInitWindowSize(800, 600);//建立一个800*600大小的窗口
       glutCreateWindow("GL_POINTS");//窗口的标题为GL_POINTS
       glutReshapeFunc(ChangeSize);//注册窗口大小改变时候的函数
       glutKeyboardFunc(KeyPressFunc);//注册按键消息
       glutSpecialFunc(SpecialKeys);//注册特殊按键消息(上下左右)
       glutDisplayFunc(RenderScene);//注册场景渲染函数
       GLenum err = glewInit();//初始化glew
       if (GLEW_OK != err) {//处理glew出错的情况
              fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
              return 1;
       }
       SetupRC();//做好场景渲染的准备工作
       glutMainLoop();//绘制主窗口
       return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43813453/article/details/85324033