跳轉到內容

GLSL 程式設計/GLUT/光照紋理表面

來自 Wikibooks,開放世界中的開放書籍
從阿波羅8號看到的地球升起。

本教程涵蓋了紋理表面的逐頂點光照

它結合了紋理球體教程鏡面高光教程的著色器程式碼,以計算光照,其中漫射材質顏色由紋理確定。如果你還沒有閱讀過紋理球體教程鏡面高光教程,現在是閱讀它們的好時機。

紋理和漫射逐頂點光照

[編輯 | 編輯原始碼]

紋理球體教程中,紋理顏色用作片段著色器的輸出。但是,也可以使用紋理顏色作為光照計算中的任何引數,特別是用於漫射反射的材質常數,它在漫射反射教程中介紹。它出現在Phong 反射模型的漫射部分

其中此方程使用不同的材質常數分別對應於紅色、綠色和藍色的三個顏色分量。透過使用紋理來確定這些材質常數,它們可以在表面上變化。

著色器程式碼

[編輯 | 編輯原始碼]

鏡面高光教程中的逐頂點光照相比,這裡的頂點著色器計算了兩個不同的顏色:diffuseColor在片段著色器中與紋理顏色相乘,而specularColor只是鏡面項,它不應該與紋理顏色相乘。這是有道理的,但由於歷史原因(即能力較差的舊圖形硬體),這有時被稱為“獨立鏡面顏色”。

attribute vec3 v_coord;
attribute vec3 v_normal;
uniform mat4 m, v, p;
uniform mat3 m_3x3_inv_transp;
uniform mat4 v_inv;

varying vec3 diffuseColor;
  // the diffuse Phong lighting computed in the vertex shader
varying vec3 specularColor;
  // the specular Phong lighting computed in the vertex shader
varying vec4 texCoords; // the texture coordinates

struct lightSource
{
  vec4 position;
  vec4 diffuse;
  vec4 specular;
  float constantAttenuation, linearAttenuation, quadraticAttenuation;
  float spotCutoff, spotExponent;
  vec3 spotDirection;
};
lightSource light0 = lightSource(
  vec4(0.0,  1.0,  2.0, 1.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)
);
vec4 scene_ambient = vec4(0.2, 0.2, 0.2, 1.0);

struct material
{
  vec4 ambient;
  vec4 diffuse;
  vec4 specular;
  float shininess;
};
material mymaterial = material(
  vec4(0.2, 0.2, 0.2, 1.0),
  vec4(1.0, 0.8, 0.8, 1.0),
  vec4(1.0, 1.0, 1.0, 1.0),
  5.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;
  float attenuation;

  if (light0.position.w == 0.0) // directional light
    {
      attenuation = 1.0; // no attenuation
      lightDirection = normalize(vec3(light0.position));
    }
  else // point or spot light (or other kind of light)
    {
      vec3 vertexToLightSource = vec3(light0.position - m * v_coord4);
      float distance = length(vertexToLightSource);
      lightDirection = normalize(vertexToLightSource);
      attenuation = 1.0 / (light0.constantAttenuation
                           + light0.linearAttenuation * distance
                           + light0.quadraticAttenuation * distance * distance);

      if (light0.spotCutoff <= 90.0) // spotlight
        {
          float clampedCosine = max(0.0, dot(-lightDirection, normalize(light0.spotDirection)));
          if (clampedCosine < cos(radians(light0.spotCutoff))) // outside of spotlight cone
            {
              attenuation = 0.0;
            }
          else
            {
              attenuation = attenuation * pow(clampedCosine, light0.spotExponent);
            }
        }
    }

  vec3 ambientLighting = vec3(scene_ambient);
    // without material color!

  vec3 diffuseReflection = attenuation
    * vec3(light0.diffuse)
    * max(0.0, dot(normalDirection, lightDirection));
    // without material color!

  vec3 specularReflection;
  if (dot(normalDirection, lightDirection) < 0.0) // light source on the wrong side?
    {
      specularReflection = vec3(0.0, 0.0, 0.0); // no specular reflection
    }
  else // light source on the right side
    {
      specularReflection = attenuation * vec3(light0.specular) * vec3(mymaterial.specular)
        * pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)),
              mymaterial.shininess);
    }

  diffuseColor = ambientLighting + diffuseReflection;
  specularColor = specularReflection;
  texCoords = v_coord4;
  gl_Position = mvp * v_coord4;
}

片段著色器用紋理顏色調製diffuseColor,並新增specularColor

varying vec3 diffuseColor;
    // the interpolated diffuse Phong lighting
varying vec3 specularColor;
    // the interpolated specular Phong lighting
varying vec4 texCoords;
    // the interpolated texture coordinates
uniform sampler2D mytexture;

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

    gl_FragColor = vec4(diffuseColor
        * vec3(texture2D(mytexture, longitudeLatitude))
        + specularColor, 1.0);
}

為了將紋理影像分配給此著色器,你應該按照紋理球體教程中討論的步驟進行操作。

恭喜你,你已經完成了本教程。我們已經瞭解了

  • 紋理和逐頂點光照通常如何結合。
  • 什麼是“獨立鏡面顏色”。

進一步閱讀

[編輯 | 編輯原始碼]

如果你想了解更多

  • 關於Phong 反射模型的漫射反射項,你應該閱讀漫射反射教程
  • 關於逐頂點光照或Phong 反射模型的其餘部分,即環境項和鏡面項,你應該閱讀鏡面高光教程
  • 關於紋理的基礎知識,你應該閱讀紋理球體教程


< GLSL 程式設計/GLUT

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