您的位置:首页 > 编程语言 > Qt开发

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

2014-04-20 22:02 423 查看
使用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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  qt opengl glsl