美文网首页
2.OpenGL图元解析

2.OpenGL图元解析

作者: bytebytebyte | 来源:发表于2020-11-26 09:24 被阅读0次

    1.掌握OpenGL的渲染架构图


    OpenGL渲染架构.png

    2.OpenGL数据传递的3种方式
    attribute属性(颜色数据、顶点数据、纹理坐标、光照法线)不能直接传递片元着色器,需要通过GLSL代码传递。

    Uniforms值可以直接传递到顶点着色器、片元着色器。
    Uniforms值一般是比较统一的动作如发生旋转。
    旋转的实现原理?每个顶点*渲染矩阵传到顶点着色器。

    纹理:就是图片。

    3.掌握OpenGL提供的存储着色器
    GLShaderManager初始化
    GLShaderManager shaderManager;
    shaderManager.InitializeStockShaders();

    GLShaderManager::UserStockShader(GLT_SHADER_IDENTITY,GLfloat vColor[4]);
    参数1: 存储着⾊器种类-单元着⾊器
    参数2: 颜⾊
    使⽤场景: 绘制默认OpenGL 坐标系(-1,1)下图形. 图形所有⽚段都会以⼀种颜⾊填充

    GLShaderManager::UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat
    vColor[4]);
    参数1: 存储着⾊器种类-平⾯着⾊器
    参数2: 允许变化的4*4矩阵
    参数3: 颜⾊
    使⽤场景: 在绘制图形时, 可以应⽤变换(模型/投影变化).

    GLShaderManager::UserStockShader(GLT_SHADER_SHADED,GLfloat mvp[16]);
    参数1: 存储着⾊器种类-上⾊着⾊器
    参数2: 允许变化的4*4矩阵
    使⽤场景: 在绘制图形时, 可以应⽤变换(模型/投影变化) 颜⾊将会平滑地插⼊到顶点之间称为平滑着⾊.

    4.正投影、透视投影API的使用
    正投影
    void SetOrthographic(GLfloat xMin, GLfloat xMax, GLfloat yMin, GLfloat yMax, GLfloat zMin, GLfloat zMax)
    void SetPerspective(float fFov, float fAspect, float fNear, float fFar)
    fFov 垂直方向上的视场角度
    fAspect 窗口宽/高的比值
    fNear 近裁剪面距离
    fFar 远裁剪面距离

    5.OpenGL上7种基本图元
    GL_POINTS 单独点
    GL_LINES 每对顶点定义一个线段
    GL_LINE_STRIP 顶点连接不封闭
    GL_LINE_LOOP 顶点连接封闭
    GL_TRIANGLES 每3个顶点定义一个三角形
    GL_TRIANGLE_STRIP 共用2个点的一组三角形
    GL_TRIANGLE_FAN 以一个圆点、中心扇形排列、共用相邻顶点的一组三角形

    截屏2020-11-15 上午10.22.11.png

    三角形的环绕方式:点到点的方向是顺时针还是逆时针
    在默认情况下,OpenGL 认为具有逆时针⽅向环绕的多边形为正
    ⾯.
    glFrontFace(GL_CW);
    GL_CW:告诉OpenGL 顺时针环绕的多边形为正⾯;
    GL_CCW:告诉OpenGL 逆时针环绕的多边形为正⾯

    三角形带 以GL_TRIANGLE_STRIP画出的一组三角形

    三角形扇 以GL_TRIANGLE_FAN画出的一组三角形

    6.在存储着色器的情况下渲染图形并能通过键盘控制.

    #include "GLTools.h"
    #include "GLMatrixStack.h" //矩阵工具类 加载单元矩阵、矩阵、矩阵相乘、压栈、出栈、缩放、平移、旋转
    #include "GLFrame.h" // 矩阵工具类 位置
    #include "GLFrustum.h" //矩阵工具类 设置正/透视投影矩阵 完成坐标3D-2D的映射
    #include "GLBatch.h" //三角形批次类传输顶点、光照、纹理、颜色数据到存储着色器中
    #include "GLGeometryTransform.h" //交换管道类 传输视图矩阵、投影矩阵、视图投影变换矩阵
    #include <math.h>
    
    #ifdef __APPLE__
    #include <GLUT/GLUT.h> //mac下使用
    #else
    #define FREEGLUT_STATIC
    #include <GL/glut.h> //linux windows 添加一个宏使用
    #endif
    
    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; //几何变换管道
    
    GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
    GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
    
    int nStep = 0; //跟踪效果步骤
    
    void setupRC() {
        glClearColor(0.7f, 0.7f, 0.7f, 1.0f);
        shaderManager.InitializeStockShaders();
        glEnable(GL_DEPTH_TEST);
        //设置变换管线以使用2个矩阵堆栈
        transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
        cameraFrame.MoveForward(-15.0f);
        GLfloat vCoast[9] = { //三角形形状
            3, 3, 0,
            0, 3, 0,
            3, 0, 0
        };
        //用点的形式
        pointBatch.Begin(GL_POINTS, 3);
        pointBatch.CopyVertexData3f(vCoast);
        pointBatch.End();
        
        //通过线的形式
        lineBatch.Begin(GL_LINES, 3);
        lineBatch.CopyVertexData3f(vCoast);
        lineBatch.End();
        
        //通过线段的形式
        lineStripBatch.Begin(GL_LINE_STRIP, 3);
        lineStripBatch.CopyVertexData3f(vCoast);
        lineStripBatch.End();
        
        //通过线环的形式
        lineLoopBatch.Begin(GL_LINE_LOOP, 3);
        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
        };
        //每3个点定义一个新的三角形
        triangleBatch.Begin(GL_TRIANGLES, 12);
        triangleBatch.CopyVertexData3f(vpyramid);
        triangleBatch.End();
        
        //三角形扇形--六边形
        GLfloat vPoints[100][3];
        int nVerts = 0;
        //半径
        GLfloat r = 3.0f;
        //原点(x,y,z) = (0,0,0)
        vPoints[nVerts][0] = 0.0f;
        vPoints[nVerts][1] = 0.0f;
        vPoints[nVerts][2] = 0.0f;
        //M3D_2PI 2pi 就是一个圆的意思
        for (GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {
            nVerts ++; //数组下标自增,每自增一次就表示一个顶点
            //弧长=半径*角度(弧度)
            //x点的坐标 cos(angle) * 半径
            vPoints[nVerts][0] = float(cos(angle)) * r;
            //y点的坐标 sin(angle) * 半径
            vPoints[nVerts][1] = float(sin(angle)) * r;
            //z点的坐标
            vPoints[nVerts][2] = -0.5f;
        }
        
        //结束扇形,前面一共绘制了7个顶点,包括圆心,添加闭合代码,屏蔽下面4行代码,并把绘制节点8改为7,则三角形扇形是无法闭合的
        nVerts ++;
        vPoints[nVerts][0] = r;
        vPoints[nVerts][1] = 0;
        vPoints[nVerts][2] = 0.0f;
        triangleFanBatch.Begin(GL_TRIANGLE_FAN, 7);
        triangleFanBatch.CopyVertexData3f(vPoints);
        triangleFanBatch.End();
        
        //三角形带,一个小环或圆柱段
        //顶点下标
        int iCounter = 0;
        //半径
        GLfloat radius = 3.0f;
        //从0度~360度,以0.3弧度为步长
        for (GLfloat angle = 0.0f; angle <= (2.0f * M3D_PI); angle += 0.3f) {
            //获取圆形顶点的X Y
            GLfloat x = radius * sin(angle);
            GLfloat y = radius * cos(angle);
            
            //绘制2个三角形,它们的x,y顶点一样,只是z点不一样
            vPoints[iCounter][0] = x;
            vPoints[iCounter][1] = y;
            vPoints[iCounter][2] = -0.5f;
            iCounter ++;
            
            vPoints[iCounter][0] = x;
            vPoints[iCounter][1] = y;
            vPoints[iCounter][2] = 0.5f;
            iCounter ++;
        }
        
        //关闭循环
        printf("三角形带的顶点数:%d\n",iCounter);
        //结束循环,在循环位置生成2个三角形
        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 drawWriteFramedBatch(GLBatch * pBatch) {
        //画绿色部分 GLT_SHADER_FLAT平面着色器 变换管线,指定了2个矩阵堆栈 颜色值
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
        pBatch->Draw();
        
        //边框部分
        
        //画黑色边框
        //偏移深度,在同一位置要绘制填充和边线,会产生冲突,所以要偏移
        glPolygonOffset(-1.0f, -1.0f);
        glEnable(GL_POLYGON_OFFSET_LINE); // GL_POLYGON_OFFSET_LINE 根据函数glPolygonOffset的设置,启用线的深度偏移
        
        //画反锯齿,让黑白好看些
        glEnable(GL_LINE_SMOOTH); //GL_LINE_SMOOTH 执行后,过虑线点的锯齿
        glEnable(GL_BLEND); //启用颜色混合。例如实现半透明效果
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        
        //通过调用glPolygonMode将多边形正面或背面设为线框模式,实现线框渲染
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        glLineWidth(2.5f);
        
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
        pBatch->Draw();
        
        //复原原本的设置
        //通过调用glPolygonMode将多边形正面或者背面设为全部填充模式
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        glDisable(GL_POLYGON_OFFSET_LINE); //关闭指定功能
        glLineWidth(1.0f);
        glDisable(GL_BLEND);
        glDisable(GL_LINE_SMOOTH);
        
    }
    
    //召唤场景
    void renderScene() {
        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);
        //GLT_SHADER_FLAT 平面着色器
        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:
                drawWriteFramedBatch(&triangleBatch);
                break;
            case 5:
                drawWriteFramedBatch(&triangleStripBatch);
                break;
            case 6:
                drawWriteFramedBatch(&triangleFanBatch);
                break;
        }
        //还原到以前的模型视图矩阵
        modelViewMatrix.PopMatrix();
        //进行缓冲区交换
        glutSwapBuffers();
        
    }
    
    void specialKeys(int key, int x, int y) {
        if (key == GLUT_KEY_UP) {
            //围绕一个指定的X Y Z轴旋转
            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();
    }
    
    //根据空格次数,切换不同的窗口名称
    void keyPressFunc(unsigned char key, int x, int y) {
        if (key == 32) {  //空格(Space)的ASCII码值是: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();
    }
    
    //窗口已更改大小,或刚刚创建,无论哪种情况我们都需要使用窗口维度设置视口和投影矩阵。
    void changeSize(int w, int h) {
        glViewport(0, 0, w, h);
        //创建投影矩阵,并将它载入投影矩阵堆栈中
        viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
        //调用顶部载入单元矩阵
        modelViewMatrix.LoadIdentity();
        
    }
    
    
    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);
        //点击空格调用的函数
        glutKeyboardFunc(keyPressFunc);
        //特殊键位函数;
        glutSpecialFunc(specialKeys);
        //显示函数
        glutDisplayFunc(renderScene);
        GLenum err = glewInit();
        if (GLEW_OK != err) {
            fprintf(stderr, "GLEW Error:%s\n",glewGetErrorString(err));
            return 1;
        }
        //绘制
        setupRC();
        glutMainLoop();
        return 0;
    }
    
    

    相关文章

      网友评论

          本文标题:2.OpenGL图元解析

          本文链接:https://www.haomeiwen.com/subject/eufnbktx.html