OpenGL

002– 3D图形 和 OpenGL 简介
http://www.jianshu.com/p/ff26de4eee71
001–OpenGL在Mac
上之条件搭建:http://www.jianshu.com/p/f3b21fe058e3

护眼图,文字太多呀!哈哈哈。。。

OpenGL 简介

OpenGL发展至今,已经20不必要年。作为一个成熟而久负闻名的跨平台的微机图形应用程序接口规范,它曾经深受广泛应在玩、影视、军事、航空航天、地理、经济学、机械设计,以及各样科学数据可视化的园地。

并且随着网络以及倒平台的急迅发展,异步突起的OpenGL ES 和 WebGL
标准呢抓住了许许多多开发者的眼珠。而当时二者与OpenGL
本身一样有千丝万缕的关系。

OpenGL 几乎协理具备现有的主流操作系统平台,包括Windows、Mac OS
X以及各类UNIX平台。它同时为得用来几乎有主流的编程语言环境面临,例如C/C++、Java、C#、Visual
Basic、Python等。因而,OpenGL应当是天底下最常见学和行使的图开发API接口。

Open GL 概述

什么是OpenGL

OpenGL 是同一栽应用程序编程接口(Application Programming
Interface,API)
,它是平等种可以对图纸硬件装备特性开展走访的软件库。包含了500单不等之命令,可以用来安装所欲的靶子、图像以及操作,以便开发交互式的3维总计机图形应用程序。

OpenGL
被设计吧一个现代化的,硬件无关的接口。因而不需考虑总结机操作系统及窗口系统的前提下,在多种不同的图纸硬件系统及,或者完全通过软件的章程实现OpenGL
接口。

OpenGL
自身是勿包含其他履行的窗扣任何要处理用户输入输出的函数。事实上我们用通过应用程序所运行的窗口系统提供的接口来实施这看似操作。

OpenGL也未尝供任何用户达3维物体模型,或者读取图像文件的操作。我们得经过同样名目繁多几哪图元(包括点、线、三角形以及patch)来创制三维空间的体。

OpenGL 程序

  • 渲染:表示总计机从模型创立最后图像的进程。OpenGL
    只是一致栽基于光栅化的网。
  • 型(场景对象):通过几何图元(点、线、三角形)来构建的。
  • 正色器,它是图片硬件设计所实施之一律类似特殊之函数。能够清楚吧图像处理单元(GPU)编译的等同栽小型程序。
  • 季种植不同之着色阶段(shander
    stage),其中最常用的席卷终端着色器(vertex
    shader)以及片元着色器,前者用于拍卖顶点数据,后者用于拍卖光栅化后底片元数据。所有OpenGL程序都要为此到即片像样在色器
  • 帧缓存(framebuffer),像从(pixel),是显示器上很是小的可见单元。总结机体系将有着的像素保存至帧缓存当中,后者是暴发图表硬件设备管理之一模一样片独立内存区域,可以直接照射到最终之显得设备及

什么叫 光栅化?
将输入图元的数学描述转为屏幕地方对应之比如说素片元,称为关栅化

OpenGL 渲染图像的OpenGL 程序要实施之操作:

  • 打OpenGL的几哪图元遭设置数据,用于构建形状。
  • 动不同的着色器(shader)对输入的图元数据实施总计操作,判断其的职、颜色,以及另渲染属性。
  • 以输入图元的数学描述转化为同屏幕地方对应之像素片元(fragment)。这无异步也称之为光栅化(rasterization)。
  • 最终,针对光栅化过程暴发的每个片元,执行片元着色器(fragment
    shader),从而控制以此片元的最后颜色和职位。
  • 万一发必不可少,还亟需对每个片元执行有附加的操作,例如判断片元对应之对象是否可见,或者用片元的颜色跟如今屏幕地点的水彩举办融合。

案例1 绘制一个恰恰方形

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

void draw() {

    //设置清屏色
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    //设置颜色,红色
    glColor3f(1.0f, 0.0f, 0.0f);
    //设置绘图时的坐标系统
    glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
    //开始渲染
    glBegin(GL_POLYGON);
    //设置多边形的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);
    //结束渲染
    glEnd();
    //强制刷新缓冲区,保证绘制命令被执行
    glFlush();

}

int main(int argc, const char* argv[]) {
    //初始化GLUT库
    glutInit(&argc, (char**)argv);
    //创建一个窗口并制定窗口名
    glutCreateWindow("HelloWorld");
    //注册一个绘图函数,操作系统在必要时刻就会对窗体进行重新绘制操作
    glutDisplayFunc(draw);
    //进入GLUT事件处理循环,让所有的与“事件”有关的函数调用无限循环(永生循环)
    glutMainLoop();
    return 0;
}

OpenGL语法

以GLUT这些当函数号称之都是使了GLUT库的

OpenGL 渲染管线

哎呀是渲染管线?
它是同雨后春笋数据处理过程,并且以应用程序的多寡易到最后的渲染图像。

OpenGl
首先接受用户提供的几乎哪数据(顶点和几哪图元),并且将她输入到同密密麻麻在色器阶段负举行处理,包括:顶点着色、细分着色、以及最后的几乎什么地方着色,然后它以登光删化单元。光栅化单元负责对所有剪切区域外之图元生成片头数据,然后针对每个转的片元都履行一个片元着色器。

其实,只有极端着色器 和
片元在色器是须的。细分和几啥地方着色器是可选的手续。

案例2 简单绘制一个三角

2.1一旦导入什么框架

  • #include<GLTools.h>
    GLTool.h头文件包含了多数GLTool中类似C语言的单独函数
  • #include<GLShaderManager.h> 移入了GLTool 着色器管理器(shader
    Mananger)类。没有着色器,我们便无能够以OpenGL(主旨框架)举办着色。着色器管理器不仅允许我们创造并管制在色器,还提供平等组“存储方色器”,他们会举办一些方始䄦基本的渲染操作。
  • 在Mac 系统下,#include<glut/glut.h>
  • 当Windows 和
    Linux上,大家使用freeglut的静态库版本并且要加上一个庞大。
    #define FREEGLUT_STATIC
    #include<GL/glut.h>

2.2 启动GLUT

1.程序的连续“main”函数开端拍卖
GLTools函数glSetWorkingDrectory为此来安当前工作目录。实际上以Windows中是无必要之,因为工作目录默认就是与程序可实施实施顺序一样的目录。不过当Mac
OS
X中,这多少个序将当前工作文件夹改吗应用程序捆绑包中的/Resource文件夹。GLUT的先期设定自动举办了这一个被安装,可是如此受法更加安全。

2.创窗口并设置突显形式
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);
GLUT_DOUBLE:双缓存窗口,是赖绘图命令实际上是离屏缓存区执行之,然后神速变换成为窗口视图,这种艺术,平常用来转动画效果;
GLUT_DEPTH766游戏网官网,:标志将一个纵深缓存区分配为呈现的同一片,由此我们可以尽深度测试;
GLUT_STENCIL:确保我们吧会面出一个可用的沙盘缓存区。
纵深、模板测试后会细心讲到。

3.初始化GLEW库
复调用GLEW库先河化OpenGL 驱动程序中装有丢失的入口点,以保OpenGL
API对开发者完全可用。
调用glewInit()函数四次等就可以完成就同样步。在待开任何渲染在此以前,还要检查确定驱动程序的伊始化过程中无现身任何问题。

4.SetupRC()
骨子里这函数对GLUT
没有啊震慑,可是以事实上开首渲染之前,我们这里开展其余OpenGL
起先化都特别便利。这里的RC代表渲染环境,这是一个运转着之OpenGL状态机的句柄。在另OpenGL
函数从成效在此之前须创立一个渲染环境。而GLUT在大家先是不成创窗口时即形成了这项工作。

5.初叶化设置
void glClearColor(GLclampf red,GLclampf green,GLclampf blue,GLclampf alpha);

当windows 颜色成分取值范围:0-255里边
每当iOS、OS 颜色成分取值范围:0-1里面浮点值
![普遍颜色值表](/Users/liuyi/Documents/潭州育/VIP Open GL/第一天/01
备课/01–OpenGL初览下/课件/颜色值表.png
)

#include "GLShaderManager.h"

#include "GLTools.h"

#include <glut/glut.h>

//简单的批次容器,是GLTools的一个简单的容器类。
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();

    //设置三角形,其中数组vVert包含所有3个顶点的x,y,笛卡尔坐标对。

      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)

{

    //清除一个或一组特定的缓冲区
    //缓冲区是一块存在图像信息的储存空间,红色、绿色、蓝色和alpha分量通常一起分量通常一起作为颜色缓存区或像素缓存区引用。
    //OpenGL 中不止一种缓冲区(颜色缓存区、深度缓存区和模板缓存区)。

    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着色器,这个着色器只是使用指定颜色以默认笛卡尔坐标第在屏幕上渲染几何图形
    //没有着色器,在OpenGL 核心框架中就无法进行任何渲染。在后面的课程中我们讲到不用固定渲染管线,当然在前期会先学习如果使用存储着色器。

    shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);

    //提交着色器

    triangleBatch.Draw();

    //将在后台缓冲区进行渲染,然后在结束时交换到前台

    glutSwapBuffers();

}

int main(int argc,char* argv[])

{

    //设置当前工作目录,针对MAC OS X
    /*
    `GLTools`函数`glSetWorkingDrectory`用来设置当前工作目录。实际上在Windows中是不必要的,因为工作目录默认就是与程序可执行执行程序相同的目录。但是在Mac OS X中,这个程序将当前工作文件夹改为应用程序捆绑包中的`/Resource`文件夹。`GLUT`的优先设定自动进行了这个中设置,但是这样中方法更加安全。
    */
    gltSetWorkingDirectory(argv[0]);

    //初始化GLUT库

    glutInit(&argc, argv);

    /*初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指

     双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区
  2.创建窗口并设置显示模式
`glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL);`
`GLUT_DOUBLE`:双缓存窗口,是指绘图命令实际上是离屏缓存区执行的,然后迅速转换成窗口视图,这种方式,经常用来生成动画效果;
`GLUT_DEPTH`:标志将一个深度缓存区分配为显示的一部分,因此我们能够执行深度测试;
`GLUT_STENCIL`:确保我们也会有一个可用的模板缓存区。
深度、模板测试后面会细致讲到
     */

    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

    SetupRC();

    glutMainLoop();

    return 0;

}

OpenGL 常见流程

01 OpenGL 渲染流程.png

  • 极着色器 和 片元在色器是必备的。细分和几啥地方着色器是可选的捕捉。
  • OpenGL 需要拿具有的数码都保存至缓存对象被(buffer object)

用数据输出到OpenGL

当用缓存数据先导化完毕后,我们可由此调用OpenGL
的一个制图命令来要渲染几何图元。使用的凡glDrawArrays()就是一个常用之绘图命令

OpenGL 的绘图日常都是提顶点数据传到OpenGL
服务端。我们好将一个顶视为一个需统一处理的数据包。这多少个包裹的多少足以是咱用的外数(也便课),平常其中几一贯会包含地点数据。其他数据或许用来当一个像素的结尾颜色。

简介绍关键概念

  • 顶着色:对于绘制命令传输的每个终端,OpenGL都谋面调用一个极着色器来拍卖顶点相关的数码。只是将数据复制并传递到下一个着色阶段,叫做传递着色器(pass-through
    shader)。平常来说,一个错综复杂的应用程序可能带有众多及点正在色器,但以相同时刻只可以发出一个顶着色器起功能
  • 划分着色:顶点着色器处理每个终端的涉数据之后,假使以激活了分着色器,那么它们将进而处理这么些数量。(第9节介绍)
    有心人分在色器阶段会就此到少个正在色器来分别管理Patch数据并爆发最后之造型。
  • 几乎哪儿着色:允许以光栅化往日对各一个几啥地方图元做还进一步的拍卖,例如创造新的图元。这多少个着色阶段是可选的。我们在前面的学科详解
  • 图元装配:图元装配将顶点及连锁的集图元之间社团起,准备下同样步剪切和光栅化操作
  • 剪切:顶点可能赢得于视口(viewport)之外,此时及终端相关的图元会做出改变,以管相关的像素不晤面在视口外绘制。剪切(clipping)由OpenGL自动完成。
  • 光栅化:将履新后底图元(primitive)数据传递到光栅化单元,身材对应的片元(fragment).我们将一个片元是为一个“候选的像素”。也就是是可以放置于帧缓存(framebuffer)中之像素,可是其呢恐怕吃最后去,不再更新对应之像素地方。之后两单等级将会合进行片元的处理。
  • 片元着色:最终一个能够经编程控制屏幕及亮颜色之级差。在Fragment
    Shader阶段中,我们使用着色器统计片元的结尾颜色及它们的深度值。

顶着色和片元着色器的之间的别?
顶点着色器(包括分和几哪着色)决定了一个图元应该放在屏幕的呀职位,而片元着色使用这个音讯来决定某个一个片元的水彩应该是呀?

  • 逐步元的操作:这一个阶段里会接纳深度测试(depth test
    )和模板测试(stencil test)的计来决定一个片元是否可见的。

main函数里的常用函数

glutInit() 负责初始化GLUT库。它会处理向程序输入的命令行参数,并且移除其中与控制GLUT如何操作相关的部分。它必须是应用程序第一个GLUT函数,负责设置其他GLUT例程必需的数据结构。

glutInitDisplayMode() 设置了程序所使用的窗口类型。窗口设置更多的OpenGL 特性,例如RAGA颜色空间,使用深度缓存或动画效果。

glutInitWindowsSize() 设置所需的窗口大小,如果不想在这个设置一个固定值,也可以先查询显示设备的尺寸,然后根据计算机的屏幕动态设置窗口的大小。

glutCreateWindow(),它的功能和它的名字一样,如果当前的系统环境可以满足glutInitDisplayMode()的显示模式要求,这里就会创建一个窗口(此时会调用计算机窗口系统的接口)。只有GLUT创建了一个窗口之后(其中包含创建创建OpenGL环境的过程),我们才可以使用OpenGL相关的函数

glewInit()函数,属于另一个辅助库GLEW(OpenGL Extention Wrangler)。GLEW可以简化获取函数地址的过程,并且包含了可以跨平台使用的其他一些OpenGL编程方法。

glutDisplayFunc(),它设置了一个显示回调(diplay callback),即GLUT在每次更新窗口内容的时候回自动调用该例程

glutMainLoop(),这是一个无限执行的循环,它会负责一直处理窗口和操作系统的用户输入等操作。(注意:不会执行在glutMainLoop()之后的所有命令。)

着手化顶点数组对象

void glGenVertexArray(GLsizei n ,GLUINT * arrays)
分配顶点Arr对象
返回n个未使用的对象名到数组arrays中,用作顶点数组对象。返回的名字可以用来分配的缓存对象,并且它们已经使用未初始化的顶点数组集合的默认状态进行了数值的初始化。

void glBindVertexArray(GLuint array);
绑定激活对象数组
glBindVertexArray(),如果输入的变量array非0,并且是glGenVertexArrays()所返回的,那么它将创建一个新的顶点数组对象并且与其名称关联起来。如果绑定到的是一个已经创建的顶点数组对象中,那么会激活这个顶点数组对象,并且直接影响对象找那个所保存的顶点数组对象,并且将渲染状态重设为顶多数组的默认状态。
如果array不是glGenVertexArrays(),所返回的数值,或者它已经被glDeleteVertexArray()函数释放,那么这里将产生一个GL_INVALID_OPERATION错误。

在2种情况下,我们需要绑定一个对象:
    1.创建一个对象并初始化它所对应的数据时;
    2.每次准备使用这个对象,而不是当前绑定的对象时。

当我们完成对顶点数组对象的操作之后,是可以调用glDeleteVertexArrays()将它释放的。

void glDeleteVertexArrays(GLsizei n,GLuint *arrays);
删除n个在arrays中定义的顶点数组对象,这样所有的名称可以再次用作顶点数据。如果绑定顶点数组已经被删除,那么当前绑定的顶点数组对象被重设为0(类似执行了glBindBuffer()函数,并且输入参数为0)。默认的顶点数组会变成当前对象。在arrays当中未使用的名称都会被释放,但是当前顶点数组的状态不会发生任何变化


为了保证程序的完整性,可以调用gllsVertexArray()检查某个名称释放已经被保留为一个顶点数组对象了。
GLboolean gllsVertexArray(GLuint array);
如果array是一个已经用GLgenVertexArrays()创建且没有被删除的顶点数组对象的名称,那么返回GL_TRUE,如果array为0或者不是任何顶点数组对象的名称,那么返回GL_FALSE;

分红顶点缓存对象

极限数组对象承担保存一多样的数码,这一个多长史存至缓冲对象被,并且由方今绑定的顶点数组对象管理。缓存对象就是OpenGL
服务端分配和管制的一个片内存区域,并且几乎所有传入的OpenGL的数量还存储在缓存对象中。
终极缓冲对象的开首化过程以及顶数组对象的始建过程看似,不过用发于缓存添加数据的一个经过。

1.创建顶点缓存对象的名称
void glGenBuffers(GLsizei n,GLuint *buffers);

返回n个当前未使用的缓存对象名,并保存到buffers数组中。返回到buffers中的名称不一定是连续的整型数据。
这里返回的名称只用于分配其他缓存对象,它们在绑定之后只会记录一个可用状态。
0是一个保留的缓存对象名称,glGenBuffers()永远都不会返回这个值的缓存对象。

2.绑定缓存对象
出于OpenGL
中生出许多不比类其余缓存对象,由此绑定一个缓存时,需要指定相应之类型。

1.指定当前激活/绑定的对象 
void glBindBuffer(GLenum target,GLunit buffer);

参数target的类型:GL_ARRAY_BUFFER、GL_ELEMENT_ARRAY_BUFFER、GL_PIXEL_PACK_BUFFER、GL_PIXEL_UNPACK_BUFFER、GL_COPY_READ_BUFFER、GL_COPY_WRITE_BUFFER、GL_TRANSFORM_FEEDBACK_BUFFER、GL_UNIFORM_BUFFER。
顶点数据缓存使用GL_ARRAY_BUFFER

参数buffer:绑定的缓存对象名称

glBindBuffer完成3项工作:1.如果是第一次绑定buffer,且它是一个非零无符号整型,那么将创建一个与该名称相对应的新缓存对象。2.如果绑定到是一个已经创建的缓存对象,那么它将成为当前被激活的缓存对象。3.如果绑定的buffer值为0,那么OpenGL将不在对当前target应用任何缓存对象。

2.释放缓存
void glDeleteBuffers(GLSizei n,const GLuint *buffers);

删除n个保存在buffer数组中的缓存对象。被释放的缓存对象可以重用。
如果删除的缓存已经绑定,那么该对象所以绑定将会重置为默认缓存对象,即相当于用0作为参数执行glBindBuffer(),如果试图删除不存在的缓存对象,或者缓存对象为0,那么将忽略该操作(不会产生错误)

3.判断一个整数值是否是一个缓存对象的名称。
GLboolean gllsBuffer(GLuint buffer);
如果buffer是一个已经分配并且没有释放的缓存对象名称,则返回GL_TRUE。如果buffer为0或者不是一个缓存对象的名称,则返回GL_FALSE。

以数据载入缓存对象

先河化顶点缓存对象下,我们需要将极数据从目的传输至缓存对象中。这无异于步步是经glBufferData()来贯彻的。它要有2个任务:分红顶点数据所待的存储空间,然后将数据由应用程序的数组拷贝到OpenGL
服务端的内存中

glBufferData(GLenum target,GLsizeiptr size,const GLVoid *data,Glenum usage);

当OpenGL 服务端内存中分配size个存储单元(通常都是byte),用于存储数据或者索引。如果当前绑定的对象已经存在了关联数据,那么首先会删除这些数据。

参数target:
顶点属性数据,GL_ARRAY_BUFFER;
索引数据,索引数据,GL_ELEMENT_ARRAY_BUFFER;
从OpenGL 中获取的像素数据,GL_PIXEL_PACK_BUFFER;
OpenGL 的像素数据GL_PIXEL_UNPACK_BUFFER;
对于缓存直接的复制数据,GL_COPY_READ_BUFFER、GL_COPY_WRITE_BUFFER;
对于通过transform feedback 着色器获得结果,GL_TRANSFORM_FEEDBACK_BUFFER、
一致变量,GL_UNIFORM_BUFFER。
对于纹理缓存中存储的纹理数据,GL_TEXTURE_BUFFER

参数size:存储数据的总数量,data存储元素的总数*单位元素存储空间
参数data: 客户端内存的指针,以便初始化缓存对象,要么是NULL,如果传入的指针合法,那么将会有size个大小的数据从客户端拷贝到服务端。如果传入的是NULL,那么将保留size大小的未初始化的数据,以备后用。

如果所需的size大小超过了服务端能够分配的额度,那么glBufferData()将产生一个GL_OUT_OF_MEMORY错误。如果usage设置的不是可用的模式值,那么会产生GL_INVALID_VALUE错误。

一刹这明亮这么多内容,可能会见微微不方便。可是这多少个函数在背后的科目上中会重复多次产出。

开始化顶点与片元着色器

对各一个OpenGL 程序,当用的OpenGL
版本高于或者当3.1平常,都要指定至少2个在色器:顶点着色器 和
片元在色器。

对于OpenGL程序员而言,着色器使用OpenGL着质语言(OpenGL shading
Language,GLSL)编写的小型函数。GLSL是结合具有OpenGL着色器的言语。它跟C++语言相当类似。用GLSL中的备特性并无能够用来OpenGL每一个着色阶段。当我们可以以字符串的样式传输GLSL着色器到OpenGL。

以吃学员还爱拔取着色器开发,我们选以着色器字符串的内存保存至文件,并且以LoadShaders()读取文件与创立OpenGL着色程序。

发表评论

电子邮件地址不会被公开。 必填项已用*标注