日期:2014-05-17 浏览次数:20834 次
在真实环境中,同一个物体在不同光源照射下的颜色并不一样,因为物体本身并没有颜色,而是它会反射不同颜色的光。物体对不同颜色光的吸收率、反射率,加上光泽度、透明度等其他物理属性组合在一起,定义了这个物体的材质。知道物体的材质,就能够方便地算出物体在不同光源照射下的颜色。这里简化山峰模型,统一使用陆地材质,水面则使用水材质,增加了平行光源、点光源和聚光灯三种光照模式,模拟一个更通用的山峰水波模型。实现流程和漫反射光实现基本一样。
首先编写着色器代码。平行光、点光和聚光灯均需要自己的数据结构和计算方法,可在一个头文件中进行定义。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; // 点光源到物体表面的距离,用于计算衰减