OpenGL --存储着色器

作者: 乔克蜀黍 | 来源:发表于2018-03-11 18:13 被阅读56次
    1.Client通过三种方式向server发送数据

    1.属性(Attributes),属性以4维向量传递数据,属性只有向单元着色器传递才有意义。
    2.Uniforms,Uniforms可以在顶点着色器和片源着色器使用,Uniforms只能使用不可以修改。
    3.纹理(Texture Data)

    2.存储着色器

    在OpenGL 3.0之前,OpenGL 包含 个固定功能的管线,它可以在 使 着 的情况下处 何与像素数据。在3.1版本开始,固定管线从核 模式去掉。因此现在需要使 着 来完成 作。
    使 OpenGL 来说,我们会使 GLSL,(OpenGL Shading Langruage,它是 在OpenGL 2.0版本发布的)。 语法与“C、C++”类似

    着色器分类

    • 单元着色器
    • 平面着色器
    • 上色着色器
    • 默认光源着色器 
    • 点光源着色器
    • 纹理替换矩阵
    • 纹理调整着色器 
    • 纹理光源着色器
    

    着色器使用

    //定义着色器
    GLShaderMananger shaderManager;
    //初始化着色器 shaderManager.InitalizeStockShaders()
    //使用
    shaderManager userStockManager(参数列表)
    
    3.举例

    创建6种不同的图形点击空格键来切换

    创建要用到的矩阵堆栈、Frame、投影矩阵、图形批次容器

    //矩阵堆栈
    #include "GLMatrixStack.h"
    //矩阵
    #include "GLFrustum.h"
    //投影矩阵
    #include "GLFrame.h"
    //三角形批次类
    #include "GLBatch.h"
    //几何变换管道
    #include "GLGeometryTransform.h"
    
    GLShaderManager shaderManager;
    //模型视图矩阵堆栈
    GLMatrixStack modelViewMatrix;
    //投影视图矩阵堆栈
    GLMatrixStack projectionMatrix;
    //照相机Frame(观察者)
    GLFrame cameraFrame;
    //世界坐标系
    GLFrame objectFrame;
    //投影矩阵
    GLFrustum viewFrustum;
    
    //容器类
    GLBatch pointBatch;
    GLBatch lineBatch;
    GLBatch lineStripBatch;
    GLBatch lineLoopBatch;
    GLBatch triangleBatch;
    GLBatch triangleStripBatch;
    GLBatch triangleFanBatch;
    
    //几何变换的管道,管理堆栈(modelViewMatrix projectionMatrix)
    GLGeometryTransform transformpipeline;
    M3DMatrix44f shadowMatrix;
    
    GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
    GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
    
    // 跟踪效果步骤
    int nStep = 0;
    

    窗口大小改变时接受新的宽度和高度,其中0,0代表窗口中视口的左下角坐标,w,h代表像素

    void ChangeSize(int w,int h) {
        glViewport(0,0, w, h);
        
        //创建透视投影,并将它载入到投影矩阵堆栈中
        /*
         参数:
         1.垂直方向上的视场角度
         2.窗口的宽度与高度的纵横比
         3.近裁剪面距离
         4.远裁剪面距离
         */
        viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 500.0f);
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
        
        //调用顶部载入单元矩阵
        modelViewMatrix.LoadIdentity();
    }
    

    为程序作一次性的设置

    void SetupRC() {
        glClearColor(0.6f, 0.6f, 0.6f, 1.0f);
        shaderManager.InitializeStockShaders();
        
        //设置变换管线以使用两个矩阵堆栈
        transformpipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
        cameraFrame.MoveForward(-15);
        
        //定义一些点,类似佛罗里达州的形状。
        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};
        
        //GL_TRIANGLES 每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) {
            
            //数组下标自增(每自增1次就表示一个顶点)
            nVerts++;
            /*
             弧长=半径*角度,这里的角度是弧度制,不是平时的角度制
             既然知道了cos值,那么角度=arccos,求一个反三角函数就行了
             */
            //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个顶点(包括圆心)
        printf("三角形扇形顶点数:%d\n",nVerts);
        //添加闭合的终点
        //课程添加演示:屏蔽177-180行代码,并把绘制节点改为7.则三角形扇形是无法闭合的。
        nVerts++;
        vPoints[nVerts][0] = r;
        vPoints[nVerts][1] = 0;
        vPoints[nVerts][2] = 0.0f;
        
        // 加载!
        //GL_TRIANGLE_FAN 以一个圆心为中心呈扇形排列,共用相邻顶点的一组三角形
        triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
        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.5;
            iCounter++;
            
            vPoints[iCounter][0] = x;
            vPoints[iCounter][1] = y;
            vPoints[iCounter][2] = 0.5;
            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++;
        
        // GL_TRIANGLE_STRIP 共用一个条带(strip)上的顶点的一组三角形
        triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
        triangleStripBatch.CopyVertexData3f(vPoints);
        triangleStripBatch.End();
    }
    

    开始渲染

    void RenderScene(void) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
        
        //压栈
        modelViewMatrix.PushMatrix();
        
        //获取照相机frame设置给张相机矩阵
        M3DMatrix44f camealMatrix;
        cameraFrame.GetCameraMatrix(camealMatrix);
        
        //照相机矩阵乘模型视图矩阵顶部的矩阵,结果存储在模型视图矩阵的顶部
        modelViewMatrix.MultMatrix(camealMatrix);
        
        //获取世界坐标系设置给世界坐标系矩阵
        M3DMatrix44f objFrame;
        objectFrame.GetMatrix(objFrame);
        
        //世界坐标系矩阵乘模型视图矩阵顶部的矩阵,结果存储在模型视图矩阵的顶部
        modelViewMatrix.MultMatrix(objFrame);
        
        shaderManager.UseStockShader(GLT_SHADER_FLAT,transformpipeline.GetModelViewProjectionMatrix(),vBlack);
        
        switch (nStep) {
            case 0:
                glPointSize(3.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;
                
            default:
                break;
        }
        
        //还原到以前的模型视图矩阵(单位矩阵)
        modelViewMatrix.PopMatrix();
        
        //进行缓存区交换
        glutSwapBuffers();
    }
    

    根据空格键次数切换不同窗口
    key:敲击的键位
    x,y光标的位置

    void keyPressFunc(unsigned char key,int x,int y)
    {
        //空格键的ascii码是32
        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();
        
    }
    

    通过点击上下左右四个键来控制图形的旋转

    void specialKeyPress(int key, int x, int y)
    {
        if (key == GLUT_KEY_UP) {
            objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0, 0);
        }
        
        if (key == GLUT_KEY_DOWN) {
            objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0, 0);
        }
        
        if (key == GLUT_KEY_LEFT) {
            objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0, 1.0f, 0);
        }
        
        if (key == GLUT_KEY_RIGHT) {
            objectFrame.RotateWorld(m3dDegToRad(5.0f), 0, 1.0f, 0);
        }
        
        glutPostRedisplay();
    }
    

    main函数做一些初始化操作和注册 调用上面函数

    int main(int argc,char* argv[]) {
        //设置当前工作目录,针对MAC OS X
        gltSetWorkingDirectory(argv[0]);
        
        //初始化GLUT库
        glutInit(&argc, argv);
        
        /*初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
         双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区*/
        glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
        
        
        //GLUT窗口大小,标题窗口
        glutInitWindowSize(800,600);
        glutCreateWindow("Triangle");
        
        //注册回调函数(这两个函数有一个不注册,窗口就弹不起来,因为在启动的一瞬间也是需要调用的,以后窗口或界面调用也会更改)
        glutReshapeFunc(ChangeSize);
        glutDisplayFunc(RenderScene);
        //空格键点击
        glutKeyboardFunc(keyPressFunc);
        
        //上下左右键点击
        glutSpecialFunc(specialKeyPress);
        
        //驱动程序的初始化中没有出现任何问题。
        GLenum err = glewInit();
        if(GLEW_OK != err) {
            fprintf(stderr,"glew error:%s\n",glewGetErrorString(err));
            return 1;
        }
        //调用SetupRC
        SetupRC();
        glutMainLoop();
        return 0;
    }
    
    void DrawWireFramedBatch(GLBatch* pBatch)
    {
        /*------------画绿色部分----------------*/
        /* GLShaderManager 中的Uniform 值——平面着色器
         参数1:平面着色器
         参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
         --transformPipeline 变换管线(指定了2个矩阵堆栈)
         参数3:颜色值
         */
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformpipeline.GetModelViewProjectionMatrix(), vGreen);
        pBatch->Draw();
        
        
        
        /*-----------边框部分-------------------*/
        /*
         glEnable(GLenum mode); 用于启用各种功能。功能由参数决定
         参数列表:http://blog.csdn.net/augusdi/article/details/23747081
         注意:glEnable() 不能写在glBegin() 和 glEnd()中间
         GL_POLYGON_OFFSET_LINE  根据函数glPolygonOffset的设置,启用线的深度偏移
         GL_LINE_SMOOTH          执行后,过虑线点的锯齿
         GL_BLEND                启用颜色混合。例如实现半透明效果
         GL_DEPTH_TEST           启用深度测试 根据坐标的远近自动隐藏被遮住的图形(材料
         
         
         glDisable(GLenum mode); 用于关闭指定的功能 功能由参数决定
         
         */
        
        //画黑色边框
        glPolygonOffset(-1.0f, -1.0f);// 偏移深度,在同一位置要绘制填充和边线,会产生z冲突,所以要偏移
        glEnable(GL_POLYGON_OFFSET_LINE);
        
        // 画反锯齿,让黑边好看些
        glEnable(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);
        
        /* GLShaderManager 中的Uniform 值——平面着色器
         参数1:平面着色器
         参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
         --transformPipeline.GetModelViewProjectionMatrix() 获取的
         GetMatrix函数就可以获得矩阵堆栈顶部的值
         参数3:颜色值(黑色)
         */
        
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformpipeline.GetModelViewProjectionMatrix(), vBlack);
        //绘制
        pBatch->Draw();
        
        // 复原原本的设置
        ////通过调用glPolygonMode将多边形正面或者背面设为全部填充模式
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        //关闭GL_POLYGON_OFFSET_LINE 模型
        glDisable(GL_POLYGON_OFFSET_LINE);
        //设置线条宽度
        glLineWidth(1.0f);
        //关闭混合
        glDisable(GL_BLEND);
        //关闭线条光滑功能
        glDisable(GL_LINE_SMOOTH);
    }
    

    xcode demo地址

    相关文章

      网友评论

        本文标题:OpenGL --存储着色器

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