美文网首页
1.OpenGL基础

1.OpenGL基础

作者: bytebytebyte | 来源:发表于2020-11-27 07:19 被阅读0次

1.图形API 简介
OpenGL (Open Graphics Library)是一个跨编程语言、跨平台的编程图形程序接口,它将计算机从资源抽象成为一个一个OpenGL对象,对这些资源的操作对象为一个个的OpenGL对象。
不管是哪个平台都会调到那个命令,最基本的。
OpenGLES (OpenGL For Embedded Systems)是OpenGL三维图形API的子集,针对手机、PAD和游戏主机等嵌入式设备而设计,去除可许多不必要和性能较低的API接口。
主要是手机使用的OpenGL的API子集。
DirectX是由很多API组成的,DirectX不是一个单纯的图形API,最重要的是DirectX是属于Windows上一个多媒体处理框架,并不支持Windows以外的平台,所以不是跨平台框架,按照性质分类,可以分为四大部分:显示部分、声音部分、输入部分和网络部分。
Windows上一个多媒体处理框架。
Mental:Apple为游戏开发者推出了新的平台技术mental,该技术能够为3D图像提高10倍的渲染性能。
mental是Apple为解决3D渲染而推出的框架。

1.下面说明中正确的是(A)
A.开发者可以再Mac程序中使用OpenGL来实现图形渲染
B.开发者只能使用Mental在Apple平台下实现图形渲染 也可以OpenGL
C.开发者们能使用DirectX在Apple平台下实现图形渲染 DirectX只能在Windows平台下使用
D.OpenGL和OpenGLES并没有差别

2.下面说明中正确的是(BC)
A.2018年后Apple开发者不能在Apple平台下使用OpenGL和OpenGLES
B.苹果底层渲染是由mental来实现的
C.OpenGLES只是比OpenGL少了一部分子集
D.iOS 开发者没有必要学习OpenGLES

图形API目的是解决什么问题?
简单来说就是实现图形的底层渲染。
A.比如在游戏开发中,对于游戏场景和任务的渲染
B.比如在音视频开发中,对于视频解码后的数据渲染
C.比如在地图引擎,对于地图上的数据渲染
D.比如在动画中,实现动画的绘制
E.比如在视频处理中,对于视频加上滤镜效果

OpenGL/OpenGLES/Mental解决问题的本质是操作GPU芯片来高效渲染图形图像.图形API是iOS开发者唯一接近GPU的方式。

3.下面说明中正确的是ACD
A.音视频开发有必要学习OpenGLES
B.ARKit中关于3D图形渲染不能用OpenGLES渲染 很少用OpenGLES渲染,所以能用
C.Cocos2D框架底层中需要依赖OpenGLES
D.Mental能够替代OpenGLES

2.图形API目的是解决什么问题?
实现图形的底层渲染。游戏场景、人物的渲染、视频解码后数据的渲染、地图上的数据渲染、视频的滤镜等。

3.OpenGL专业名词解析
OpenGL上下文 是一个巨大的状态机,状态机可以不同,但可以共享纹理、缓冲区等资源来避免切换上下文的开销。

OpenGL状态机 是一种行为。
可以记忆状态,如当前使用的颜色;
可以接受输入、改变、可以输出,如调用OPenGL函数时实际是在接受我们的输入GLColor3f;
停机状态,不工作了,如程序退出,OpenGL 先停止工作。

渲染rendering:图形数据->图像 的操作

顶点数组VertexArray 顶点缓冲区VertexBuffer
可以放在CPU的内存中,在内存中叫顶点数组,也可以放在GPU的显存中,在显存中叫顶点缓冲区。
图像由图元组成,OpenGLES的3种图元:点、线、三角形。

管线:渲染图形经历的一个个节点,顺序不能乱。

固定渲染管线,又叫存储着色器,完成图形渲染的shader程序,只传入参数就行调用shader程序完成渲染。

着色器程序shader:OpenGL绘制前需要调用的着色器程序shader,分为片元着色器和顶点着色器。
片元着色器=片段着色器=像素着色器

顶点着色器:
是一段计算顶点属性如顶点坐标变换、逐顶点光照运算的程序,
处理顶点的变换如旋转、平移、投影,
每个顶点都会执行一次顶点着色器,这是并行的。

像素着色器:
是一段计算像素颜色的程序,
处理每个像素点颜色的计算和填充,
每个像素都会执行一次像素着色器,这是并行的。

GLSL(OpenGL Shading Language)OpenGL着色器语言,在GPU(Graphic Processor Unit图形处理单元)上执行,GLSL代码分成2部分:顶点着色器和像素着色器。

光栅化:顶点数据->片元过程,把物体的数学描述以及与物体相关的颜色信息转换为屏幕上对应位置的像素及用于填充像素的颜色。

纹理:理解为图片

混合:颜色的混合

变换矩阵:图形的平移、缩放、旋转需要用到变换矩阵。

投影矩阵: 3维转2维再绘制。

交换缓冲区

2D笛卡尔坐标
3D笛卡尔坐标
视口
OpenGL投影方式
透视投影:远近有大小,从摄像机角度看
正投影:远近无大小。

4.OpenGL坐标系
物体坐标系 -旋转->惯性坐标系 -平移-> 世界坐标系

5.图形从文件渲染到屏幕的过程解析
着色器的渲染流程:
顶点数据->顶点着色器->细分着色器->集合着色器->图元设置->剪切->光栅化->片元着色器->效果
图片渲染流程

6.固定管线下使用OpenGL渲染三角形

#include "GLShaderManager.h"
#include "GLTools.h"
#include <GLUT/GLUT.h>

GLBatch triangleBatch;
GLShaderManager shaderManager;
//窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
void ChangeSize(int w, int h) {
    glViewport(0, 0, w, h);
}
//为程序做一次性的设置
void setupRC() {
    //设置背景颜色
    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
    //初始化着色器
    shaderManager.InitializeStockShaders();
    //设置三角形的3个顶点
    GLfloat vVerts[] = {
        -0.5f, 0.0f, 0.0f,
        0.5f, 0.0f, 0.0f,
        0.0f, 0.5f, 0.0f
    };
    //批次处理
    triangleBatch.Begin(GL_TRIANGLES, 3);
    triangleBatch.CopyVertexData3f(vVerts);
    triangleBatch.End();
    
}

//开始渲染
void renderScene(void) {
    //清除一个或一组特定的缓冲区
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    //设置一组浮点数来表示红色
    GLfloat vRed[] = {1.0f, 0.0f, 0.0f, 1.0f};
    //传递到存储着色器GLT_SHADER_IDENTITY,这个着色器只是使用指定颜色以默认笛卡尔坐标在屏幕上渲染几何图形
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
    //提交着色器
    triangleBatch.Draw();
    //将在后台缓冲区进行渲染,然后在结束时交换到前台
    glutSwapBuffers();
}

int main(int argc, char *argv[]) {
    //设置当前工作目录,针对MAC OS X
    gltSetWorkingDirectory(argv[0]);
    //初始化GLUT库
    glutInit(&argc, argv);
    //初始化双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    //GLUT窗口大小
    glutInitWindowSize(800, 600);
    //标题窗口
    glutCreateWindow("Triangle");
    //注册回调函数
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(renderScene);
    //驱动程序的初始化中没有出现任何问题
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "glew error:%s\n",glewGetErrorString(err));
        return 1;
    }
    setupRC();
    glutMainLoop();
    return 0;
}

7.固定管线下使用OpenGL渲染正方形,并能通过键盘移动该图形

#include "GLShaderManager.h"
#include "GLTools.h"
#include <GLUT/GLUT.h>


GLBatch triangleBatch;
GLShaderManager shaderManager;
GLfloat blockSize = 0.1f;//边长
GLfloat vVerts[] = { //正方形的4个点坐标
    -blockSize, -blockSize, 0.0f,
    blockSize, -blockSize, 0.0f,
    blockSize, blockSize, 0.0f,
    -blockSize, blockSize, 0.0f
};
//窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
void changeSize(int w, int h) {
    glViewport(0, 0, w, h);
}

void renderScene(void) {
    //清除一个或一组特定的缓冲区
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    //设置一组浮点数来表示红色
    GLfloat vRed[] = {1.0f, 0.0f, 0.0f, 1.0f};
    //传递到存储着色器GLT_SHADER_IDENTITY,这个着色器只是使用指定颜色以默认笛卡尔坐标在屏幕上渲染几何图形
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
    //提交着色器
    triangleBatch.Draw();
    //将在后台缓冲区进行渲染,然后在结束时交换到前台
    glutSwapBuffers();
}

//为程序做一次性的设置
void setupRC() {
    //设置背景颜色
    glClearColor(0.98f, 0.40f, 0.7f, 1.0f);
    //初始化着色器
    shaderManager.InitializeStockShaders();
    //修改GL_TRIANGLE_FAN为4个顶点
    triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
    triangleBatch.CopyVertexData3f(vVerts);
    triangleBatch.End();
    
}

void specialKeys(int key, int x, int y) {
    GLfloat stepSize = 0.025f;
    GLfloat blockX = vVerts[0];
    GLfloat blockY = vVerts[10];
    printf("v[0] = %f\n",blockX);
    printf("v[10] = %f\n",blockY);
    if (key == GLUT_KEY_UP) {
        blockY += stepSize;
    }
    if (key == GLUT_KEY_DOWN) {
        blockY -= stepSize;
    }
    if (key == GLUT_KEY_LEFT) {
        blockX -= stepSize;
    }
    if (key == GLUT_KEY_RIGHT) {
        blockX += stepSize;
    }
    //触碰到4个边界的处理
    //正方形移动超过最左边的时候
    if (blockX < -1.0f) {
        blockX = -1.0f;
    }
    //正方形移动超过最右边的时候
    if (blockX > (1.0 - blockSize * 2)) {
        blockX = 1.0f - blockSize * 2;
    }
    //当正方形移动到最下面时
    if (blockY < -1.0f + blockSize * 2) {
        blockY = -1.0f + blockSize * 2;
    }
    //当正方形移动到最上面时
    if (blockY > 1.0f) {
        blockY = 1.0f;
    }
    printf("blockX = %f\n",blockX);
    printf("blockY = %f\n",blockY);
    vVerts[0] = blockX;
    vVerts[1] = blockY - blockSize * 2;
    printf("(%f,%f)\n",vVerts[0],vVerts[1]);
    
    vVerts[3] = blockX + blockSize * 2;
    vVerts[4] = blockY - blockSize * 2;
    printf("(%f,%f)\n",vVerts[3],vVerts[4]);
    
    vVerts[6] = blockX + blockSize * 2;
    vVerts[7] = blockY;
    printf("(%f,%f)\n",vVerts[6],vVerts[7]);
    
    vVerts[9] = blockX;
    vVerts[10] = blockY;
    printf("(%f,%f)\n",vVerts[9],vVerts[10]);
    //手动触发渲染函数
    triangleBatch.CopyVertexData3f(vVerts);
    //手动触发重新渲染
    glutPostRedisplay();
}

int main(int argc, char *argv[]) {
    //设置当前工作目录,针对MAC OS X
    gltSetWorkingDirectory(argv[0]);
    //初始化GLUT库
    glutInit(&argc, argv);
    //初始化双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
    //GLUT窗口大小
    glutInitWindowSize(800, 600);
    //标题窗口
    glutCreateWindow("Triangle");
    //注册重塑函数
    glutReshapeFunc(changeSize);
    //注册显示函数
    glutDisplayFunc(renderScene);
    //注册特殊函数vvv
    glutSpecialFunc(specialKeys);
    //驱动程序的初始化中没有出现任何问题
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "glew error:%s\n",glewGetErrorString(err));
        return 1;
    }
    //设置渲染环境
    setupRC();
    glutMainLoop();
    return 0;
}

8.固定管线下使用OpenGL绘制图形

#include <iostream>
#include <GLUT/GLUT.h>
#include "math3d.h"

void drawSquare() {
    //1.设置清屏颜色
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    //2.清除缓存区对数值进行预置
    glClear(GL_COLOR_BUFFER_BIT);
    //3.设置颜色
    glColor3f(1.0f, 0.0f, 0.0f);
    //4.设置绘图的坐标系统
    glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
    //5.开始渲染
    glBegin(GL_POLYGON);
    //6.设置多边形的4个顶点
    glVertex3f(0.25f, 0.25f, 0.0f);
    glVertex3f(0.75f, 0.25f, 0.0f);
    glVertex3f(0.75f, 0.75f, 0.0f);
    glVertex3f(0.25f, 0.75f, 0.0f);
    //7.结束渲染
    glEnd();
    //8.强制刷新缓存区,保证绘制命令得以执行
    glFlush();
    
}

void drawCircle() {
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0f, 0.0f, 0.0f);
    glBegin(GL_POLYGON);
    const int n = 55;
    const GLfloat R = 0.5f;
    const GLfloat pi = 3.1415926f;
    for (int i = 0; i < n; i ++) {
        glVertex2f(R * cos(2 * pi / n * i), R * sin(2 * pi / n * i));
    }
    glEnd();
    glFlush();
}

//五角星
void drawPentagon() {
    //假设五角星的中心在原点
    const GLfloat pi = 3.1415926536f;
    GLfloat a = 1 / (2 - 2 * cos(72 * pi / 180));  //五角星的中心到顶点的距离为a
    GLfloat bx = a * cos(18 * pi / 180);
    GLfloat by = a * sin(18 * pi / 180);
    GLfloat cy = -a * cos(18 * pi / 180);
    GLfloat
    PointA[2] = {0, a},
    PointB[2] = {bx, by},
    PointC[2] = {0.5, cy},
    PointD[2] = {-0.5, cy},
    PointE[2] = {- bx, by};
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_LINE_LOOP);
    //按照A->C->E->D->B->A的顺序可以一笔将五角星画出
    glVertex2fv(PointA);
    glVertex2fv(PointC);
    glVertex2fv(PointE);
    glVertex2fv(PointB);
    glVertex2fv(PointD);
    glEnd();
    glFlush();
    
}

void drawSin() {
    /*
     由于OpenGL默认坐标值只能从-1到1,可以修改,所以我们设置一个因子factor,把所有的坐标值等比例缩小,这样就可以画出多个正弦周期,可以修改factor的值,观察变化情况
     */
    const GLfloat factor = 0.1f;
    GLfloat x;
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_LINES);
    glVertex2f(-1.0f, 0.0f);
    glVertex2f(1.0f, 0.0f);
    glVertex2f(0.0f, -1.0f);
    glVertex2f(0.0f, 1.0f);
    glEnd();
    glBegin(GL_LINE_STRIP);
    for (x = -1.0f / factor; x < 1.0f / factor; x += 0.01f) {
        glVertex2f(x * factor, sin(x) * factor);
    }
    glEnd();
    glFlush();
}



int main(int argc, char *argv[]) {
    //1.初始化一个GLUT库
    glutInit(&argc, (char **)argv);
    //2.创建一个窗口并制定窗口名
    glutCreateWindow("MM_Window");
    //3.注册一个绘图函数,操作系统在必要时刻就会对窗体重绘制操作,它设置了一个显示回调,即GLUT在每次更新窗口的时候会自动调用该函数
//    glutDisplayFunc(drawCircle);
//    glutDisplayFunc(drawSquare);
//    glutDisplayFunc(drawPentagon);
    glutDisplayFunc(drawSin);
    glutMainLoop();//这是一个无限执行的循环,它会一直处理窗口和操作系统的用户输入等操作,不会执行之后的所有命令
    
    return 0;
}

相关文章

网友评论

      本文标题:1.OpenGL基础

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