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


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

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

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

           OpenGL固定渲染管线主要实现的是高洛德着色模型,这是一种简单的光照效果,主要应用在实时渲染领域。

    我这次实践主要将全局光照、漫反射效果以及镜面反射效果实现了,漫反射使用了兰伯特(Lambert)公式、镜面反射使用可比林 – 冯(Blinn - Phong)公式。

           以下是程序的截图:

           这里使用了三盏灯光,分别在角色左上角、右下角和正后方。使用的是同一颜色:白色。

    同一时候设置全局的光颜色为黑色。这样能够凸显出每一个光源的着色效果。

           为了实现这种效果。我在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;
    }

  • 相关阅读:
    mysql常用语句、命令(增删改查功能)
    MySQL 入门知识点
    windows下安装mysql解压版
    第4章 HDFS操作
    第3章 Hadoop 2.x分布式集群搭建
    第2章 CentOS7集群环境配置
    第1章 VMware中安装CentOS7
    windows10激活方法
    linux系统下操作mysql数据库常见命令
    xampp搭建开源项目iwebshop后,服务器重启后再启动xampp显示组件都启动ok,但是实际启动失败解决办法
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/7001559.html
Copyright © 2020-2023  润新知