跳轉到內容

GLSL 程式設計/GLUT/紋理層

來自 Wikibooks,開放世界中的開放書籍
人類皮膚層。

本教程介紹了多紋理,即在著色器中使用多個紋理影像。

它擴充套件了紋理球教程中的著色器程式碼以處理多個紋理,並展示了一種組合它們的方法。如果您還沒有閱讀過這些教程,現在是一個很好的機會去閱讀它們。

表面層

[編輯 | 編輯原始碼]

許多真實表面(例如左側影像中所示的人類皮膚)由不同顏色、透明度、反射率等的幾層組成。如果最上面一層是不透明的並且不透射任何光線,這對於渲染表面來說並不重要。但是,在許多情況下,最上面一層是(半)透明的,因此表面的準確渲染必須考慮多層。

事實上,Phong 反射模型中包含的鏡面反射(參見鏡面高光教程)通常對應於反射光的透明層:人類皮膚上的汗水、水果上的蠟、嵌入色素顆粒的透明塑膠等等。另一方面,漫反射對應於最上面透明層下面的層。

照明這種分層表面不需要層的幾何模型:它們可以用單個、無限薄的多邊形網格表示。但是,照明計算必須為不同的層計算不同的反射,並且必須考慮光在層之間的傳輸(當光進入層時和當光離開層時)。這種方法的示例包括 Nvidia 的“Dawn”演示(參見“GPU Gems”一書的第 3 章,該書可在網上獲得)和 Nvidia 的“Human Head”演示(參見“GPU Gems 3”一書的第 14 章,該書也可在網上獲得)。

這些過程的完整描述超出了本教程的範圍。只需說,層通常與紋理影像相關聯,以指定它們的特性。在這裡,我們只展示如何使用兩種紋理和一種特定組合方法。這個例子實際上與層無關,因此說明了多紋理比表面層有更多應用。

未點亮地球的地圖。
太陽照射地球的地圖。

亮暗地球

[編輯 | 編輯原始碼]

由於人類活動,地球的未點亮一側並不完全黑暗。相反,人造燈游標記了城市的位置和範圍,如左圖所示。因此,地球的漫反射照明不應該僅僅使太陽照射表面的紋理影像變暗,而應該實際將它與未點亮紋理影像混合。請注意,太陽照射的地球比未點亮一側的人造燈光亮得多;但是,我們降低了這種對比度,以便展示夜間紋理。

著色器程式碼擴充套件了來自紋理球教程的程式碼以處理兩個紋理影像,並使用漫反射教程中描述的計算來處理單個方向光源

根據該方程,漫反射照明水平levelOfLighting為 max(0, N·L)。然後,我們根據levelOfLighting混合白天紋理和夜間紋理的顏色。這可以透過將白天顏色乘以levelOfLighting,將夜間顏色乘以1.0 - levelOfLighting,然後將它們加起來以確定片段的顏色來實現。或者,可以使用內建的 GLSL 函式mixmix(a, b, w) = b*w + a*(1.0-w)),它可能更有效。因此,片段著色器可以是(再次使用我們在longitudeLatitude中計算紋理座標的特定方法)

void main(void)
{
    vec2 longitudeLatitude = vec2((atan(texCoords.y, texCoords.x) / 3.1415926 + 1.0) * 0.5,
                                  (asin(texCoords.z) / 3.1415926 + 0.5));

    vec4 nighttimeColor = texture2D(mytexture, longitudeLatitude);
    vec4 daytimeColor = texture2D(mytexture_sunlit, longitudeLatitude);

    gl_FragColor = mix(nighttimeColor, daytimeColor, levelOfLighting);
}

請注意,這種混合與透明度教程中討論的 alpha 混合非常相似,只是我們在片段著色器內執行混合,並使用levelOfLighting而不是應該“覆蓋”另一個紋理的紋理的 alpha 分量(即不透明度)。事實上,如果daytimeTexture指定了一個 alpha 分量(參見透明紋理教程),我們可以使用這個 alpha 分量將mytexture_sunlit混合到mytexture上。這將對應於一個部分透明的層,它位於一個不透明的層之上,該不透明的層在最上面一層透明的地方可見。

完整著色器程式碼

[編輯 | 編輯原始碼]
varying float levelOfLighting;
varying vec4 texCoords;
uniform sampler2D mytexture;
uniform sampler2D mytexture_sunlit;

void main(void)
{
    vec2 longitudeLatitude = vec2((atan(texCoords.y, texCoords.x) / 3.1415926 + 1.0) * 0.5,
                                  (asin(texCoords.z) / 3.1415926 + 0.5));

    vec4 nighttimeColor = texture2D(mytexture, longitudeLatitude);
    vec4 daytimeColor = texture2D(mytexture_sunlit, longitudeLatitude);

    gl_FragColor = mix(nighttimeColor, daytimeColor, levelOfLighting);
}
attribute vec3 v_coord;
attribute vec3 v_normal;
uniform mat4 m, v, p;
uniform mat3 m_3x3_inv_transp;
uniform mat4 v_inv;

varying float levelOfLighting; // the level of diffuse
  // lighting that is computed in the vertex shader
varying vec4 texCoords;

struct lightSource
{
  vec4 position;
  vec4 diffuse;
  vec4 specular;
  float constantAttenuation, linearAttenuation, quadraticAttenuation;
  float spotCutoff, spotExponent;
  vec3 spotDirection;
};
lightSource light0 = lightSource(
  vec4(2.0,  1.0,  1.0, 0.0),
  vec4(1.0,  1.0,  1.0, 1.0),
  vec4(1.0,  1.0,  1.0, 1.0),
  0.0, 1.0, 0.0,
  180.0, 0.0,
  vec3(0.0, 0.0, 0.0)
);

void main(void)
{
  vec4 v_coord4 = vec4(v_coord, 1.0);
  mat4 mvp = p*v*m;
  vec3 normalDirection = normalize(m_3x3_inv_transp * v_normal);
  vec3 viewDirection = normalize(vec3(v_inv * vec4(0.0, 0.0, 0.0, 1.0) - m * v_coord4));
  vec3 lightDirection;

  if (light0.position.w == 0.0) // directional light
    {
      lightDirection = normalize(vec3(light0.position));
    }
  else // point or spot light (or other kind of light)
    {
      vec3 vertexToLightSource = vec3(light0.position - m * v_coord4);
      lightDirection = normalize(vertexToLightSource);
    }

  levelOfLighting = max(0.0, dot(normalDirection, lightDirection));
  texCoords = v_coord4;
  gl_Position = mvp * v_coord4;
}

恭喜!您已到達關於基本紋理的最後一個教程的結尾。我們已經瞭解了

  • 表面層如何影響材料的外觀(例如人類皮膚、打蠟水果、塑膠等)。
  • 在對代表地球的球體進行紋理化時,如何將未點亮一側的人造燈光考慮在內。
  • 如何在著色器中實現此技術。
  • 這與將 alpha 紋理混合到第二個不透明紋理上的關係。

進一步閱讀

[編輯 | 編輯原始碼]

如果您還想了解更多

  • 關於基本紋理,您應該閱讀紋理球教程
  • 關於漫反射,您應該閱讀漫反射教程
  • 關於 alpha 紋理,您應該閱讀透明紋理教程
  • 關於高階皮膚渲染,您可以閱讀 Randima Fernando(編輯)於 2004 年由 Addison-Wesley 出版、由 Curtis Beeson 和 Kevin Bjorke 撰寫的“GPU Gems”一書中由 Curtis Beeson 和 Kevin Bjorke 撰寫的第 3 章“Dawn”演示中的皮膚”和 Hubert Nguyen(編輯)於 2007 年由 Addison-Wesley 出版、由 Eugene d’Eon 和 David Luebke 撰寫的“GPU Gems 3”一書中由 Eugene d’Eon 和 David Luebke 撰寫的第 14 章“用於逼真即時皮膚渲染的高階技術”,這些書可在網上網上獲得。


< GLSL 程式設計/GLUT

除非另有說明,本頁上的所有示例原始碼均授予公有領域。
返回OpenGL 程式設計 - 照明部分 返回GLSL 程式設計 - GLUT 部分
華夏公益教科書