OpenGLOpenGL+MetalOpenGL ES图形处理

OpenGL --存储着色器

2018-03-11  本文已影响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地址

上一篇下一篇

猜你喜欢

热点阅读