01-初识OpenGL

1.OpenGL 简介

OpenGL 是⼀一种图形应⽤用程序编程接⼝口(Application Programming Interface, API).简单理理解就是开发的 图形库。主要应用于:

  • 视频,图形,图⽚处理理
  • 2D/3D 游戏引擎开发
  • 科学可视化
  • 医学软件开发
  • CAD(计算机辅助技术)
  • 虚拟实境(AR,VR)
  • AI ⼈人⼯工智能

1.1 OpenGL 和OpenG ES的区别

OpenGL 与 OpenGL ES 的主要区别,在于OpenGL ES 主要针对嵌⼊入式设备使⽤用

1.2 着色器的基本认识

  • 图元: 组成图像的基本单元
  • OpenGL 渲染管线: ⼀系列有序的处理阶段的序列,用于把我们应用中的数据转化到OpenGL 生成 一个最终的图像的一个过程
  • GLSL: 专⻔为图形开发设计的编程语⾔

1.3 着色器的渲染流程

着色器中,顶点着色器和片元着色器是必选的,其他都是可选的。
着色器的渲染流程

2. OpenGL 基础渲染

2.1 基础图形管线

在OpenGL 3.0之前,OpenGL 包含一个固定功能的管线,它可以在不使⽤着色器的情况下处理几何与像素数据。在3.1版本开始,固定管线从核⼼ 模式去掉。因此现在需要使⽤着色器来完成工作。
OpenGL 中的图元只不过是顶点的集合以预定义的方式结合一起罢了。下图为管线流程:

理解客户机、服务器
管线分为上下2部分,上部分是客户端,而下半部分则是服务端。

  • 客户端是存储在CPU存储器中的,并且在应用程序中执⾏,或者在主系 统内存的驱动程序中执行。驱动程序会将渲染命令和数组组合起来,发送给服务器执⾏!(在⼀一台典型的个⼈人计算机上,服务器器就是实际上就 是图形加速卡上的硬件和内存)
  • 服务器 和 客户机在功能上也是异步的。 它们是各自独⽴的软件块或硬 件块。我们是希望它们2个端都尽量在不停的工作。客户端不断的把数据块和命令块组合在一起输送到缓冲区,然后缓冲区就会发送到服务器 执行。
  • 如果服务器停止工作等待客户机,或者客户机停⽌⼯工作来等待服务器做好接受更多的命令和准备,我们把这种情况成为管线停滞

2.2 着色器

渲染过程中,必备的两个着色器:顶点着色器和片元着色器.

2.3 三种想OpenGL 着色器传递渲染数据的方法

  • 属性
    就是对一个顶点都要作出改变的数据元素.实际上,顶点位置本身就是一个属性. 属性可以是浮点类型,整型,布尔类 型等.
    (1)属性总是以四维向量的形式进行内部存储的,即使我们不会使用所有的 4个分量。一个顶点位置可能存储(x,y,z),将占有4个分量中的3个。
    (2)实际上如果是在平面情况下:只要在xy平⾯上就能绘制,那么Z分量就 会自动设置为0;
    (3)属性还可以是:纹理坐标、颜⾊色值、光照计算表⾯面法线
    (4)在顶点程序(shader渲染)可以代表你想要的任何意义。因为都是你设 定的。
  • uniform
    通过设置Uniform 变量就紧接着发送一个图元批次处理理命令. Uniform 变量实际上可以无限次的使用. 设置一个应⽤于 整个表⾯的单个颜色值,还可也是一个时间值.
  • 纹理

2.4 着色器常用代码:

  • 定义着色器
    GLShaderMananger shaderMananger;
  • 初始化着色器
    shaderMananger.initalizeStockShaders();
  • 使用
    shaderMananger.userStockMananger(参数列列表);

3. 创建坐标系

3.1 正投影

在这里插入图片描述

3.2 透视投影

在这里插入图片描述
透视投影会进⾏透视除法对距离观察者很远的对象进行缩短和收缩。在投影到屏幕之后,视景体背面与视景体正⾯的宽度测量量标准不同。

GLFrustum类通过setPerspective 方法为我们构建一个平截头体。
 CLFrustum::SetPerspective(float fFov,float fAspect,float fNear ,float fFar);
参数:
fFov:垂直方向上的视场角度
fAspect:窗口的宽度与高度的纵横比
fNear:近裁剪面距离
fFar:远裁剪面距离
纵横⽐比 = 宽(w)/高(h)

4.存储着色器的使用

4.1 GLShaderManager的初始化

// GLShaderManager 的初始化
 GLShaderManager shaderManager; 
 shaderManager.InitializeStockShaders();

4.2 GLShaderManager属性

在这里插入图片描述

4.3 GLShanderManager 的 uniform值

  • 一般情况,要对几何图形进行渲染,我们需要给对象递交属性矩阵,⾸先要绑定我们想要使⽤的着⾊程序上,并提供程序的uniform值。但是GLShanderManager 类可以暂时为我们完成工作。
  • useStockShader 函数会选择一个存储着色器并提供这个着⾊器的uniform值。
GLShaderManager.UserStockShader(GLeunm shader...);
  1. 单位着色器
GLShaderManager.UserStockShader(GLT_ATTRIBUTE_VERTEX,GLfloat vColor[4]);

单位着色器:只是简单地使用默认笛卡尔坐标系(坐标范围(-1.0, 1.0))。所有的片段都应用同一种颜色,几何图形为 实心和未渲染 的。
需要设置存储着⾊器一个属性: GLT_ATTRIBUTE_VERTEX(顶点分量)
参数2:vColor[4],你需要的颜色

  1. 平⾯着⾊器
GLShaderManager.UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[1 6],GLfloat vColor[4]);

参数1:平⾯着⾊器
参数2:允许变化的4*4矩阵
参数3:颜⾊
它将统一着⾊器进行了拓展。允许为几何图形变换指定一个 4 * 4 变换矩阵。经常被称为“模型视图投影矩阵".

  1. 上色着色器
GLShaderManager.UserStockShader(GLT_SHADER_SHADED,GLfloat mvp [16]);

在几何图形中应用的变换矩阵。
需要设置存储着色器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和
GLT_ATTRIBUTE_COLOR(颜⾊分量) 2个属性。颜⾊色值将被平滑地插⼊顶 点之间(平滑着色)

  1. 默认光源着⾊器
GLShaderManager.UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLfl oat mvMatrix[16],GLfloat pMatrix[16],GLfloat vColor[4]);

参数1:默认光源着色器
参数2:模型视图矩阵
参数3:投影矩阵
参数4:颜⾊色值
这种着⾊器,是对象产⽣阴影和光照的效果。 需要设置存储着色器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和
GLT_ATTRIBUTE_NORMAL(表⾯法线)

  1. 点光源着⾊器
GLShaderManager.UserStockShader(GLT_SHADER_DEFAULT_LIGHT_DIEF ,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3] ,GLfloat vColor[4]);

参数1:点光源着⾊器
参数2:模型视图矩阵
参数3:投影矩阵
参数4:视点坐标光源位置
参数5:颜⾊色值
点光源着⾊器和默认光源着⾊器很相似,区别在于:光源位置是特定的。 同样需要设置存储着⾊器的 GLT_ATTRIBUTE_VERTEX(顶点分量) 和
GLT_ATTRIBUTE_NORMAL(表⾯法线)

  1. 纹理替换矩阵
GLShaderManager.UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GL float mvMatrix[16],GLint nTextureUnit);

着色器通过给定的模型视图投影矩阵,使用绑定到 nTextureUnit (纹理单元) 指定纹理单元的纹理对几何图形进⾏变化。
⽚段颜色:是直接从纹理样本中直接获取的。
需要设置存储着⾊器的 GLT_ATTRIBUTE_VERTEX(顶点分量量) 和
GLT_ATTRIBUTE_NORMAL(表⾯法线)

  1. 纹理调整着⾊器
GLShaderManager.UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGH T_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLight Pos[3],GLfloat vBaseColor[4],GLint nTextureUnit);

参数1:纹理光源着⾊器
参数2:投影矩阵
参数3:视觉空间中的光源位置
参数4:⼏何图形的基本色
参数5:将要使用的纹理单元
将一个纹理通过漫反射照明计算机进⾏调整(相乘)。光线在视觉空间中 的位置是给定的。
需要设置存储着⾊器的 GLT_ATTRIBUTE_VERTEX(顶点分量量) 和
GLT_ATTRIBUTE_TEXTURE0(纹理坐标)、GLT_ATTRIBUTE_NORMAL(表面法线)

5. 简单绘制图像

5.1 点

点,是最简单的图像。每个特定的顶点在屏幕上都仅仅是一个单独的点。默认情况下,点的大小是一个像素的大小。

  • 修改点的大小
//1.最简单也是最常用的,4.0f,表示点的大小 
glPointSize(4.0f);
//2. 设置点的范围和点与点的之间的间距
GLfloat sizes[2] = {2.0f,4.0f};
GLfloat step = 1.0f;
//获取点大小范围和最小步长
 glGetFloatv(GL_POINT_SIZE_RANGE,sizes); glGetFloatv(GL_POINT_GRAULARITY,&step);
//3.通过使用程序点大小模式来设置点大小
glEnable(GL_PROGRAM_POINT_SIZE);
// gl_PointSize 可以在着色器源码直接写
gl_PointSize = 5.0;

5.2 线

比点更进一步的是独立线段。一个线段就是2个顶点之间绘制的。默认情况下,线段的宽度是一个像素。线段的宽度是一个像素。改变线段唯一的方式通过:

glLineWidth(2.5f);

5.3 线带

线段连续从一个顶点到下一个顶点绘制的线段,以形成一个真正链接的点的线段。

5.4 线环

线环是线带的一种简单拓展。在线带的基础上额外增加一条将线带闭合。

5.5 绘制三角形

最简单的实体多边形就是三角形,它只有3个边。光栅化硬件最欢迎三角形。并且现在三角形已经是OpenGL 中支持的唯一一种多边形。

5.6 环绕

在这里插入图片描述
在这里插入图片描述
默认情况下,OpenGL认为具有逆时针方向环绕的多边形是正面的。而右侧的顺时针方向三角形是三角形的背面。

//定义前向和背向的多边型
glFrontFace(mode)
参数:GL_CW | GL_CCW
GL_CCW:表示传入的mode会选择逆时针为前向
GL_CW:表示顺时针为前向
默认: GL_CCW,逆向时针为前向。

5.7 三角地带

在这里插入图片描述

5.8 三角形扇

除了三角形带之外,还可以使用GL_TRINGLE_FAN 创建一组围绕一个中心点的相连三角形。
在这里插入图片描述

6.OpenGL 深度测试

6.1 在渲染过程中可能产生的问题

在绘制3D场景的时候,我们需要决定哪些部分是对观察者可见的,或者哪些部分是对观察者不可见的。对于不可见的部分,应该及早丢弃。例如,一个不透明的墙壁后面,就不应该渲染,这种情况叫做**“隐藏面消除”**。
在这里插入图片描述

6.2 解决方案

  • 油画算法

先绘制场景中的离观察者比较远的物体,再绘制比较近的物体。
例如下图的图例:先绘制红色部分,再绘制黄色部分,最后再绘制灰色部分,即可解决隐藏面消除的问题。
在这里插入图片描述
油画法的弊端:
使用油画算法,只能将场景按照物理距离观察者的距离远近排序,由远及近的绘制。那么会出现一种情况,就是无法判断物体的远近时,就无法处理,如下图:
在这里插入图片描述

  • 正背面剔除(Face Culling)

背景:

  • 从一个立方体的任务位置和方向上看,不可能看到多于3个面。
  • 那么我们就不需要去绘制那部分多与的的看不到的另外的面。
  • 如果能以某种方式去丢弃这部分数据,OpenGL在渲染性能即可提高超过50%。
    任何平面都有2个面,正面\背面。意味着你一个时刻只能看到一面。
    OpenGL 可以做到检查所有正面朝向观察者的面,并渲染它们。从而丢弃背面朝向的面。

OpenGL是可以通过分析顶点数据的顺序来判断绘制的图形,哪个是正面,哪个是背面。
在这里插入图片描述
可以以立方体为例分析其正背面:
在这里插入图片描述

分析

  • 左侧三角形顶点顺序为:1-2-3,右侧三角形的顶点顺序为:1-2-3.
  • 当观察者在右侧时,则右边的三角形方向为逆时针方向为正面,左侧的三角形为顺时针则为背面。
  • 当观察者在左侧时,则左侧的三角形为逆时针方面判定为正面,右侧的三角形为顺时针则为背面。
  • 正背面剔除的常用代码

开启表面剔除(默认背面剔除)
void glEnable(GL_CULL_FACE);
关闭表面剔除(默认背面剔除)
void glDisable(GL_CULL_FACE);
用户选择剔除那个面(正面/背面)
void glCullFace(GLenum mode);
mode参数为: GL_FRONT,GL_BACK,GL_FRONT_AND_BACK ,默认GL_BACK
用户指定绕序那个为正面
void glFrontFace(GLenum mode);
mode参数为: GL_CW,GL_CCW,默认值:GL_CCW
例如,剔除正面实现(1)
glCullFace(GL_BACK);
glFrontFace(GL_CW);
例如,剔除正面实现(2)
glCullFace(GL_FRONT);

  • 深度测试

7.深度测试

7.1 了解深度

  • 什么是深度?

深度就是该像素点在3D世界中距离摄像机的距离,即Z值

  • 什么是深度缓冲区?

深度缓冲区,就是一块内存区域,专门存储每个像素点(绘制在屏幕上的)深度值。深度值(z值)越大,则离摄像机就越远。

  • 为什么需要深度缓冲区?

在不使用深度测试的时候,如果先绘制一个距离比较近的物体,再绘制距离比较远的物体,则距离远的位图因为后绘制,会把距离近的物体覆盖掉。有了深度缓冲区后,绘制物体的顺序就不那么重要。
只要存在深度缓冲区,OpenGL都会把像素的深度值写入到缓冲区中。除非调用glDepthMask(GL_FALSE)来禁止写入。

7.2 使用深度测试方法(Z-buffer)

  • 深度测试
  • 深度缓冲区(DepthBuffer)和颜色缓存区(ColorBuffer)是对应的。
  • 颜色缓冲区存储像素的颜色值,而深度缓冲区存储像素的深度信息。
  • 在决定是否绘制一个物体的表面时,首先要将表面对应的像素的深度值与当前深度缓冲区中的值进行比较。
  • 如果大于深度缓冲区的值,则丢弃这部分,否则利用这个像素对应的深度值和颜色值,分别更新深度缓冲区和颜色缓冲区。
  • 这个过程称为“深度测试”。
  • 使用深度测试
  • 深度缓冲区,一般由窗口管理系统 GLFW创建,深度值有16位、24位、32位表示。通常24位,位数越高,深度精确度越好。

  • 开启深度测试:
    glEnable(GL_DEPTH_TEST);

  • 在绘制场景前,清除颜色缓冲区、深度缓冲区:
    glClearColor(0.0f,0.0f,0.0f,1.0f );
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  • 清除深度缓冲区默认值为1.0,表示最大的深度值,深度值的范围为(0,1)之间。值越小表示越靠近观察者,值越大表达离观察者越远。

  • 指定深度测试判别式
    在这里插入图片描述

  • 打开/阻断 深度缓存去写入
    void glDepthMask(GLBool value);
    value : GL_TURE 开启深度缓冲区写⼊;
    GL_FALSE 关闭深度缓冲区写⼊

7.3 什么深度测试存在的问题

  • ZFighting 闪烁问题
  • 在开启深度测试后,OpenGL就不会再去绘制模型被挡住的部分。这样实现的显示更加真实。
  • 但是由于深度缓冲区精度的限制对于深度相差非常小的情况,OpenGL就可能出现不能正确判断两者的深度值,就会导致深度测试的结果不可预测。
  • 显示出来的现象时交错闪烁,叫做ZFighting闪烁问题。在这里插入图片描述

7.4 ZFighting闪烁问题的解决

  1. 第一步:启用Polyon Offset方式解决
    让深度值之间产生间隔,如果2个图像之间有间隔,就意味着不会产生干涉。可以理解为执行深度测试前,将立方体的深度值做一些细微的增加。于是就能讲重叠的2个图形深度值之间有所区分。
  • 启用Polygon Offset方式
    glEnable(GL_POLYON_OFFSET_FILL)
    参数列表:
    GL_POLYGON_OFFSET_POINT 对应光栅化模式: GL_POINT
    GL_POLYGON_OFFSET_LINE 对应光栅化模式: GL_LINE
    GL_POLYGON_OFFSET_FILL 对应光栅化模式: GL_FILL
  1. 第二步:指定偏移量
  • 通过glPolyonOffset 来指定.glPolygonOffset;需要两个参数:factor,units
  • 每个Fragment 的深度值增加,如下所示的偏移量:
    Offset = ( m * factor ) + ( r * units);
    m : 多边形的深度的斜率的最大值,理解为一个多边形越是与近裁剪面平行,m 就越接近于0.
    r : 能产生于窗口坐标系的深度值中可分辨的差异最小值.
    r 是由具体OpenGL 平台指定的 一个常量.
  • 一个大于0的Offset 会把模型推到离你(摄像机)更远的位置,相应的一个小于0的Offset 会把模型拉近
  • 一般⽽言,只需要将-1.0 和 0.0 这样简单赋值给glPolygonOffset 基本可以满足需求.
  • 3.第三步关闭Polygon Offset

glDisable(GL_POLYGON_OFFSET_FILL)

  • 4.ZFighting闪烁问题预防
  • 不用讲两个物体靠的太近,避免渲染时三角形叠在一起。这种方式要求对场景中物体插入一个小量的偏移,那么就可能避免ZFighting现象。当然这种手动插入小的偏移是要付出代价的。
  • 尽可能将近裁截面设置得离观察者远一些。上面我们看到,在近裁剪平⾯附近,深度的精确度是很高 的,因此尽可能让近裁剪面远一些的话,会使整个裁剪范围内的精确度变高一些。但是这种方式会使 离观察者较近的物体被裁减掉,因此需要调试好裁剪面参数。
  • 使用更高位深度缓冲区,通常使用的深度缓冲区是24位,现在有一个写硬件使用32位的缓冲区,使精确度得到提高。

8. 裁剪

在OpenGL中提高渲染的一种方式,就是“裁剪”。只刷新屏幕上发生变化的部分。OpenGL允许将要进行渲染的窗口去指定一个裁剪框。

  1. 基本原理
  • 在渲染时限制绘制区域,通过此技术可以在屏幕(帧缓冲)指定一个矩形区域。
  • 启用裁剪测试之后,不在此矩形区域的片元被丢弃,只有在此矩形区域的片元才有可能进入帧缓冲。
  • 因为实际达到的效果就是在屏幕上开辟了一个小窗口,可以再其中进行制定内容的绘制。
  1. 裁剪的使用代码

**1 .开启裁剪测试 **
glEnable(GL_SCISSOR_TEST);
2.关闭裁剪测试
glDisable(GL_SCISSOR_TEST);
3.指定裁剪窗⼝
void glScissor(Glint x,Glint y,GLSize width,GLSize height);
x,y:指定裁剪框左下⻆角位置;
width , height:指定裁剪尺寸

  1. 理解窗口、视口、裁剪区域
    (1) 窗口

窗口就是显示界面

(2)视口

视口就是窗口中用来显示图形的一块矩形区域,他可以和窗口等大,也可以比窗口大或者小。只有绘制在视口区域的图形才能被显示,如果图形有一部分超出了视口区域,那么那一部分就看不到的。
通过glViewport()函数设置。

(3)裁剪区域

裁剪区域(平行投影):就是视口矩形区域的最小最大x坐标(left,right)和最小最大y坐标(bottom,top),而不是窗口的最小最大x坐标和y坐标。
通过glOrtho()函数设置,这个函数还需指定最近最远z坐标,形成一个立体的裁剪区域。
在这里插入图片描述

9. 混合

  • OpenGL渲染时,会把颜色值存在颜色缓存区中,每个片段的深度值也放在深度缓冲区。
  • 当深度缓冲区被关闭时,新的颜色将简单的覆盖原来颜色缓冲区的颜色值;
  • 当深度缓冲区再次打开时,新的颜色片段只是当它们比原来的值更接近裁截面时才会替换原来的颜色片段。
  • glEnable(GL_BlEND);

9.1 组合颜色

  • 目标颜色:已经存储在颜色缓冲区的颜色值,即旧的颜色值
  • 源颜色:作为当前渲染命令结果进入颜色缓存区的颜色值, 即新的颜色值
  • 混合功能被启动时,源颜色和目标颜⾊的组合⽅式是混合方程式控制的。在默认情况下,
    混合方程式如下所示:

Cf = (Cs * S) + (Cd * D)
Cf :最终计算参数的颜色
Cs : 源颜⾊
Cd :目标颜色
S:源混合因子
D:目标混合因子

9.2 设置混合因子

设置混合引子,需要用到glBlendFun函数:

glBlendFunc(GLenum S,GLenum D);
S:源混合因⼦
D:目标混合因⼦
在这里插入图片描述
表中R、G、B、A 分别代表 红、绿、蓝、alpha。
表中下标S、D,分别代表源、⽬目标
表中C 代表常量颜⾊(默认⿊色)

总结

  • 最终颜色是以原先的红色(目标颜色)与 后来的颜色(源颜色)进⾏组合。
  • 源颜⾊的alpha值 越高,添加后来颜⾊成分越高,目标颜⾊所保留的成分就会越少。
  • 混合函数经常⽤于实现在其他⼀些不透明的物体前面绘制一个透明物体的效果。

10. 抗锯齿

要知道,图片在屏幕中显示都是由一个个像素点组成的。当无限放大一张图片时,就会发现颜色的边界都是锯齿状。为了优化这种现象,有了抗锯齿的功能。抗锯齿功能,更多用于点和线中。

抗锯齿混合的2个功能:

  • 颜色组合
  • 抗锯齿

要知道,抗锯齿只能优化显示效果,但是并不能消除这种现象。

抗锯齿的使用

//开启混合处理
glEnable(GL_BLEND);
//指定混合因⼦子 GLBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
//指定混合⽅方程式
glBlendEquation(GL_FUNC_ADD);
//对点进⾏抗锯齿处理
glEnable(GL_POINT_SMOOTH);
//对线进⾏抗锯⻮处理
glEnable(GL_LINE_SMOOTH);
//对多边形进⾏行行抗锯⻮处理glEnable(GL_POLYGON_SMOOTH);

11.多重采样

多重采样也是解决抗锯齿的一种方式,只不过比上面的抗锯齿方法的不同在于:多重采样更多是应用于多边形中。

多重采样的使用

  • 1.可以调用 glutInitDisplayMode 添加采样缓存区
    glutInitDisplayMode(GLUT_MULTISAMPLE);
  • 2.可以使用glEnable| glDisable组合使⽤GLUT_MULTISAMPLE 打开|关闭 多重采样。
    glEnable(GLUT_MULTISAMPLE);
    glDisable(GLUT_MULTISAMPLE);

12.纹理

  • 改变纹理的像素的存储方式

void glPixelStorei(GLenum pname,GLint param);

  • 恢复像素存储⽅式

void glPixelStoref(GLenum pname,GLfloat param);

  • 从颜⾊缓存区内容作为像素图直接读取

void glReadPixels(GLint x,GLint y,GLSizei width,GLSizei height, GLenum format, GLenum type,const void * pixels);

  • 参数1:x,矩形左下⻆角的窗⼝坐标
  • 餐宿2:y,矩形左下⻆角的窗⼝坐标
  • 参数3:width,矩形的宽,以像素为单位
  • 参数4:height,矩形的⾼,以像素为单位
  • 参数5:format,OpenGL 的像素格式 参考 下图
    在这里插入图片描述 - 参数6:type,解释参数pixels指向的数据,告诉OpenGL 使⽤缓存区中的什么 数据类型来存储颜⾊分量,像素数据的数据
  • 读写缓存

glReadBuffer(mode);—> 指定读取的缓存 glWriteBuffer(mode);—> 指定写⼊的缓存

  • 载入纹理的方法

void glTexImage1D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLint border,GLenum format,GLenum type,void *data);

void glTexImage2D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,void * data);

void glTexImage3D(GLenum target,GLint level,GLint internalformat,GLSizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,void *data);

  • target:GL_TEXTURE_1DGL_TEXTURE_2DGL_TEXTURE_3D
  • Level:指定所加载的mip贴图层次。⼀般我们都把这个参数设置为0。
  • internalformat:每个纹理单元中存储多少颜⾊成分。
  • width、height、depth参数:指加载纹理的宽度、⾼度、深度。==注意!==这些值必须是 2的整数次⽅。(这是因为OpenGL 旧版本上的遗留下的⼀个要求。当然现在已经可以⽀持不是 2的整数次⽅。但是开发者们还是习惯使⽤以2的整数次⽅去设置这些参数。)
  • border参数:允许为纹理贴图指定⼀个边界宽度。
  • format、type、data参数:与我们在讲glDrawPixels 函数对于的参数相同
  • 更新纹理

void glTexSubImage1D(GLenum target,GLint level,GLint xOffset,GLsizei width,GLenum format,GLenum type,const GLvoid *data);

void glTexSubImage2D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const GLvoid *data);

void glTexSubImage3D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLint zOffset,GLsizei width,GLsizei height,GLsizei depth,Glenum type,const GLvoid * data);

  • 插入替换纹理

void glCopyTexSubImage1D(GLenum target,GLint level,GLint xoffset,GLint x,GLint y,GLsizei width);

void glCopyTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yOffset,GLint x,GLi y,GLsizei width,GLsizei height);

void glCopyTexSubImage3D(GLenum target,GLint level,GLint xoffset,GLint yOffset,GLint zOffset,GLint x,GLint y,GLsizei width,GLsizei height);

  • 使⽤颜⾊缓存区加载数据,形成新的纹理使⽤

void glCopyTexImage1D(GLenum target,GLint level,GLenum internalformt,GLint x,GLint y,GLsizei width,GLint border);

void glCopyTexImage2D(GLenum target,GLint level,GLenum internalformt,GLint x,GLint y,GLsizei width,GLsizei height,GLint border);

其中,x,y 在颜⾊缓存区中指定了开始读取纹理数据的位置;
缓存区⾥的数据,是源缓存区通过glReadBuffer设置的。

  • 纹理对象的使用
    1.使⽤函数分配纹理对象

    void glGenTextures(GLsizei n,GLuint * textTures);

    • 指定纹理对象的数量
    • 指定纹理对象的指针(指针指向⼀个⽆符号整形数组,由纹理对象标识符填充)。

    2.绑定纹理状态

    void glBindTexture(GLenum target,GLunit texture);

    • 参数target:GL_TEXTURE_1DGL_TEXTURE_2DGL_TEXTURE_3D
    • 参数texture:需要绑定的纹理对象

    3.删除绑定纹理对象

    void glDeleteTextures(GLsizei n,GLuint *textures)

    • 纹理对象
    • 纹理对象指针(指针指向⼀个⽆符号整形数组,由纹理对象标识符填充)。

    4.测试纹理对象是否有效

    GLboolean glIsTexture(GLuint texture);

    • 如果texture是⼀个已经分配空间的纹理对象,那么这个函数会返回GL_TRUE,否则会返回GL_FALSE。

    5.设置纹理参数

    glTexParameterf(GLenum target,GLenum pname,GLFloat param);

    glTexParameteri(GLenum target,GLenum pname,GLint param);

    glTexParameterfv(GLenum target,GLenum pname,GLFloat *param);

    glTexParameteriv(GLenum target,GLenum pname,GLint *param);

    • 参数1:target,指定这些参数将要应⽤在那个纹理模式上,⽐如GL_TEXTURE_1DGL_TEXTURE_2DGL_TEXTURE_3D
    • 参数2:pname,指定需要设置哪个纹理参数
    • 参数3:param,设定特定的纹理参数的值
  • 6.设置纹理过滤方式

(1)邻近过滤(GL_NEAREST):是指取附近一个颜色值返回
在这里插入图片描述
(2)线性过滤(GL_LINEAR):取附近周围的点平均颜色返回
在这里插入图片描述
3. 两种纹理方式的比较
在这里插入图片描述
4.使用方法

  • 纹理缩⼩时,使⽤邻近过滤
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST)
  • 纹理放⼤时,使⽤线性过滤
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)

5.设置环绕方式在这里插入图片描述
在这里插入图片描述

  • 代码设置如下:
  • glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_S,GL_CLAMP_TO_EDGE);

  • glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_T,GL_CLAMP_TO_EDGE);

  • 参数1:GL_TEXTURE_1DGL_TEXTURE_2DGL_TEXTURE_3D
  • 参数2:GL_TEXTURE_WRAP_SGL_TEXTURE_TGL_TEXTURE_R,针对s,t,r坐标
  • 参数3:GL_REPEATGL_CLAMPGL_CLAMP_TO_EDGEGL_CLAMP_TO_BORDER
    (1)GL_REPEAT:OpenGL 在纹理坐标超过1.0的⽅向上对纹理进⾏重复;
    (2)GL_CLAMP:所需的纹理单元取⾃纹理边界或TEXTURE_BORDER_COLOR.
    (3)GL_CLAMP_TO_EDGE环绕模式强制对范围之外的纹理坐标沿着合法的纹理单元的最后⼀⾏或者最后⼀ 列来进⾏采样。
    (4)GL_CLAMP_TO_BORDER:在纹理坐标在0.0到1.0范围之外的只使⽤边界纹理单元。边界纹理单元是 作为围绕基本图像的额外的⾏和列,并与基本纹理图像⼀起加载的。

6.设置MIP贴图

  • 设置mip贴图基层 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_BASE_LEVEL,0);
  • 设置mip贴图最⼤层 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_BASE_LEVEL,0);
  1. 经过Mip贴图的纹理过滤
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值