`

简单光照实现

 
阅读更多

此篇是根据简单光照模型的理论为基础进行的实现,实现了平行光点,光源,锥形光的效果也算是光照的最基础的入门篇:

 

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;
}
 基本思路,先算衰减值,然后再计算光照。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics