D3D中光源可大致分为3种,点光源,方向光,环境光
1)
可以大致对应我们生活中的 电灯泡,太阳光,环境光。通过抽象各种光的性质,我们可以使用结构体Light,以更方便地表示光。
光可以定义如下
Struct Light { D3DXVECTOR3 pos;//位置 D3DXVECTOR3 dir;//方向 D3DXCOLOR ambiet;//环境光颜色 D3DXCOLOR diffuse;//漫反射颜色 D3DXCOLOR specular;//镜面反射颜色 float power;//光强 }
从C++代码中定义各个分量,再通过Effect接口传入效果文件中。定义光源。下面是使用Light结构体定义一个具体的光(方向光的例子)
C++代码:
mParallelLight.dir = D3DXVECTOR3(0.57735f, -0.57735f, 0.57735f); mParallelLight.ambient = D3DXCOLOR(0.4f, 0.4f, 0.4f, 1.0f); mParallelLight.diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); mParallelLight.specular = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
2)
与之前的顶点赋色不同,当有光照参与时,需要为物体设置材质。通过计算光照与材质,最终得到物体的颜色。
例如
struct Material { Material() { ZeroMemory(this,sizeof(Material)); } D3DXCOLOR ambient; D3DXCOLOR diffuse; D3DXCOLOR specular; float specpow; };
由于D3D用三角形网格描述物体,而网格最终由顶点组成。所以材质的定义还是要落在顶点属性里。
例如
struct Vertex
{
D3DVECTOR3 pos;
D3DVECTOR3 normal;
D3DXCOLOR ambient;
D3DXCOLOR diffuse;
D3DXCOLOR specular;
}
通过定义顶点布局,使效果文件知道如何使用Vertex的各个分量。
3)
光照与材质生成物体颜色的计算过程,我们在像素着色器中完成。
下面是以平行光照射物体的处理为例。一段像素着色器的HLSL代码
float4 PS(VS_OUT pIn) : SV_Target
{
pIn.normalW = normalize(pIn.normalW);
SurfaceInfo v = {pIn.posW, pIn.normalW, pIn.diffuse, pIn.spec};
float3 litColor;
litColor = ParallelLight(v, gLight, gEyePosW);
return float4(litColor, pIn.diffuse.a);
}
补充平行光与材质作用的具体光照方程(HLSL):
float3 ParallelLight(SurfaceInfo v, Light L, float3 eyePos) { float3 litColor = float3(0.0f, 0.0f, 0.0f); // The light vector aims opposite the direction the light rays travel. float3 lightVec = -L.dir; // Add the ambient term. litColor += v.diffuse * L.ambient; // Add diffuse and specular term, provided the surface is in // the line of site of the light. float diffuseFactor = dot(lightVec, v.normal); [branch] if( diffuseFactor > 0.0f ) { float specPower = max(v.spec.a, 1.0f); float3 toEye = normalize(eyePos - v.pos); float3 R = reflect(-lightVec, v.normal); float specFactor = pow(max(dot(R, toEye), 0.0f), specPower); // diffuse and specular terms litColor += diffuseFactor * v.diffuse * L.diffuse; litColor += specFactor * v.spec * L.spec; } return litColor; }
在我们的程序中,存放在顶点缓冲区中的顶点数据首先经过顶点着色器,从顶点着色器出来后,进入像素着色器。完成光照计算。