此篇是根据简单光照模型的理论为基础进行的实现,实现了平行光点,光源,锥形光的效果也算是光照的最基础的入门篇:
1.cbuffer:这里需要强调的是在构造Cbuffer的数据结构的时候,一定要注意字段的顺序,很容易出错。
重要:HLSL的结构体struct其实并不管你是一个变量还是几个变量,它就是按照一次放满一个float4的内存长度,多少变量都往一个float4里面塞,塞满了再接着塞下一个float4。测试结果显示:cbuffer的长度必须是float4的整数倍才行,不知道float+float3的这种组合是否可以正常获取数据,也不清楚float+float+float3+float3这种组合能不能正常分配到数据,关键取决于GPU的内存分配规则。
// 光源
struct LightBuffer
{
float mType; // 光源类型 4种
Vector3 mPosition; // 位置
float mAngleInnerCone; // 内角弧度
Vector3 mAttenuation; // 衰减因子,衰减=1/(x+ y* D+ z* D* D),D是距离
float mAngleOuterCone; // 外角弧度
Vector3 mDirection; // 方向 点光源无用
// 把光的基础颜色分成三种比较有针对性
Color4 mColorAmbient; // 环境光的颜色
Color4 mColorDiffuse; // 漫反射光的颜色
Color4 mColorSpecular; // 镜面光的颜色
};
// 材质
struct MaterialBuffer
{
Vector3 cameraPosition; //摄像机的位置
float shininess; //高光指数
Quaternion Ke; //材质的自发光
Quaternion Ka; //材质的环境光系数
Quaternion Kd; //材质的漫反射系数
Quaternion Ks; //材质的高光系数
};
2.ps:此实现是在ps里面实现的光照,vs里面基本无实现内容
// Pixel Shader
float4 PortPixelShader(PixelInputType input) : SV_TARGET
{
float4 resultColor = float4(0,0,0,1.0);
float4 colorDiffuse = mColorDiffuse; // 漫反射
float4 colorSpecular = mColorSpecular; // 镜面反射
float3 N = input.worldNormal; // 法向量
float3 L = float3(0,0,0); //光线向量
float3 V = cameraPosition - input.worldPosition.xyz; // 世界坐标指向相机(注意方向)
//1.自发光
resultColor = resultColor + Ke;
//2.环境光
resultColor = resultColor + Ka * mColorAmbient; // 对位相乘 (x1*y1,x2*y2,x3*y3,x4*y4)
int type = mType;
float atte = 1.0; // 衰减系数
float d = distance(mPosition, input.worldPosition.xyz); // 光源与点的距离
switch(type)
{
case 1: // 平行光源
L = mDirection;
break;
case 2: // 点光源
L = mPosition - input.worldPosition.xyz; // 方向为空间点-->光源
atte = 1 / (mAttenuation.x + mAttenuation.y * d + mAttenuation.z * d * d);
//atte = 1 / (1 + 0.01 * d + 0.0001 * d * d);
break;
case 3: // 锥形光源
L = mPosition - input.worldPosition.xyz; // 与点光源一致
atte = 1 / (mAttenuation.x + mAttenuation.y * d + mAttenuation.z * d * d);
//θ<α<φ 利用cos值进行比较,并且锥形外角小于PI
L = normalize(L);
float3 direction = normalize(mDirection); // 光源的方向,归一化
float cosa = dot(L, direction);
float coso = cos(mAngleOuterCone);
if(cosa<cos(mAngleInnerCone) && cosa>coso) // 半影区
{
atte = atte*(cosa - coso); // 利用余弦值来
}else if(cosa<coso)
{
atte = 0;
}
break;
default:
break;
}
// 对向量进行归一化
N = normalize(N);
L = normalize(L);
V = normalize(V);
//3.漫反射
float diff = max(dot(L, N),0); // L.N 点积,因为镜面反射会用到,这里提取出来。
resultColor = resultColor + Kd * colorDiffuse * diff * atte; // 漫反射公式:Dintensity*Dcolor *N.L,saturate保障值为[0,1]闭区间
//4.镜面反射
float3 R = normalize(2 * diff * N - L); // 这里求的是反射向量
resultColor = resultColor + Ks * colorSpecular * atte * pow(saturate(dot(R, V)), shininess); // R.V^n 高光指数在这里用上了
return resultColor;
}
基本思路,先算衰减值,然后再计算光照。