【GLSL教程】(八)纹理贴图 【转】
http://blog.csdn.net/racehorse/article/details/6664717
简单的纹理贴图(Simple Texture)
为了在GLSL中应用纹理,我们需要访问每个顶点的纹理坐标。GLSL中提供了一些属性变量,每个纹理单元一个:
- attribute vec4 gl_MultiTexCoord0;
- attribute vec4 gl_MultiTexCoord1;
- attribute vec4 gl_MultiTexCoord2;
- attribute vec4 gl_MultiTexCoord3;
- attribute vec4 gl_MultiTexCoord4;
- attribute vec4 gl_MultiTexCoord5;
- attribute vec4 gl_MultiTexCoord6;
- attribute vec4 gl_MultiTexCoord7;
GLSL还为访问每个纹理的纹理矩阵提供了一个一致变量数组:
- uniform mat4 gl_TextureMatrix[gl_MaxTextureCoords];
顶点shader可以通过上面所示的内容访问OpenGL程序中指定的纹理坐标。然后必须为每个顶点计算纹理坐标,并保存在预先定义的易变变量gl_TexCoord[i]中,i表示纹理单元号。
下面这条语句直接复制OpenGL程序中指定的纹理坐标,作为纹理单元0的顶点纹理坐标。
- gl_TexCoord[0] = gl_MultiTexCoord0;
下面是个简单的例子,在顶点shader中设置纹理单元0的纹理坐标。
- void main()
- {
- gl_TexCoord[0] = gl_MultiTexCoord0;
- gl_Position = ftransform();
- }
如果你想使用纹理矩阵,可以这样操作:
- void main()
- {
- gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
- gl_Position = ftransform();
- }
前面说过,gl_TexCoord是一个易变变量,所以在片断shder中可以访问经过插值的纹理坐标。
为了访问纹理的数值,在片断shader中有必要声明一个特殊的变量,对一个2D纹理可以可以这样写:
- uniform sampler2D tex;
如果是1D或者3D的纹理,可以改成sampler1D和sampler3D。
这个用户定义的变量tex包含我们将会使用的纹理单元,通过texture2D函数我们可以得到一个纹素(texel),这是一个纹理图片中的像素。函数参数分别为simpler2D以及纹理坐标:
- vec4 texture2D(sampler2D, vec2);
函数的返回值已经考虑了所有在OpenGL程序中定义的纹理设置,比如过滤、mipmap、clamp等。
我们的片断shader可以写成如下形式:
- uniform sampler2D tex;
- void main()
- {
- vec4 color = texture2D(tex,gl_TexCoord[0].st);
- gl_FragColor = color;
- }
注意访问gl_TexCoord时选择子st的使用。在本教程前面关于数据类型和变量的讨论中说过,访问纹理坐标时可以使用如下选择子:s、t、p、q。(r因为和rgb选择子冲突而没有使用)

本节内容Shader Designer的工程下载地址:
http://www.lighthouse3d.com/wp-content/uploads/2011/03/textureSimple.zip
组合纹理与片断
OpenGL允许我们通过多种方式将纹理颜色和片断颜色联合到一起。下表显示了RGBA模式时可用的联合方式:
GL_REPLACE | C = Ct | A = At |
GL_MODULATE | C = Ct*Cf | A = At*Af |
GL_DECAL | C = Cf * (1 – At) + Ct * At | A = Af |
表中Ct和At表示纹理的颜色和alpha值,Cf和Af表示片断(fragment)的颜色和alpha值,C和A表示最终的颜色和alpha值。
上一节的例子就相当于使用了GL_REPLACE模式。下面我们我们准备在一个立方体上实现与GL_MODULATE等同的效果。两个shader只计算使用一个白色方向光的散射以及环境光成分,关于材质的完整定义请参照光照有关的章节。
因为使用了光照,所以顶点shader中必须处理法线信息。必须将法线变换到视图空间然后归一化,光线方向向量也必须归一化(光线方向向量已经由OpenGL变换到了视图空间)。现在新的顶点shader如下:
- varying vec3 lightDir,normal;
- void main()
- {
- normal = normalize(gl_NormalMatrix * gl_Normal);
- lightDir = normalize(vec3(gl_LightSource[0].position));
- gl_TexCoord[0] = gl_MultiTexCoord0;
- gl_Position = ftransform();
- }
在片断shader中,光照得到的片断的颜色和alpha值在cf和af中分别计算。shader中剩余代码按照GL_MODULATE的公式计算:
- varying vec3 lightDir,normal;
- uniform sampler2D tex;
- void main()
- {
- vec3 ct,cf;
- vec4 texel;
- float intensity,at,af;
- intensity = max(dot(lightDir,normalize(normal)),0.0);
- cf = intensity * (gl_FrontMaterial.diffuse).rgb +
- gl_FrontMaterial.ambient.rgb;
- af = gl_FrontMaterial.diffuse.a;
- texel = texture2D(tex,gl_TexCoord[0].st);
- ct = texel.rgb;
- at = texel.a;
- gl_FragColor = vec4(ct * cf, at * af);
- }

Shader Designer的工程下载地址:
http://www.lighthouse3d.com/wp-content/uploads/2011/03/textureComb.zip
多重纹理
在GLSL中实现多重纹理十分容易,我们只需要访问所有纹理即可。因为我们打算给每个纹理使用相同的纹理坐标,所以顶点shader不需要改动。片断shader中只需要进行些许改动,加上多个纹理的颜色值。
- varying vec3 lightDir,normal;
- uniform sampler2D tex;
- void main()
- {
- vec3 ct,cf;
- vec4 texel;
- float intensity,at,af;
- intensity = max(dot(lightDir,normalize(normal)),0.0);
- cf = intensity * (gl_FrontMaterial.diffuse).rgb +
- gl_FrontMaterial.ambient.rgb;
- af = gl_FrontMaterial.diffuse.a;
- texel = texture2D(tex,gl_TexCoord[0].st) +
- texture2D(l3d,gl_TexCoord[0].st);
- ct = texel.rgb;
- at = texel.a;
- gl_FragColor = vec4(ct * cf, at * af);
- }
效果如下:

下面添加点不同的效果:在黑暗中发光。我们希望第二个纹理能在黑暗中发光,在没有光照时达到最亮,在有光照时变暗。

我们通过两步计算最终的颜色:首先将第一个纹理与片断颜色进行modulate计算,然后根据光照强度(indensity)加上第二个纹理单元。
如果indensity是0,第二个纹理单元取最大值,如果indensity为1,只取第二个纹理单元颜色的10%,当indensity在0和1之间时按这两个大小进行插值。可以使用smoothstep函数实现这个要求:
- genType smoothStep(genType edge0, genType edge1, genType x);
如果x <= edge0结果是0,如果x >= edge1结果为1,如果edge0 < x < edge1结果在0和1之间进行Hermite插值。在本例中我们按如下方式调用:
coef = smoothStep(1.0, 0.2, intensity);
下面的片断shader实现了需要的效果:
- varying vec3 lightDir,normal;
- uniform sampler2D tex,l3d;
- void main()
- {
- vec3 ct,cf,c;
- vec4 texel;
- float intensity,at,af,a;
- intensity = max(dot(lightDir,normalize(normal)),0.0);
- cf = intensity * (gl_FrontMaterial.diffuse).rgb +
- gl_FrontMaterial.ambient.rgb;
- af = gl_FrontMaterial.diffuse.a;
- texel = texture2D(tex,gl_TexCoord[0].st);
- ct = texel.rgb;
- at = texel.a;
- c = cf * ct;
- a = af * at;
- float coef = smoothstep(1.0,0.2,intensity);
- c += coef * vec3(texture2D(l3d,gl_TexCoord[0].st));
- gl_FragColor = vec4(c, a);
- }
Shader Designer的工程下载地址:
http://www.lighthouse3d.com/wp-content/uploads/2011/03/textureGlow.zip
【GLSL教程】(八)纹理贴图 【转】的更多相关文章
- GLSL纹理贴图 【转】
转载:http://blog.csdn.net/hgl868/article/details/7872466 简单的纹理贴图(Simple Texture) 为了在GLSL中应用纹理,我们需要访问每个 ...
- (转载)Cocos2dx-OpenGL ES2.0教程:纹理贴图(6)
在上一篇文章中,我们介绍了如何绘制一个立方体,里面涉及的知识点有VBO(Vertex Buffer Object).IBO(Index Buffer Object)和MVP(Modile-View-P ...
- IOS 中openGL使用教程3(openGL ES 入门篇 | 纹理贴图(texture)使用)
在这篇文章中,我们将学习如何在openGL中使用纹理贴图. penGL中纹理可以分为1D,2D和3D纹理,我们在绑定纹理对象的时候需要指定纹理的种类.由于本文将以一张图片为例,因此我们为我们的纹理对象 ...
- Three.js基础探寻八——法向材质与材质的纹理贴图
4.法向材质 法向材质可以将材质的颜色设置为其法向量的方向,有时候对于调试很有帮助. 法向材质的设定很简单,甚至不用设置任何参数: new THREE.MeshNormalMaterial() 材质的 ...
- 翻译:GLSL的顶点位移贴图
翻译:GLSL的顶点位移贴图 翻译自: Vertex Displacement Mapping using GLSL 译者: FreeBlues 说明: 之所以选择这篇文档, 是因为现在但凡提到位移贴 ...
- 【GLSL教程】(一)图形流水线 【转】
http://blog.csdn.net/racehorse/article/details/6593719 这是一些列来自lighthouse3d的GLSL教程,非常适合入门.我将边学习边翻译该教程 ...
- Esfog_UnityShader教程_NormalMap法线贴图
咳咳,好久没有更新了,一来是这段时间很忙很忙,再来就是自己有些懒了,这个要不得啊,赶紧补上.在前面我们已经介绍过了漫反射和镜面反射,这两个是基本的光照类型,仅仅依靠它们就想制作出精美的效果是远远不够的 ...
- Android OpenGL ES 开发(九): OpenGL ES 纹理贴图
一.概念 一般说来,纹理是表示物体表面的一幅或几幅二维图形,也称纹理贴图(texture).当把纹理按照特定的方式映射到物体表面上的时候,能使物体看上去更加真实.当前流行的图形系统中,纹理绘制已经成为 ...
- OpenGL ES课程VI之纹理贴图(原文对照)
http://www.educity.cn/wenda/92368.html OpenGL ES教程VI之纹理贴图(原文对照) OpenGL ES Tutorial for Android – Par ...
随机推荐
- manjaro安装anaconda出错
出错信息: ==> Creating package "anaconda"... -> Generating .PKGINFO file... -> Gene ...
- c++面试须知
这些都是从zhihu上看到的. 指针,多态(虚函数表.内存layout),作用域,内存的管理 算法与数据结构,数据结构上由掌握哈希.优先级队列,算法上有字符串处理,简单的DFS.BFS.动态规划 系统 ...
- nyoj 题目6 喷水装置
喷水装置(一) 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 现有一块草坪,长为20米,宽为2米,要在横中心线上放置半径为Ri的喷水装置,每个喷水装置的效果都会让以 ...
- 【bzoj2245】[SDOI2011]工作安排 费用流
题目描述 你的公司接到了一批订单.订单要求你的公司提供n类产品,产品被编号为1~n,其中第i类产品共需要Ci件.公司共有m名员工,员工被编号为1~m员工能够制造的产品种类有所区别.一件产品必须完整地由 ...
- [HNOI2012]矿场搭建(tarjan求点双)
题目 Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无 ...
- DataSet导出Excel,比以往的方法导出的Excel外观更加好看
原文发布时间为:2010-06-21 -- 来源于本人的百度文章 [由搬家工具导入] ======目前方法=========== #region 生成Excel/// <summary>/ ...
- .net3.5下使用LINQ递归算法实现简洁代码
原文发布时间为:2011-04-24 -- 来源于本人的百度文章 [由搬家工具导入] http://www.cnblogs.com/wintersun/archive/2009/03/29/14243 ...
- Dependency Injection in ASP.NET Web API 2
What is Dependency Injection? A dependency is any object that another object requires. For example, ...
- 基址重定位表&.reloc节区
第16-17章 - 基址重定位表&.reloc节区 @date: 2016/11/31 @author: dlive 0x01 PE重定位 若加载的是DLL.SYS文件,且在ImageBase ...
- 常用 vim 命令总结
学习 vim ,是需要经常使用的,而这些命令,是我这段时间最常用的命令,很有效率的提高的我的文本编辑效率.----------------------------------------------- ...