日期:2014-05-17 浏览次数:20985 次
在真实环境中,同一个物体在不同光源照射下的颜色并不一样,因为物体本身并没有颜色,而是它会反射不同颜色的光。物体对不同颜色光的吸收率、反射率,加上光泽度、透明度等其他物理属性组合在一起,定义了这个物体的材质。知道物体的材质,就能够方便地算出物体在不同光源照射下的颜色。这里简化山峰模型,统一使用陆地材质,水面则使用水材质,增加了平行光源、点光源和聚光灯三种光照模式,模拟一个更通用的山峰水波模型。实现流程和漫反射光实现基本一样。
首先编写着色器代码。平行光、点光和聚光灯均需要自己的数据结构和计算方法,可在一个头文件中进行定义。HLSL的头文件扩展名为hlsli,创建方法与创建C++头文件一样,其代码如下:
/***************************************************
/ LightBase.hlsli
/
/ 光源结构体和对应的光照计算方法。
/***************************************************/
struct DirectionalLight
{
float4 Ambient;
float4 Diffuse;
float4 Specular;
float3 Direction;
float pad;
};
struct PointLight
{
float4 Ambient;
float4 Diffuse;
float4 Specular;
float3 Position;
float Range;
float3 Att;
float pad;
};
struct SpotLight
{
float4 Ambient;
float4 Diffuse;
float4 Specular;
float3 Position;
float Range;
float3 Direction;
float Spot;
float3 Att;
float pad;
};
struct Material
{
float4 Ambient;
float4 Diffuse;
float4 Specular;
float4 Reflect;
};
//---------------------------------------------------
// 计算平行光源照射产生的环境光,漫反射光和高光
//---------------------------------------------------
void ComputeDirectionalLight(Material mat, DirectionalLightL,
float3 normal, float3 toEye,
out float4 ambient,
out float4 diffuse,
out float4 spec)
{
ambient = float4(0.0f, 0.0f, 0.0f,0.0f);
diffuse = float4(0.0f, 0.0f, 0.0f,0.0f);
spec = float4(0.0f, 0.0f, 0.0f, 0.0f);
// V向量的方向与光线的方向相反.
float3 lightVec =-L.Direction;
// 计算环境光
ambient =mat.Ambient * L.Ambient;
// 计算漫反射光和高光
// 如果V向量与法向量夹角小于零,无需计算
float diffuseFactor =dot(lightVec, normal);
[flatten]
if( diffuseFactor >0.0f )
{
float3 v = reflect(-lightVec, normal);
float specFactor =pow(max(dot(v, toEye), 0.0f), mat.Specular.w);
diffuse =diffuseFactor * mat.Diffuse * L.Diffuse;
spec = specFactor * mat.Specular * L.Specular;
}
}
//---------------------------------------------------
// 计算点光源照射产生的环境光,漫反射光和高光
//---------------------------------------------------
void ComputePointLight(Material mat, PointLight L, float3 pos, float3 normal, float3 toEye,
out float4 ambient, out float4 diffuse, out float4 spec)
{
ambient = float4(0.0f, 0.0f, 0.0f,0.0f);
diffuse = float4(0.0f, 0.0f, 0.0f,0.0f);
spec = float4(0.0f, 0.0f, 0.0f, 0.0f);
// 点光源指向物体表面的光线向量
float3 lightVec =L.Position - pos;
// 点光源到物体表面的距离,用于计算衰减
float d =length(lightVec);
// 超出点光源照射范围不计算
if( d > L.Range )
return;
// 归一化光线向量
lightVec /= d;
// 计算环境光
ambient = mat.Ambient* L.Ambient;
// 计算漫反射光和高光
// 如果V向量与法向量夹角小于零,无需计算
float diffuseFactor =dot(lightVec, normal);
[flatten]
if( diffuseFactor >0.0f )
{
float3 v = reflect(-lightVec, normal);
float specFactor =pow(max(dot(v, toEye), 0.0f), mat.Specular.w);
diffuse =diffuseFactor * mat.Diffuse * L.Diffuse;
spec = specFactor * mat.Specular * L.Specular;
}
// 计算衰减
float att = 1.0f /dot(L.Att, float3(1.0f, d, d*d));
diffuse *= att;
spec *= att;
}
//---------------------------------------------------
// 计算聚光灯光源照射产生的环境光,漫反射光和高光
//---------------------------------------------------
void ComputeSpotLight(Material mat, SpotLight L, float3 pos, float3 normal, float3 toEye,
out float4 ambient, out float4 diffuse, out float4 spec)
{
ambient = float4(0.0f, 0.0f, 0.0f,0.0f);
diffuse = float4(0.0f, 0.0f, 0.0f,0.0f);
spec = float4(0.0f, 0.0f, 0.0f, 0.0f);
// 点光源指向物体表面的光线向量
float3 lightVec =L.Position - pos;
// 点光源到物体表面的距离,用于计算衰减