美文网首页OpenGL
OpenGL固定管线着色器

OpenGL固定管线着色器

作者: 聪莞 | 来源:发表于2019-05-15 17:06 被阅读16次

    OpenGL固定管线下的着色器包括:

    1. 单元着色器(GLT_SHADER_IDENTITY)
    2. 平面着色器(GLT_SHADER_FLAT)
    3. 上色着色器(GLT_SHADER_SHADED)
    4. 默认光源着色器(GLT_SHADER_DEFAULT_LIGHT)
    5. 点光源着色器(GLT_SHADER_POINT_LIGHT_DIEF)
    6. 纹理替换矩阵着色器(GLT_SHADER_TEXTURE_REPLACE)
    7. 纹理调整着色器(GLT_SHADER_TEXTURE_MODULATE)
    8. 纹理光源着色器(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF)

    了解几个概念:

    模型视图投影矩阵的作用,就是将顶点从局部坐标系转化到规范立方体中,总而言之, 模型视图投影矩阵 = 模型矩阵视图矩阵投影矩阵;
    模型矩阵: 将顶点从局部坐标系转换到世界坐标系中;
    视图矩阵: 将顶点从世界坐标转化到视图坐标系下;
    投影矩阵: 将顶点从视图坐标系转换到规范立方体中(即屏幕中);

    再来熟悉几个头文件:

    //包含了大部分GLTool中类似C语言的独立函数
    #include "GLTools.h"    
    
    //矩阵工具类,可以利用GLMatrixStack加载单元矩阵/矩阵/矩阵相乘/压栈/出栈/缩放/平移/旋转     
    #include "GLMatrixStack.h"    
    
    //矩阵工具类,表示位置。通过设置vOrigin,vForward,vUp
    #include "GLFrame.h"
    
    //矩阵工具类,用来快速设置 正/透 投影矩阵,完成坐标从3d->2d的映射
    #include "GLFrustum.h"
    
    //批次类,帮助类,可以传输顶点/光照/纹理/颜色等数据到着色器中
    #include "GLBatch.h"
    
    //变换管道类:用来快速在代码中传输视图矩阵/投影矩阵/视图投影变换矩阵等
    #include "GLGeometryTransform.h"
    
    //数学库
    #include <math.h>
    

    平面着色器实现一个金字塔的效果

    着色器的种类很多,这里就不一一举例了,用法都是流程都是一样的,只是根据不同的需求选择不同的着色器跟不同的算法。

    定义一些变量:
    GLShaderManager     shaderManager;        //着色器管理类
    GLMatrixStack       modelViewMatrix;      //模型视图矩阵堆栈
    GLMatrixStack       projectionMatrix;     //透视矩阵堆栈
    GLFrame             cameraFrame;          //观察者位置
    GLFrame             objectFrame;          //物体本身的位置
    
    GLFrustum           viewFrustum;            //投影矩阵
    
    GLBatch             triangleBatch;            //批次类
    
    GLGeometryTransform transformPipeline;    //几何变换的管道
    
    GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };    //金字塔颜色
    GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };    //金字塔分割线的颜色
    

    具体项目源码看附件Demo,这里只写关键代码

    初始化准备
    void SetupRC()
    {
        //清屏并设置背影颜色
        glClearColor(0.3f,0.3f,0.3f,1.0f);
        
        //初始化着色管理器
        shaderManager.InitializeStockShaders();
        
        //开始深度测试
        glEnable(GL_DEPTH_TEST);
        
        //设置变换管线以使用两个矩阵
        transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
        
        //移动观察者的位置 :-15表示离观察者的距离,设置为-30则离观察者更远,看到的图形效果就小一些
        cameraFrame.MoveForward(-15);
        
        //定义一些点表示金字塔的顶点
        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();
    }
    
    changeSize回调
    //窗口大小改变时接受新的宽度和高度,其中0,0代表窗口中视口的左下角坐标,w,h代表像素
    void ChangeSize(int w,int h)
    {
        glViewport(0,0, w, h);
        
        /* 创建投影矩阵,并把它加入到投影矩阵堆栈
         * 参数说明 : 垂直方向视场角度、窗口宽度与高度的纵横比、近裁剪面距离、远裁剪面距离
         */
        viewFrustum.SetPerspective(40.0f, float(w) / float(h), 1.0f, 500.0f);
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
        
        //载入单元矩阵、单元矩阵的话可以不写
        modelViewMatrix.LoadIdentity();
    }
    
    特殊键位来控制金字塔的旋转
    //特殊键位处理
    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();
    }
    
    RenderScene开始渲染场景
    void RenderScene(void)
    {
        //清除一个或一组特定的缓冲区 执行
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
        
        
        //将当前变换矩阵(单位矩阵)压入堆栈 glPushMatrix的目的是让各次变换相互独立 push跟pop对应
        modelViewMatrix.PushMatrix();
        
        //获得观察者的矩阵堆栈
        M3DMatrix44f mCamera;
        cameraFrame.GetCameraMatrix(mCamera);
        
        //压栈:视图矩阵 ,也可以直接矩阵相乘 ,如果是push的话,后面就需要另外一个pop
    //    modelViewMatrix.PushMatrix(mCamera);
        modelViewMatrix.MultMatrix(mCamera);
        
        M3DMatrix44f mObjectFrame;
        //获取模型矩阵
        objectFrame.GetMatrix(mObjectFrame);
        modelViewMatrix.MultMatrix(mObjectFrame);
        
        //使用平面着色器
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
        
        //开始画金字塔
        DrawGoldTowerBatch(&triangleBatch);
        
        modelViewMatrix.PopMatrix();
        
        //将在后台缓冲区进行渲染,然后在结束时交换到前台
        glutSwapBuffers();
        
    }
    
    开始画金字塔
    void DrawGoldTowerBatch(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); 用于关闭指定的功能 功能由参数决定
         
         */
        
        //画黑色边框
        //偏移深度,在同一位置要绘制填充和边线,会产生z冲突,所以要偏移
        glPolygonOffset(-1.0f, -1.0f);
        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);
        glDisable(GL_POLYGON_OFFSET_LINE);
        glLineWidth(1.0f);
        glDisable(GL_BLEND);
        glDisable(GL_LINE_SMOOTH);
    }
    

    运行效果如下:


    jzt.gif

    demo链接:https://download.csdn.net/download/zc971188623/11180298

    相关文章

      网友评论

        本文标题:OpenGL固定管线着色器

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