GLSL 编程/GLUT/光照纹理表面
外观
本教程涵盖了纹理表面的逐顶点光照。
它结合了纹理球体教程和镜面高光教程的着色器代码,以计算光照,其中漫射材质颜色由纹理确定。如果你还没有阅读过纹理球体教程或镜面高光教程,现在是阅读它们的好时机。
在纹理球体教程中,纹理颜色用作片段着色器的输出。但是,也可以使用纹理颜色作为光照计算中的任何参数,特别是用于漫射反射的材质常数,它在漫射反射教程中介绍。它出现在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 反射模型的其余部分,即环境项和镜面项,你应该阅读镜面高光教程。
- 关于纹理的基础知识,你应该阅读纹理球体教程。
除非另有说明,否则本页面上的所有示例源代码均属公有领域。
返回OpenGL 编程 - 光照部分 | 返回GLSL 编程 - GLUT 部分 |