纹理
为了凸显出更多的细节,我们需要使用纹理。纹理上可以有更多的细节,并且还不需要更多的点就可以完成。
为了绘制纹理,需要指定三角形的每个顶点对应纹理的哪个部分,每个顶点关联一个纹理坐标。之后在图形的片段上进行插值。
使用纹理坐标获取纹理颜色叫做采样。起始于左下角。
指定顶点
左下角对应图片的左下角。所以一个三角形的结果就是:
0,0 左下 1,0 右下 中上 0.5f,1。三个顶点会在片段中计算差值。
纹理环绕方式
纹理范围是0,0到1,1,如果设置之外会如何?
环绕方式:
- GL_REPEAT 重复
- GL_MIRRORED_REPEAT 重复但是镜像
- GL_CLAMP_TO_EDGE 边缘拉伸
- GL_CLAMP_TO_BORDER 指定为一个目标颜色
案例:
//第一个参数:使用的是2D纹理
//第二个是使用的纹理ST
//第三个就是环绕方式。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
使用的是目标颜色的选项:
float borderColor[] = {r,g,b,a};
glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_BORDER,borderColor)
纹理过滤
纹理坐标不依赖分辨率,它可以任意浮点值,他需要知道如何将纹理映射到纹理坐标上。
比如缩放场景,分辨率其实和坐标并不是一一对应的。
补充:一张图片是由无数的像素点组成的,他根据提供的坐标,去查询纹理图像上的像素,然后提取颜色。
- GL_NEAREST:临近过滤,默认的过滤方式,选择距离中心最近的那个像素。
- GL_LINE:线性过滤,基于纹理坐标附近的像素,计算一个插值,距离中心位置越大,贡献就越大
当放大或缩小的时候就需要设置过滤,可以对不同的情况设置不同的方式。
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINER);
多级渐远纹理
假设我们有一个包含着上千物体的大房间,每个物体上都有纹理。有些物体会很远,但其纹理会拥有与近处物体同样高的分辨率。由于远处的物体可能只产生很少的片段,OpenGL从高分辨率纹理中为这些片段获取正确的颜色值就很困难,因为它需要对一个跨过纹理很大部分的片段只拾取一个纹理颜色。在小物体上这会产生不真实的感觉,更不用说对它们使用高分辨率纹理浪费内存的问题了。
总结一下:
会两个结果
- 一个是产生不真实的感觉
- 高分辨率浪费内存
OpenGL使用一种叫做多级渐远纹理(Mipmap)的概念来解决这个问题,它简单来说就是一系列的纹理图像,后一个纹理图像是前一个的二分之一。
多级渐远纹理背后的理念很简单:距观察者的距离超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最适合物体的距离的那个。由于距离
远,解析度不高也不会被用户注意到。同时,多级渐远纹理另一加分之处是它的性能非常好。让我们看一下多级渐远纹理是什么样子的:
在渲染中切换多级渐远纹理级别(Level)时,OpenGL在两个不同级别的多级渐远纹理层之间会产生不真实的生硬边界。就像普通的纹理过滤一样,
切换多级渐远纹理级别时你也可以在两个不同多级渐远纹理级别之间使用NEAREST和LINEAR过滤。为了指定不同多级渐远纹理级别之间的过滤方
式,你可以使用下面四个选项中的一个代替原有的过滤方式:
这个我认为是从近处走到远处的时候,会有一个切换,这个切换会产生这种效果;
过滤方式 描述
GL_NEAREST_MIPMAP_NEAREST 使用最邻近的多级渐远纹理来匹配像素大小,并使用邻近插值进行纹理采样
GL_LINEAR_MIPMAP_NEAREST 使用最邻近的多级渐远纹理级别,并使用线性插值进行采样
GL_NEAREST_MIPMAP_LINEAR 在两个最匹配像素大小的多级渐远纹理之间进行线性插值,使用邻近插值进行采样
GL_LINEAR_MIPMAP_LINEAR 在两个邻近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样
一个常见的错误是,将放大过滤的选项设置为多级渐远纹理过滤选项之一。这样没有任何效果,因为多级渐远纹理主要是使用在纹理被缩小的
情况下的:纹理放大不会使用多级渐远纹理,为放大过滤设置多级渐远纹理的选项会产生一个GL_INVALID_ENUM错误代码。
mipmap只使用在缩小的时候,并不适用于放大
使用纹理
使用之前将其加载到内存中,但是图片格式各种各样,所以将其转成字节序列
生成纹理
纹理也是使用ID引用的。
- 创建一个纹理
(1)生成纹理的数量
(2)存储的位置。
glGenTextures(1,&texture);
- 绑定纹理
glbindTexture(GL_TEXTURE_2D,texture);
绑定了就可以对纹理进行操作了。
- 使用图片数据生成一个纹理。
(1)2d纹理
(2)多级渐远纹理
(3)存储格式
(4)宽和高
(5)设置为0 没有为什么。
(6)格式和数据类型
(7)数据
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height,-,GL_RGB,GL_UNSIGNED_BYTE,data);
上面的并不是设置多级渐远纹理
glGenerateMipmap(GL_TEXTURE_2D);
这句会自己生成多级渐远纹理
释放图片资源
图片资源绑定到纹理之后就可以释放了。
应用纹理
- 给纹理坐标设置坐标值
- 将纹理传递给片段着色器
(1)vertext书写
attribute vec2 vCoordinate;
(2)获取位置
glHCoordinate = GLES20.glGetAttribLocation(mProgram, "vCoordinate");
(3)设置值
GLES20.glVertexAttribPointer(glHCoordinate, 2, GLES20.GL_FLOAT, false, 0, vCoordinate);
上面那些和之前绘制图形原理一样,没啥可以说的了。
(4)纹理 ,片段着色器中访问纹理对象,需要一个内奸数据类型,采样器,以及纹理类的后缀samplerxD,作用就是将一个纹理添加到片段着色器中。
uniform sampler2D vTexture;
(5)得到位置 给纹理赋值
glHTexture = GLES20.glGetUniformLocation(mProgram, "vTexture");
(6)绑定并使用
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
GLES20.glUniform1i(glHTexture, 0);
纹理单元(没看懂,下来在看)(已重新看完 )
sampler2D变量是一个uniform,但是没有使用uniform赋值.使用uniform1i的方式,这样可以在一个片段中设置多个纹理,一个纹理位置通常是一个纹理单元,一般的0是默认
激活的纹理,可以不需要给它分配一个位置(分配也是没有问题的。)
如何使用多个纹理??
将纹理赋值给采样器,一次绑定多个纹理,首先激活纹理单元。
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,texture);
激活之后,下来绑定纹理单元,0默认是激活的,可以不需要写。
默认是16个纹理。
使用:
- shader
uniform sampler2D texture1;
uniform sampler2D texture2;
- 渲染
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);