OpenGL固定管线着色器

354 阅读5分钟

#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链接:download.csdn.net/download/zc…

堆栈操作不理解的可以看:OpenGL矩阵堆栈处理