使用GLSL实现对光照的模拟(二)

使用GLSL实现对光照的模拟(二)

       上一篇文章讲到了我对于光照这一块的实践,这回折腾了一阵子,写了一个小小的应用程序,测试我写的光照是否还有问题。

原创文章,反对未声明的引用。原博客地址:http://blog.csdn.net/gamesdev/article/details/24199913

       OpenGL固定渲染管线主要实现的是高洛德着色模型,这是一种简单的光照效果,主要应用在实时渲染领域。我这次实践主要将全局光照、漫反射效果以及镜面反射效果实现了,漫反射使用了兰伯特(Lambert)公式、镜面反射使用可比林 – 冯(Blinn - Phong)公式。

       下面是程序的截图:

使用GLSL实现对光照的模拟(二)_第1张图片

       这里使用了三盏灯光,分别在角色左上角、右下角和正后方。使用的是同一颜色:白色。同时设置全局的光颜色为黑色,这样可以凸显出每个光源的着色效果。

       为了实现这样的效果,我在Host端定义了光源基类,并且有一些派生类来实现。下面是相关类的代码:

class BaseLight
{
    bool            m_Enabled;
    Vector3F        m_Ambient;
    Vector3F        m_Diffuse;
    Vector3F        m_Specular;
};
/*---------------------------------------------------------------------------*/
class DirectionalLight: public BaseLight
{
    Vector3F        m_Direction;
    Vector3F        m_HalfPlane;
};
/*---------------------------------------------------------------------------*/
class PointLight: public BaseLight
{
    Vector3F        m_Position;
    Vector3F        m_SpotDirection;
    Vector3F        m_Attenuation;// K0, K1 and K2
    float           m_Exponent;
};
/*---------------------------------------------------------------------------*/
class SpotLight: public PointLight
{
    float           m_CutOffAngle;
};

而在着色器端,我同样定义了类似的数据结构。由于GLSL不支持class以及继承,有些成员只得重复定义了。我将方向光源、点光源以及聚光灯这三类光源分开,存入了vary中,若有需要,可在片断着色器中处理颜色的混合。下面是GLSL代码:

/*---------------------------------------------------------------------------*/
attribute vec3 position;
attribute vec3 normal;
attribute vec3 texCoord;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
varying vec2 v_TexCoord;
/*---------------------------------------------------------------------------*/
struct DirectionalLight// 方向光源
{
    int         enabled;
    vec3        ambient;
    vec3        diffuse;
    vec3        specular;
    vec3        direction;
    vec3        halfPlane;
};
/*---------------------------------------------------------------------------*/
struct PointLight// 点光源
{
    int         enabled;
    vec3        ambient;
    vec3        diffuse;
    vec3        specular;
    vec3        position;
    vec3        spotDirection;
    vec3        attenuation;
    float       exponent;
};
/*---------------------------------------------------------------------------*/
struct SpotLight// 聚光灯
{
    int         enabled;
    vec3        ambient;
    vec3        diffuse;
    vec3        specular;
    vec3        position;
    vec3        spotDirection;
    vec3        attenuation;
    float       exponent;
    float       cutOffAngle;
};
/*---------------------------------------------------------------------------*/
const int                       MAX_LIGHT = 8;// 通过修改此参数以修改最多多少个光源
uniform int                     directionalLightCount;
uniform int                     pointLightCount;
uniform int                     spotLightCount;
uniform DirectionalLight        directionalLight[MAX_LIGHT];
uniform PointLight              pointLight[MAX_LIGHT];
uniform SpotLight               spotLight[MAX_LIGHT];
uniform int                     lightingIsEnabled;

// 这些是由模型传来的材质参数
uniform float shininess;

varying vec3 directionalAmbient;
varying vec3 directionalDiffuse;
varying vec3 directionalSpecular;
varying vec3 pointAmbient;
varying vec3 pointDiffuse;
varying vec3 pointSpecular;
varying vec3 spotAmbient;
varying vec3 spotDiffuse;
varying vec3 spotSpecular;
/*---------------------------------------------------------------------------*/
void InitLightOutput( void )
{
    directionalAmbient = vec3( 0.0 );
    directionalDiffuse = vec3( 0.0 );
    directionalSpecular = vec3( 0.0 );
    pointAmbient = vec3( 0.0 );
    pointDiffuse = vec3( 0.0 );
    pointSpecular = vec3( 0.0 );
    spotAmbient = vec3( 0.0 );
    spotDiffuse = vec3( 0.0 );
    spotSpecular = vec3( 0.0 );
}
/*---------------------------------------------------------------------------*/
void DirectionalLighting( vec3 position, vec3 normal )
{
    for ( int i = 0; i < directionalLightCount; ++i )
    {
        if ( directionalLight[i].enabled == 0 ) continue;

        vec3 N = normalize( normal );
        vec3 V = normalize( position );
        vec3 L = normalize( directionalLight[i].direction );
        vec3 H = normalize( directionalLight[i].halfPlane );

        // 计算全局光
        directionalAmbient += directionalLight[i].ambient;

        // 使用兰伯特余弦定律(Lambert' cosine law)计算漫反射
        float NdotL = max( 0.0, dot( N, L ) );
        directionalDiffuse += directionalLight[i].diffuse * NdotL;

        // 使用比林 - 冯着色模型(Blinn - Phong shading model)来计算镜面反射
        float NdotH = max( 0.0, pow( dot( N, H ), shininess ) );
        directionalSpecular += directionalLight[i].specular * NdotH;
    }
}
/*---------------------------------------------------------------------------*/
void PointLighting( vec3 position, vec3 normal )
{
    for ( int i = 0; i < pointLightCount; ++i )
    {
        if ( pointLight[i].enabled == 0 ) continue;

        vec3 N = normalize( normal );
        vec3 V = normalize( position );
        vec3 L = normalize( pointLight[i].position - position );
        vec3 H = normalize( V + L );

        // 计算衰减
        float d = length( pointLight[i].position - position );
        float attenuation = 1.0 / (
                    pointLight[i].attenuation[0] +
                pointLight[i].attenuation[1] * d +
                pointLight[i].attenuation[2] * d * d );

        // 计算全局光
        pointAmbient += pointLight[i].ambient * attenuation;

        // 使用兰伯特余弦定律(Lambert' cosine law)计算漫反射
        float NdotL = max( 0.0, dot( N, L ) );
        pointDiffuse += pointLight[i].diffuse * NdotL * attenuation;

        // 使用比林 - 冯着色模型(Blinn - Phong shading model)来计算镜面反射
        float NdotH = max( 0.0, pow( dot( N, H ), shininess ) );
        pointSpecular += pointLight[i].specular * NdotH * attenuation;
    }
}
/*---------------------------------------------------------------------------*/
void SpotLighting( vec3 position, vec3 normal )
{
    for ( int i = 0; i < spotLightCount; ++i )
    {
        if ( spotLight[i].enabled == 0 ) continue;

        vec3 N = normalize( normal );
        vec3 V = normalize( position );
        vec3 L = normalize( spotLight[i].position - position );
        vec3 H = normalize( V + L );

        // 计算衰减
        float d = length( spotLight[i].position - position );
        float attenuation = 1.0 / (
                    spotLight[i].attenuation[0] +
                spotLight[i].attenuation[1] * d +
                spotLight[i].attenuation[2] * d * d );


        // 计算顶点是否所在半切角内,来决定是否接受聚光灯光照
        float dotSpot = dot( -L, normalize( spotLight[i].spotDirection ) );
        float cosCutOff = cos( spotLight[i].cutOffAngle );
        float spotAttenuation = 0.0;
        if ( dotSpot > cosCutOff )// 顶点所在聚光灯光照范围内
        {
            spotAttenuation = pow( dotSpot, spotLight[i].exponent );
        }
        attenuation *= spotAttenuation;

        // 计算全局光
        spotAmbient += spotLight[i].ambient * attenuation;

        // 使用兰伯特余弦定律(Lambert' cosine law)计算漫反射
        float NdotL = max( 0.0, dot( N, L ) );
        spotDiffuse += spotLight[i].diffuse * NdotL * attenuation;

        // 使用比林 - 冯着色模型(Blinn - Phong shading model)来计算镜面反射
        float NdotH = max( 0.0, pow( dot( N, H ), shininess ) );
        spotSpecular += spotLight[i].specular * NdotH * attenuation;
    }
}
/*---------------------------------------------------------------------------*/
void main( void )
{
    if ( lightingIsEnabled == 1 )
    {
        InitLightOutput( );
        DirectionalLighting( position, normal );
        PointLighting( position, normal );
        SpotLighting( position, normal );
    }

    gl_Position =
            projectionMatrix *
            viewMatrix *
            modelMatrix *
            vec4( position, 1.0 );
    v_TexCoord = texCoord.xy;
}

你可能感兴趣的:(GLSL,Qt,OpenGL,Qt游戏开发,OpenGL探索,探索着色器)