【GLSL教程】(八)纹理贴图

转载 2016年08月29日 11:34:56

本文转载自http://blog.csdn.net/racehorse/article/details/6664717


简单的纹理贴图(Simple Texture)
为了在GLSL中应用纹理,我们需要访问每个顶点的纹理坐标。GLSL中提供了一些属性变量,每个纹理单元一个:

[cpp] view plain copy
  1. attribute vec4 gl_MultiTexCoord0;  
  2. attribute vec4 gl_MultiTexCoord1;  
  3. attribute vec4 gl_MultiTexCoord2;  
  4. attribute vec4 gl_MultiTexCoord3;  
  5. attribute vec4 gl_MultiTexCoord4;  
  6. attribute vec4 gl_MultiTexCoord5;  
  7. attribute vec4 gl_MultiTexCoord6;  
  8. attribute vec4 gl_MultiTexCoord7;  
GLSL还为访问每个纹理的纹理矩阵提供了一个一致变量数组:
[cpp] view plain copy
  1. uniform mat4 gl_TextureMatrix[gl_MaxTextureCoords];  
顶点shader可以通过上面所示的内容访问OpenGL程序中指定的纹理坐标。然后必须为每个顶点计算纹理坐标,并保存在预先定义的易变变量gl_TexCoord[i]中,i表示纹理单元号。
下面这条语句直接复制OpenGL程序中指定的纹理坐标,作为纹理单元0的顶点纹理坐标。
[cpp] view plain copy
  1. gl_TexCoord[0]  = gl_MultiTexCoord0;  
下面是个简单的例子,在顶点shader中设置纹理单元0的纹理坐标。
[cpp] view plain copy
  1. void main()  
  2. {  
  3.     gl_TexCoord[0] = gl_MultiTexCoord0;  
  4.     gl_Position = ftransform();  
  5. }  
如果你想使用纹理矩阵,可以这样操作:
[cpp] view plain copy
  1. void main()  
  2. {  
  3.     gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;  
  4.     gl_Position = ftransform();  
  5. }  
前面说过,gl_TexCoord是一个易变变量,所以在片断shder中可以访问经过插值的纹理坐标。
为了访问纹理的数值,在片断shader中有必要声明一个特殊的变量,对一个2D纹理可以可以这样写:
[cpp] view plain copy
  1. uniform sampler2D tex;  
如果是1D或者3D的纹理,可以改成sampler1D和sampler3D。
这个用户定义的变量tex包含我们将会使用的纹理单元,通过texture2D函数我们可以得到一个纹素(texel),这是一个纹理图片中的像素。函数参数分别为simpler2D以及纹理坐标:
[cpp] view plain copy
  1. vec4 texture2D(sampler2D, vec2);  
函数的返回值已经考虑了所有在OpenGL程序中定义的纹理设置,比如过滤、mipmap、clamp等。
我们的片断shader可以写成如下形式:
[cpp] view plain copy
  1. uniform sampler2D tex;  
  2.   
  3. void main()  
  4. {  
  5.     vec4 color = texture2D(tex,gl_TexCoord[0].st);  
  6.     gl_FragColor = color;  
  7. }  
注意访问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如下:

[cpp] view plain copy
  1. varying vec3 lightDir,normal;  
  2.   
  3. void main()  
  4. {  
  5.     normal = normalize(gl_NormalMatrix * gl_Normal);  
  6.   
  7.     lightDir = normalize(vec3(gl_LightSource[0].position));  
  8.     gl_TexCoord[0] = gl_MultiTexCoord0;  
  9.   
  10.     gl_Position = ftransform();  
  11. }  
在片断shader中,光照得到的片断的颜色和alpha值在cf和af中分别计算。shader中剩余代码按照GL_MODULATE的公式计算:
[cpp] view plain copy
  1. varying vec3 lightDir,normal;  
  2. uniform sampler2D tex;  
  3.   
  4. void main()  
  5. {  
  6.     vec3 ct,cf;  
  7.     vec4 texel;  
  8.     float intensity,at,af;  
  9.   
  10.     intensity = max(dot(lightDir,normalize(normal)),0.0);  
  11.     cf = intensity * (gl_FrontMaterial.diffuse).rgb +  
  12.                   gl_FrontMaterial.ambient.rgb;  
  13.     af = gl_FrontMaterial.diffuse.a;  
  14.   
  15.     texel = texture2D(tex,gl_TexCoord[0].st);  
  16.     ct = texel.rgb;  
  17.     at = texel.a;  
  18.   
  19.     gl_FragColor = vec4(ct * cf, at * af);  
  20. }  

Shader Designer的工程下载地址:
http://www.lighthouse3d.com/wp-content/uploads/2011/03/textureComb.zip

多重纹理
在GLSL中实现多重纹理十分容易,我们只需要访问所有纹理即可。因为我们打算给每个纹理使用相同的纹理坐标,所以顶点shader不需要改动。片断shader中只需要进行些许改动,加上多个纹理的颜色值。
[cpp] view plain copy
  1. varying vec3 lightDir,normal;  
  2. uniform sampler2D tex;  
  3.   
  4. void main()  
  5. {  
  6.     vec3 ct,cf;  
  7.     vec4 texel;  
  8.     float intensity,at,af;  
  9.   
  10.     intensity = max(dot(lightDir,normalize(normal)),0.0);  
  11.     cf = intensity * (gl_FrontMaterial.diffuse).rgb +  
  12.                   gl_FrontMaterial.ambient.rgb;  
  13.     af = gl_FrontMaterial.diffuse.a;  
  14.   
  15.     texel = texture2D(tex,gl_TexCoord[0].st) +  
  16.           texture2D(l3d,gl_TexCoord[0].st);  
  17.     ct = texel.rgb;  
  18.     at = texel.a;  
  19.   
  20.     gl_FragColor = vec4(ct * cf, at * af);  
  21. }  
效果如下:

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

我们通过两步计算最终的颜色:首先将第一个纹理与片断颜色进行modulate计算,然后根据光照强度(indensity)加上第二个纹理单元。
如果indensity是0,第二个纹理单元取最大值,如果indensity为1,只取第二个纹理单元颜色的10%,当indensity在0和1之间时按这两个大小进行插值。可以使用smoothstep函数实现这个要求:
[cpp] view plain copy
  1. 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实现了需要的效果:
[cpp] view plain copy
  1. varying vec3 lightDir,normal;  
  2. uniform sampler2D tex,l3d;  
  3.   
  4. void main()  
  5. {  
  6.     vec3 ct,cf,c;  
  7.     vec4 texel;  
  8.     float intensity,at,af,a;  
  9.   
  10.     intensity = max(dot(lightDir,normalize(normal)),0.0);  
  11.   
  12.     cf = intensity * (gl_FrontMaterial.diffuse).rgb +  
  13.                       gl_FrontMaterial.ambient.rgb;  
  14.     af = gl_FrontMaterial.diffuse.a;  
  15.   
  16.     texel = texture2D(tex,gl_TexCoord[0].st);  
  17.   
  18.     ct = texel.rgb;  
  19.     at = texel.a;  
  20.   
  21.     c = cf * ct;  
  22.     a = af * at;  
  23.   
  24.     float coef = smoothstep(1.0,0.2,intensity);  
  25.     c += coef *  vec3(texture2D(l3d,gl_TexCoord[0].st));  
  26.   
  27.     gl_FragColor = vec4(c, a);  
  28. }  
Shader Designer的工程下载地址:
http://www.lighthouse3d.com/wp-content/uploads/2011/03/textureGlow.zip

【GLSL教程】(八)纹理贴图

简单的纹理贴图(Simple Texture) 为了在GLSL中应用纹理,我们需要访问每个顶点的纹理坐标。GLSL中提供了一些属性变量,每个纹理单元一个: [cpp] view p...
  • vampirem
  • vampirem
  • 2013年09月17日 19:02
  • 613

(转)【GLSL教程】(八)纹理贴图

简单的纹理贴图(
  • woashizhangsi
  • woashizhangsi
  • 2014年12月12日 09:39
  • 324

Unity中写GLSL(二)—— Unlit着色器,无光照,只从纹理采样

GLSL语法用的330之后的语法。先上图: 棋盘格纹理是我百度随便找的。 下面是代码:Shader "Unlit/UnlitShader_GL" { Properties { ...
  • qq_22472397
  • qq_22472397
  • 2018年01月12日 21:34
  • 20

GLSL入门2 关于GLSL中的纹理贴图

我将注解以及源码直接放到这里了 // GLSL01.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include #include #include...
  • davidsu33
  • davidsu33
  • 2013年12月15日 20:05
  • 1872

GLSL 纹理贴图

简单的纹理贴图(Simple Texture) 为了在GLSL中应用纹理,我们需要访问每个顶点的纹理坐标。GLSL中提供了一些属性变量,每个纹理单元一个: attribute vec4...
  • Anzhongliu
  • Anzhongliu
  • 2015年05月09日 00:20
  • 702

Unity3D环境下的GLSL shaders写法 — 纹理参数

在这篇文章中我们要写一个shader来显示材质
  • cosmos53076
  • cosmos53076
  • 2014年05月12日 18:01
  • 859

GLSL基础教程(一)

        高级着色语言(HLSL――High Level Shading Language)是用来在顶点和像素着色器(shader)中编程的语言。其实,说白了他们就是我们写的短小的自定义程序,他...
  • skyman_2001
  • skyman_2001
  • 2006年09月25日 19:29
  • 3788

GLSL经典入门教程汇总

权威官方文档:https://www.opengl.org/documentation/glsl/ 权威民间金典入门教程:http://blog.csdn.net/racehorse 一个详细...
  • u013467442
  • u013467442
  • 2015年03月19日 14:59
  • 5526

OpenGL GLSL访问纹理

这一节我们给上一节的ADSPhone的程序贴上一张纹理贴图 如下图: GLSL访问纹理很简单,只需要把要使用的纹理坐标和纹理的对象传入着色器即可 对于本程序,我们把纹理坐标和纹理对象传入顶...
  • jk823394954
  • jk823394954
  • 2015年09月03日 10:19
  • 1629

GLSL学习资料整理

之前只是使用过别人写好的shader,自己只知道它的作用,但并没有完全理解其中每一行代码的含义。工作之后,还是对图形这一块比较感兴趣,再加上这两年VR比较火,facebook CEO都说了看好VR在未...
  • ziren235
  • ziren235
  • 2016年05月17日 23:05
  • 470
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【GLSL教程】(八)纹理贴图
举报原因:
原因补充:

(最多只允许输入30个字)