OpenGL游戏引擎开发[4]-在OpenGL绘制纹理

上一节我们学会了使用OpenGL着色器,但是在片段着色器中,我们使用简单纯色来绘制物体,这一节,我们要在片段着色器中使用采用器对纹理进行采样输出,作为物体表面的颜色,进而绘制带有纹理贴图的物体。

纹理

纹理简单来说就是一张图片,最常见的就是王者荣耀中英雄的皮肤,当然,这里只说游戏角色的外观,因为不同的皮肤还有不同的特效,甚至有不同的人物动作。不同的游戏人物外观就是换了不同纹理贴图。

根据纹理的作用,纹理贴图可以分为:普通纹理(就是着色用的)、法线贴图、切线切图… 顾名思义,普通纹理中存储的就是颜色值,就是我们常看的普通图像;法线贴图中每个像素存储的是法线的值,切线贴图每个像素存的是切线… 后两种属于 奇技淫巧,它们自由它们的用途。我们这节主要讲如何在OpenGL中使用普通的纹理贴图,其他的都使用起来都差不多,只不过用途不同罢了。

纹理坐标

纹理坐标就是用来确定纹理中每个像素的位置的,它的坐标范围是[0,1],这是一个比例值,也就说,任何大小的纹理贴图的纹理坐标都是这个范围。那么有人问,那么超过这个范围怎么办?物体的颜色怎么赋值呢?不同大小的物体,我们使用同一个纹理,表现效果相同吗?… 别着急,我们马上就要说了。

先来看个例子,我们怎么把左边这个图,贴到右边的矩形上。其实很简单,就是绘制顶点的时候,不仅传递顶点的位置,还要传递定该顶点对对应的纹理坐标,要不然前面说,纹理坐标也是顶点的一个属性呢?这样我们在着色器中,根据顶点的纹理坐标去纹理中采样,获得纹理的颜色,输出为顶点的颜色,这样,顶点不就像“穿了衣服”一样了吗?而不是我们前面设置的纯色。

OpenGL游戏引擎开发[4]-在OpenGL绘制纹理_第1张图片

有的书上说,纹理坐标的原点在图像的左上角,有的书上说,纹理坐标的原点在图像的左下角。这。。。你们为这个问题困扰过吗?

OpenGL游戏引擎开发[4]-在OpenGL绘制纹理_第2张图片

我从来不担心这个问题,爱谁谁,反正不是在左上角就是在左下角。我就始终认为他是左上角,你画出来看看,发现不对了。你改成左下角不就行了?这里个坐标系之间的转换很难吗?不就是y轴坐标变成1-y,x轴坐标不变的区别吗?当然纹理坐标叫uv坐标,不叫xy。我叫习惯了,你们知道就好。

这样,只要顶点位置和纹理坐标对应起来,则纹理采样器才会正确采样纹理的颜色。

OpenGL游戏引擎开发[4]-在OpenGL绘制纹理_第3张图片

纹理参数:纹理环绕方式

纹理参数是OpenGL用来设置如何使用纹理的。比如说,纹理坐标范围是[0,1],如果,程序员给一个顶点的纹理坐标设置为(2,2)这样的坐标,咋办?这个顶点的颜色该何去何从?

这个问题OpenGL给出了一个叫 纹理环绕方式 的参数。这个参数可以设置很多值:GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_WRAP_TO_BORDER. 不同参数的区别大家自行查阅相关资料。我们这里讲2个最简单的。

GL_CLAMP: 对于超过 [0,1]范围的纹理坐标直接丢弃,也就说该点的颜色就是 OpenGL 给的默认值,好像是黑色。

GL_REPEAT: 顾名思义,就是重复之前的纹理,那么(2,2)这个纹理坐标对应的顶点颜色就是(1,1)这个纹理坐标对应的顶点颜色。其他情况以此类推。

纹理参数:Mipmap

大家都知道,我们现实生活中看到的物体是远小近大的。远处的物体你几乎看不到物体的外观,而近处的物体你是可以看到的。同样在OpenGL中,如果使用透视投影的话,那么物体也会像人观察物体那样,近处大,远处小。但是它不像人眼那么聪明呀,人眼可以自动调节焦距,远处的人长啥样穿什么衣服,你看不清就不看了呗(睁大眼拼命看的人不在考虑之列),何必浪费能量呢。但是计算机不行呀,它不是人呀,它是机器。你得告诉它,远处的物体,你就不要给它穿那么好看的衣服了,因为我们看不清呀。

来张图感受下,远处的顶点和近处的顶点对同一张纹理进行采样,所以远处和近处显示的效果一样。但是,但是由于 近大远小 的透视效果,远处的物体看起来并不是很”精细“,反而有种”过度饱和“的感觉。这就是典型的”吃力不讨好“,不但运行渲染性能,还显示不出好效果。

OpenGL游戏引擎开发[4]-在OpenGL绘制纹理_第4张图片

那么怎么办呢?OpenGL设计了一个叫 Mipmap 的机制,就是在加载纹理的时候,一次性生成很多张大小不同的问题。对于近处的顶点,我们采样大的纹理,这样近处的顶点纹理就比较清晰,对于远处的顶点我们采样小的纹理,因为远处的顶点我们不需要看清楚,这样既节约了性能,从某种程度上还提高了视觉效果,岂不美哉。计算机科学真的凝聚了人类无限的智慧结晶!!!

再来张图感受下,这就是使用Mipmap的效果。

OpenGL游戏引擎开发[4]-在OpenGL绘制纹理_第5张图片

我们再来考虑一个问题,你说顶点显示远近,多远才算远?多近才算近?

OpenGL游戏引擎开发[4]-在OpenGL绘制纹理_第6张图片

到底是聪明人呀。 OpenGL中为mipmap划分了等级,OpenGL根据纹理的应用环境,自动为顶点决定使用哪个等级的纹理。不同等级纹理之间需要插值,不同的插值方法性能不同(当然效果好的方法就耗费更多的处理性能),我们只要手动设置这些参数,剩下的OpenGL帮我们自动搞定。

纹理采样

OpenGL通过在片段着色器声明一个纹理采样器,然后根据 顶点着色器传递过来的顶点对应的纹理坐标进行纹理采样,将采样的颜色直接作为顶点的输出颜色。其实,顶点光照的处理一般也是在这里完成的,有时候我们为了体现物体本来的颜色,还可以将物体颜色和纹理的颜色进行混合。这样,有纹理,有光照,有物体本身的颜色,通过不同的组合可以生成物体不同的外观。这就是常说的物体的 材质。 unity中已经把它高度包装得很好用了,其底层实现就是像这里这样对顶点着色。当然,我们这里只简单赋值了纹理的颜色,后面学了光照,会做出更加酷炫的效果。

OpenGL游戏引擎开发[4]-在OpenGL绘制纹理_第7张图片

加载并使用纹理

接着我们加载纹理:

OpenGL游戏引擎开发[4]-在OpenGL绘制纹理_第8张图片

在使用纹理之前,我们需要告知OpenGL我们需要使用哪个纹理,因为同一个程序中可能加载了多个纹理。

OpenGL游戏引擎开发[4]-在OpenGL绘制纹理_第9张图片

然后,你应该可以看到这样:

OpenGL游戏引擎开发[4]-在OpenGL绘制纹理_第10张图片

同理,带纹理的球体也是这么绘制的。

OpenGL游戏引擎开发[4]-在OpenGL绘制纹理_第11张图片

ok。本节结束。

你可能感兴趣的:(OpenGL游戏引擎,opengl,游戏引擎,纹理,纹理地球,glsl)