OpenGL ES 3.0编程指南:第八章. Vertex Shaders---(二)

[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

  • 漫反射光照计算


    OpenGL ES 3.0编程指南:第八章. Vertex Shaders---(二)_第1张图片

    漫反射光照颜色 = 光照强度 * 光照颜色 * cos(光照与法线夹角)

  • 镜面反射-Phong


    OpenGL ES 3.0编程指南:第八章. Vertex Shaders---(二)_第2张图片

    OpenGL ES 3.0编程指南:第八章. Vertex Shaders---(二)_第3张图片

镜面反射特性:当R与V重合时光照最强,稍微有一点偏差就会有很大的衰减。
镜面反射光照颜色 = pow(dot(R, V), 光照颜色)

  • 镜面反射-BlinnPhong


    OpenGL ES 3.0编程指南:第八章. Vertex Shaders---(二)_第4张图片

    镜面反射光照颜色 = 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。点光源在各个方向上的亮度均匀,但是随着距离的递增,亮度递减,这种递减可用如下公式计算:

距离衰减 = 1 / (K0 + K1 * ||VPlight|| + K2 * ||VPlight||2 )

聚光灯是同时拥有位置和方向的锥体光源,如下图所示:


OpenGL ES 3.0编程指南:第八章. Vertex Shaders---(二)_第5张图片

聚光灯的光照强度由光锥中轴向周围递减,衰减因子在光锥中轴为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;    //距离衰减因子K0,K1,K2
    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;
}

你可能感兴趣的:(OpenGL ES 3.0编程指南:第八章. Vertex Shaders---(二))