GLSL 程式設計/Blender/照明紋理表面
外觀

本教程涵蓋紋理表面的逐頂點照明。
它結合了紋理球體教程和鏡面高光教程的著色器程式碼,以計算使用紋理確定的漫反射材質顏色進行照明。如果你還沒有閱讀紋理球體教程或鏡面高光教程,這將是一個很好的機會來閱讀它們。
在紋理球體教程中,紋理顏色被用作片段著色器的輸出。然而,也可以將紋理顏色用作照明計算中的任何引數,特別是材質常數用於漫反射,這在漫反射教程中介紹過。它出現在Phong 反射模型的漫反射部分
其中該方程使用不同的材質常數來表示三種顏色分量,即紅色、綠色和藍色。透過使用紋理來確定這些材質常數,它們可以在表面上變化。
與鏡面高光教程中的逐頂點照明相比,這裡的頂點著色器計算了兩個不同的顏色:diffuseColor 在片段著色器中乘以紋理顏色,specularColor 只是鏡面項,不應該乘以紋理顏色。這是完全合理的,但由於歷史原因(即能力較弱的舊圖形硬體),這有時被稱為“分離的鏡面顏色”。
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
void main()
{
vec3 normalDirection =
normalize(gl_NormalMatrix * gl_Normal);
vec3 viewDirection =
-normalize(vec3(gl_ModelViewMatrix * gl_Vertex));
vec3 lightDirection;
float attenuation;
if (0.0 == gl_LightSource[0].position.w)
// directional light?
{
attenuation = 1.0; // no attenuation
lightDirection =
normalize(vec3(gl_LightSource[0].position));
}
else // point light or spotlight (or other kind of light)
{
vec3 vertexToLightSource =
vec3(gl_LightSource[0].position
- gl_ModelViewMatrix * gl_Vertex);
float distance = length(vertexToLightSource);
attenuation = 1.0 / distance; // linear attenuation
lightDirection = normalize(vertexToLightSource);
if (gl_LightSource[0].spotCutoff <= 90.0) // spotlight?
{
float clampedCosine = max(0.0, dot(-lightDirection,
gl_LightSource[0].spotDirection));
if (clampedCosine < gl_LightSource[0].spotCosCutoff)
// outside of spotlight cone?
{
attenuation = 0.0;
}
else
{
attenuation = attenuation * pow(clampedCosine,
gl_LightSource[0].spotExponent);
}
}
}
vec3 ambientLighting = vec3(gl_LightModel.ambient);
// without material color!
vec3 diffuseReflection = attenuation
* vec3(gl_LightSource[0].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(gl_LightSource[0].specular)
* vec3(gl_FrontMaterial.specular)
* pow(max(0.0, dot(reflect(-lightDirection,
normalDirection), viewDirection)),
gl_FrontMaterial.shininess);
}
diffuseColor = ambientLighting + diffuseReflection;
specularColor = specularReflection;
texCoords = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
片段著色器使用紋理顏色對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 textureUnit;
void main()
{
vec2 longitudeLatitude = vec2(
(atan(texCoords.y, texCoords.x) / 3.1415926 + 1.0) * 0.5,
1.0 - acos(texCoords.z) / 3.1415926);
// unusual processing of texture coordinates
gl_FragColor = vec4(diffuseColor
* vec3(texture2D(textureUnit, longitudeLatitude))
+ specularColor, 1.0);
}
為了將紋理影像分配給此著色器,你應該按照紋理球體教程中討論的步驟操作;特別是,Python 指令碼必須設定統一的textureUnit的值,例如使用
shader.setSampler('textureUnit', 0)
恭喜,你已經到達了結尾。我們已經瞭解了
- 紋理和逐頂點照明通常是如何結合的。
- 什麼是“分離的鏡面顏色”。
如果你還想了解更多
除非另有說明,否則本頁上的所有示例原始碼都歸屬於公共領域。