【GLSL教程】(八)紋理貼圖
阿新 • • 發佈:2018-11-22
簡單的紋理貼圖(Simple Texture)
為了在GLSL中應用紋理,我們需要訪問每個頂點的紋理座標。GLSL中提供了一些屬性變數,每個紋理單元一個:
下面這條語句直接複製OpenGL程式中指定的紋理座標,作為紋理單元0的頂點紋理座標。
為了訪問紋理的數值,在片斷shader中有必要宣告一個特殊的變數,對一個2D紋理可以可以這樣寫:
這個使用者定義的變數tex包含我們將會使用的紋理單元,通過texture2D函式我們可以得到一個紋素(texel),這是一個紋理圖片中的畫素。函式引數分別為simpler2D以及紋理座標:
我們的片斷shader可以寫成如下形式:
本節內容Shader Designer的工程下載地址:
http://www.lighthouse3d.com/wp-content/uploads/2011/03/textureSimple.zip
組合紋理與片斷
表中Ct和At表示紋理的顏色和alpha值,Cf和Af表示片斷(fragment)的顏色和alpha值,C和A表示最終的顏色和alpha值。
上一節的例子就相當於使用了GL_REPLACE模式。下面我們我們準備在一個立方體上實現與GL_MODULATE等同的效果。兩個shader只計算使用一個白色方向光的散射以及環境光成分,關於材質的完整定義請參照光照有關的章節。
因為使用了光照,所以頂點shader中必須處理法線資訊。必須將法線變換到檢視空間然後歸一化,光線方向向量也必須歸一化(光線方向向量已經由OpenGL變換到了檢視空間)。現在新的頂點shader如下:
Shader Designer的工程下載地址:
http://www.lighthouse3d.com/wp-content/uploads/2011/03/textureComb.zip
多重紋理
在GLSL中實現多重紋理十分容易,我們只需要訪問所有紋理即可。因為我們打算給每個紋理使用相同的紋理座標,所以頂點shader不需要改動。片斷shader中只需要進行些許改動,加上多個紋理的顏色值。
下面新增點不同的效果:在黑暗中發光。我們希望第二個紋理能在黑暗中發光,在沒有光照時達到最亮,在有光照時變暗。
我們通過兩步計算最終的顏色:首先將第一個紋理與片斷顏色進行modulate計算,然後根據光照強度(indensity)加上第二個紋理單元。
如果indensity是0,第二個紋理單元取最大值,如果indensity為1,只取第二個紋理單元顏色的10%,當indensity在0和1之間時按這兩個大小進行插值。可以使用smoothstep函式實現這個要求:
coef = smoothStep(1.0, 0.2, intensity);
下面的片斷shader實現了需要的效果:
http://www.lighthouse3d.com/wp-content/uploads/2011/03/textureGlow.zip
為了在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;
uniform mat4 gl_TextureMatrix[gl_MaxTextureCoords];
頂點shader可以通過上面所示的內容訪問OpenGL程式中指定的紋理座標。然後必須為每個頂點計算紋理座標,並儲存在預先定義的易變變數gl_TexCoord[i]中,i表示紋理單元號。
下面這條語句直接複製OpenGL程式中指定的紋理座標,作為紋理單元0的頂點紋理座標。
gl_TexCoord[0] = gl_MultiTexCoord0;
下面是個簡單的例子,在頂點shader中設定紋理單元0的紋理座標。
-
void
- {
- gl_TexCoord[ 0] = gl_MultiTexCoord0;
- gl_Position = ftransform();
- }
- void main()
- {
- gl_TexCoord[ 0] = gl_TextureMatrix[ 0] * gl_MultiTexCoord0;
- gl_Position = ftransform();
- }
為了訪問紋理的數值,在片斷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;
- }
本節內容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 |
上一節的例子就相當於使用了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();
- }
- 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);
- }
http://www.lighthouse3d.com/wp-content/uploads/2011/03/textureGlow.zip