opengl 教程(20) 点光源

http://www.cnblogs.com/mikewolf2002/archive/2013/01/26/2877507.html


原帖地址: http://ogldev.atspace.co.uk/www/tutorial20/tutorial20.html

      前面的教程中,我们在方向光的前提下,研究了基本的光照模型(环境光,漫反射光,高光)。方向光没有起点,所有光线都是沿着一个方向,它的强度不会随着距离的增加有任何变化。本篇教程中,我们开始研究点光源,点光源是起始于一个点,向四面照射,会随着传输距离增加而衰减,所以在点光源属性中,我们会增加一个光源位置。

通常点光源衰减程度离物体距离的平方成反,如下面的公式:

inverse_square_law

      但在距离比较小的时候,上面的公式在3D图形学中,效果并不好,所以我们计算点光源衰减系数时候,常使用下面的公式:它包括3个因子,常量因子,线性因子和二次因子。

attenuation

下面我们总结一下计算点光源时需要的步骤:

  1. 环境光的计算和方向光一样
  2. 在世界坐标系中,计算点(像素)到光源的方向,做为光源的方向向量。
  3. 计算像素到光源的距离,用来计算衰减因子。
  4. 把环境光、漫反射光和高光加起来,然后乘以衰减因子。
 

lighting_technique.h

struct BaseLight 

Vector3f Color; 
float AmbientIntensity; 
float DiffuseIntensity; 
}; 



struct PointLight : public BaseLight 

Vector3f Position; 
struct 

float Constant; 
float Linear; 
float Exp; 
} Attenuation; 
}

      建立一个BaseLight类,抽象出光源的共有属性,然后派生出点光源和方向光源,它们都有自己特有的属性,比如点光源的位置,衰减系数,方向光的方向等等。

lighting_technique.h

void SetPointLights(unsigned int NumLights, const PointLight* pLights);

除了演示点光源,本教程中还要实施多光源,包括一个方向光和多个电光源。

struct { 
GLuint Color; 
GLuint AmbientIntensity; 
GLuint DiffuseIntensity; 
GLuint Position; 
struct 

GLuint Constant; 
GLuint Linear; 
GLuint Exp; 
} Atten; 
} m_pointLightsLocation[MAX_POINT_LIGHTS];

我们使用结构数组来实现多个点光源,MAX_POINT_LIGHTS是个常量值,指定光源的数目,缺省值是2。

lighting_technique.cpp

vec4 CalcLightInternal(BaseLight Light, vec3 LightDirection, vec3 Normal) 

vec4 AmbientColor = vec4(Light.Color, 1.0f) * Light.AmbientIntensity; 
float DiffuseFactor = dot(Normal, -LightDirection); 
vec4 DiffuseColor = vec4(0, 0, 0, 0); 
vec4 SpecularColor = vec4(0, 0, 0, 0); 
if (DiffuseFactor > 0) { 
DiffuseColor = vec4(Light.Color, 1.0f) * Light.DiffuseIntensity * DiffuseFactor; 
vec3 VertexToEye = normalize(gEyeWorldPos - WorldPos0); 
vec3 LightReflect = normalize(reflect(LightDirection, Normal)); 
float SpecularFactor = dot(VertexToEye, LightReflect); 
SpecularFactor = pow(SpecularFactor, gSpecularPower); 
if (SpecularFactor > 0) { 
SpecularColor = vec4(Light.Color, 1.0f) * 
gMatSpecularIntensity * SpecularFactor; 


return (AmbientColor + DiffuseColor + SpecularColor); 
}

上面是计算点光源的通用函数,计算点光源和方向光时候,我们都可以调用该函数来实现。

vec4 CalcDirectionalLight(vec3 Normal) 

return CalcLightInternal(gDirectionalLight.Base, gDirectionalLight.Direction, Normal); 
}

上面是调用该函数实现方向光计算。

vec4 CalcPointLight(int Index, vec3 Normal) 

vec3 LightDirection = WorldPos0 - gPointLights[Index].Position; 
float Distance = length(LightDirection); 
LightDirection = normalize(LightDirection); 
vec4 Color = CalcLightInternal(gPointLights[Index].Base, LightDirection, Normal); 
float Attenuation = gPointLights[Index].Atten.Constant + 
gPointLights[Index].Atten.Linear * Distance + 
gPointLights[Index].Atten.Exp * Distance * Distance; 
return Color / Attenuation; 
}

上面是调用该函数实现点光源计算。

void main() 

vec3 Normal = normalize(Normal0); 
vec4 TotalLight = CalcDirectionalLight(Normal); 
for (int i = 0 ; i < gNumPointLights ; i++) { 
TotalLight += CalcPointLight(i, Normal); 

FragColor = texture2D(gSampler, TexCoord0.xy) * TotalLight; 
}

最终输出最终像素颜色时候,我们把所有光源的效果加起来,并用纹理颜色进行调制。

void LightingTechnique::SetPointLights(unsigned int NumLights, const PointLight* pLights) { 
glUniform1i(m_numPointLightsLocation, NumLights); 
for (unsigned int i = 0 ; i < NumLights ; i++) { 
glUniform3f(m_pointLightsLocation[i].Color, pLights[i].Color.x, pLights[i].Color.y, pLights[i].Color.z); 
glUniform1f(m_pointLightsLocation[i].AmbientIntensity, pLights[i].AmbientIntensity); 
glUniform1f(m_pointLightsLocation[i].DiffuseIntensity, pLights[i].DiffuseIntensity); 
glUniform3f(m_pointLightsLocation[i].Position, pLights[i].Position.x, pLights[i].Position.y, pLights[i].Position.z); 
glUniform1f(m_pointLightsLocation[i].Atten.Constant, pLights[i].Attenuation.Constant); 
glUniform1f(m_pointLightsLocation[i].Atten.Linear, pLights[i].Attenuation.Linear); 
glUniform1f(m_pointLightsLocation[i].Atten.Exp, pLights[i].Attenuation.Exp); 

}

上面是给各个uniform变量赋值。

程序执行后界面如下,我们使用了2个点光源:

clipboard


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值