跳轉到內容

GLSL 程式設計/GLUT/雙面平滑曲面

來自華夏公益教科書,開放的書籍,為了一個開放的世界
使用曲面兩側的不同顏色渲染凱萊結點三次曲面。

本教程涵蓋雙面逐畫素光照(即雙面 Phong 著色)。

在這裡,我們將平滑鏡面高光教程中討論的逐畫素光照與雙面曲面教程中討論的雙面光照結合起來。

著色器編碼器

[編輯 | 編輯原始碼]

平滑鏡面高光教程程式碼的必要更改是:背面材料的新屬性,片段著色器中材料引數的新區域性變數,這些變數根據gl_FrontFacing設定為正面材料引數或背面材料引數。此外,如果渲染背面,則表面法線向量將被取反。此外,背面剔除必須像透明度教程中描述的那樣被停用。實際上這非常簡單。

頂點著色器可能看起來像這樣

attribute vec4 v_coord;
attribute vec3 v_normal;
varying vec4 position;  // position of the vertex (and fragment) in world space
varying vec3 varyingNormalDirection;  // surface normal vector in world space
uniform mat4 m, v, p;
uniform mat3 m_3x3_inv_transp;

void main()
{
  position = m * v_coord;
  varyingNormalDirection = normalize(m_3x3_inv_transp * v_normal);

  mat4 mvp = p*v*m;
  gl_Position = mvp * v_coord;
}

而片段著色器可能是

varying vec4 position;  // position of the vertex (and fragment) in world space
varying vec3 varyingNormalDirection;  // surface normal vector in world space
uniform mat4 m, v, p;
uniform mat4 v_inv;

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 frontMaterial = material(
  vec4(0.2, 0.2, 0.2, 1.0),
  vec4(1.0, 0.0, 0.0, 1.0),
  vec4(1.0, 1.0, 1.0, 1.0),
  100.0
);
material backMaterial = material(
  vec4(0.2, 0.2, 0.2, 1.0),
  vec4(0.0, 0.0, 1.0, 1.0),
  vec4(1.0, 1.0, 1.0, 1.0),
  100.0
);

void main()
{
  vec3 normalDirection = normalize(varyingNormalDirection);
  vec4 ambientColor;
  vec4 diffuseColor;
  vec4 specularColor;
  float shininess;
  
  if (gl_FrontFacing)
    {
      ambientColor = frontMaterial.ambient;
      diffuseColor = frontMaterial.diffuse;
      specularColor = frontMaterial.specular;
      shininess = frontMaterial.shininess;
    }
  else
    {
      ambientColor = backMaterial.ambient;
      diffuseColor = backMaterial.diffuse;
      specularColor = backMaterial.specular;
      shininess = backMaterial.shininess;
      normalDirection = -normalDirection;
    }
  
  vec3 viewDirection = normalize(vec3(v_inv * vec4(0.0, 0.0, 0.0, 1.0) - position));
  vec3 lightDirection;
  float attenuation;
  
  if (0.0 == light0.position.w) // directional light?
    {
      attenuation = 1.0; // no attenuation
      lightDirection = normalize(vec3(light0.position));
    } 
  else // point light or spotlight (or other kind of light) 
    {
      vec3 positionToLightSource = vec3(light0.position - position);
      float distance = length(positionToLightSource);
      lightDirection = normalize(positionToLightSource);
      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, 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) * vec3(ambientColor);
  
  vec3 diffuseReflection = attenuation 
    * vec3(light0.diffuse) * vec3(diffuseColor)
    * max(0.0, dot(normalDirection, lightDirection));
 
  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(specularColor) 
	* pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)), shininess);
    }
  
  gl_FragColor = vec4(ambientLighting + diffuseReflection + specularReflection, 1.0);
}

恭喜您完成了本簡短教程。我們已經看到了

  • 如何使用逐畫素光照渲染雙面曲面。

進一步閱讀

[編輯 | 編輯原始碼]

如果您還想了解更多


< GLSL 程式設計/GLUT

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