此篇是根据简单光照模型的理论为基础进行的实现,实现了平行光点,光源,锥形光的效果也算是光照的最基础的入门篇:
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; }基本思路,先算衰减值,然后再计算光照。