[TOC]
2. Vertex Shader Examples
接下来通过一些实例来说明如何在顶点shader中实现下列功能:
- 用矩阵来变换顶点坐标
- 光照计算,生成逐顶点漫反射和高光反射
- 生成纹理坐标
- 顶点蒙皮
- 使用纹理查找值来代替顶点位置
Matrix Transformations
Example 8-1:
#version 300 es
uniform mat4 u_mvpMatrix;
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec4 a_color;
out vec4 v_color;
void main()
{
v_color = a_color;
gl_Position = u_mvpMatrix * a_position;
}
在第七章我们已经介绍过,顶点shader的输入位置是在物体坐标系中,输出位置是在裁剪坐标系中,这种变换是通过一个MVP矩阵来实现的:
- 模型矩阵:将物体坐标转换为世界坐标
- 视图矩阵:将世界坐标转换为视口坐标(眼睛坐标、摄像机坐标)
- 投影矩阵:将视口坐标转换为裁剪坐标
Lighting in a Vertex Shader
-
漫反射光照计算
漫反射光照颜色 = 光照强度 * 光照颜色 * cos(光照与法线夹角)
-
镜面反射-Phong
镜面反射特性:当R与V重合时光照最强,稍微有一点偏差就会有很大的衰减。
镜面反射光照颜色 = pow(dot(R, V), 光照颜色)
-
镜面反射-BlinnPhong
镜面反射光照颜色 = pow(dot(H, N), 光照颜色)
方向光
方向光,也叫平行光,是一个距离被照明物体无限远的光源,比如太阳光。由于距离物体无限远,所以方向光的光线都是平行的,照明方向向量是一个常量,不需要逐顶点计算。
Example 8-2
#version 300 es
struct directional_light
{
vec3 direction; // normalized
vec3 halfplane; // normalized
vec4 ambient_color;
vec4 diffuse_color;
vec4 specular_color;
};
struct material_properties
{
vec4 ambient_color;
vec4 diffuse_color;
vec4 specular_color;
float specular_exponent
};
const float c_zero = 0.0;
const float c_one = 1.0;
uniform material_properties material;
uniform directional_light light;
vec4 directional_light_color (vec3 normal)
{
vec4 computer_color = vec4 (c_zero, c_zero, c_zero, c_zero);
float NdotL = max (c_zero, dot (normal, light.direction));
float NdotH = max (c_zero, dot (normal, light.halfplane));
computer_color += light.ambient_color * material.ambient_color; //环境光
computer_color += NdotL * light.diffuse_color * material.diffuse_color; //漫反射光
if (NdotH > 0) {
computer_color += pow(NdotH, material.specular_exponent) * material.specular_color * light.specular_color; //镜面高光
}
return computer_color;
}
点光源和聚光灯
点光源是空间中某个位置向所有方向均匀发射光线的光源,由一个位置向量(x, y, z, w)指定,其中w≠0。点光源在各个方向上的亮度均匀,但是随着距离的递增,亮度递减,这种递减可用如下公式计算:
<center><font size = 4> 距离衰减 = 1 / (K0 + K1 * ||VPlight|| + K2 * ||VPlight||2 ) </font></center>
聚光灯是同时拥有位置和方向的锥体光源,如下图所示:
聚光灯的光照强度由光锥中轴向周围递减,衰减因子在光锥中轴为1,在光锥边缘按照指数关系衰减为0。
Example 8-3 Spotlight
#version 300 es
struct spot_light
{
vec4 position;
vec4 ambient_color;
vec4 diffuse_color;
vec4 specular_color;
vec3 spot_direction;
vec3 attenuation_factors; //距离衰减因子K<sub>0</sub>,K<sub>1</sub>,K<sub>2</sub>
bool compute_distance_attenuation;
float spot_exponent;
float spot_cutoff_angle;
};
struct material_properties
{
vec4 ambient_color;
vec4 diffuse_color;
vec4 specular_color;
float specular_exponent;
};
const float c_zero = 0.0;
const float c_one = 1.0;
uniform material_properties material;
uniform spot_light light;
vec4 spot_light_color (vec3 normal, vec4 position)
{
vec4 computed_color = vec4 (c_zero, c_zero, c_zero, c_zero);
vec3 lightDir;
vec3 halfplane;
float NdotL, NdotH;
float att_factor;
att_factor = c_one;
lightDir = light.position.xyz - position.xyz;
if (light. compute_distance_attenuation) {
vec3 att_dist;
att_dist.x = 1;
att_dist.z = dot (lightDir, lightDir);
att_dist.y = sqrt(att_dist.z);
att_factor = c_one / dot(att_dist, light.attenuation_factors);
}
lightDir = normalize (lightDir);
if (light.spot_cutoff_angle < 180.0) {
float spot_factor = dot (-lightDir, light.spot_direction);
if (spot_factor >= cos(radians(light.spot_cutoff_angle)) )
spot_factor = pow (spot_factor, light.spot_exponent);
else
spot_factor = c_zero;
att_factor *= spot_factor;
}
if (att_factor > c_zero) {
computed_color += light.ambient_color * material.ambient_color;
NdotL = max(c_zero, dot(normal, lightDir));
computed_color += NdotL * light.diffuse_color * material.diffuse_color;
halfplane = normailze (lightDir + vec3(c_zero, c_zero, c_one));
NdotH = dot (normal, halfplane);
if (NdotH > c_zero) {
computed_color += pow (NdotH, material.specular_exponent) * material.specular_color * light.specular_color;
}
computed_color *= att_factor;
}
return computed_color;
}
网友评论