Directx11教程三十二之MultipleLightShadowMapping

这节教程采用的结构和上一节教程“D3D11教程三十一之ShadowMap(阴影贴图)” 是一样的,上节教程是一个点光源而已,而这一节教程是采用多个点光源,来加深我们对ShadowMap的理解。





这节教程没多少好说的,直接放出我的Shader


Light.fx       (直接定义计算点光源光照的函数)

//这个文件包含一些计算光效果的函数

//这个函数用于计算点光源的衰减强度
//第一个参数为点光源位置,第二个参数为像素位置,第三个参数为像素法线量,第四个参数为在点光源处最初的漫反射光颜色
float4 ComputePLightDiffuse(float3 LightPos, float3 PixelPos,float3 PixelNormal,float4 DiffuseColor)
{
	float DiffuseIntensity;
	float3 DiffuseDir; 
	float3 InvseDiffuseDir;
	float DiffuseFactor;
	float4 FinalDiffuseLight;

    //求出漫反射光的的方向
	DiffuseDir = PixelPos - LightPos;

	//求出点光源和像素(片元)之间的距离
	float distance = length(DiffuseDir);

	//三个衰减系数
	float atten1 = 1.0f;
	float atten2 = 0.2f;
	float atten3 = 0.0f;

	//求出衰减强度
	DiffuseIntensity = 1.0f / (atten1 + atten2*distance + atten3*distance*distance);


	//求出漫反射光的反方向
	InvseDiffuseDir = -DiffuseDir;

	//求出漫反射因子,范围[0.0,1.0]
	DiffuseFactor= saturate(dot(InvseDiffuseDir, PixelNormal));

	//求出最终照射在该像素点上的漫反射光
	FinalDiffuseLight= DiffuseFactor*DiffuseIntensity*DiffuseColor;


	return FinalDiffuseLight;
}


DrawShadowShader.fx


#include"Light.fx"  //用于计算点光源漫反射光的函数
Texture2D BaseTexture:register(t0);  //基础纹理
Texture2D ShadowMap1:register(t1);  //投影纹理
Texture2D ShadowMap2:register(t2);  //投影纹理
SamplerState WrapSampleType:register(s0);   //采样方式
SamplerState ClampSampleType:register(s1);   //采样方式

//VertexShader
cbuffer CBMatrix:register(b0)
{
	matrix World;
	matrix View;
	matrix Proj;
	matrix WorldInvTranspose;
	matrix ProjectorView1;
	matrix ProjectorProj1;
	matrix ProjectorView2;
	matrix ProjectorProj2;
};

cbuffer CBLight:register(b1)
{
	float4 AmbientColor;
	float3 PointLightPos1;
	float pad1;
	float4 diffuseColor1;
	float3 PointLightPos2;
	float pad2;
	float4 diffuseColor2;
}

struct VertexIn
{
	float3 Pos:POSITION;
	float2 Tex:TEXCOORD0;  //多重纹理可以用其它数字
	float3 Normal:NORMAL;
};


struct VertexOut
{
	float4 Pos:SV_POSITION;
	float4 ProjPos1:POSITION; //基于点光源投影在齐次裁剪空间的坐标
	float4 ProjPos2:POSITION1; //基于点光源投影在齐次裁剪空间的坐标
	float2 Tex:TEXCOORD0;
	float3 W_Normal:NORMAL;  //世界空间的法线
	float3 Pos_W:NORMAL1; //物体在世界空间的顶点坐标

};


VertexOut VS(VertexIn ina)
{
	VertexOut outa;

	//将坐标变换到观察相机下的齐次裁剪空间
	outa.Pos = mul(float4(ina.Pos,1.0f), World);
	outa.Pos = mul(outa.Pos, View);
	outa.Pos = mul(outa.Pos, Proj);

	//将顶点法向量由局部坐标变换到世界坐标
	outa.W_Normal = mul(ina.Normal, (float3x3)WorldInvTranspose);  //此事世界逆转置矩阵的第四行本来就没啥用

	//对世界空间的顶点法向量进行规格化
	outa.W_Normal = normalize(outa.W_Normal);

	//获取纹理坐标
	outa.Tex= ina.Tex;

	//将坐标变换到投影相机1下的齐次裁剪空间
	outa.ProjPos1= mul(float4(ina.Pos, 1.0f), World);
	outa.ProjPos1 = mul(outa.ProjPos1, ProjectorView1);
	outa.ProjPos1 = mul(outa.ProjPos1, ProjectorProj1);

	//将坐标变换到投影相机1下的齐次裁剪空间
	outa.ProjPos2 = mul(float4(ina.Pos, 1.0f), World);
	outa.ProjPos2 = mul(outa.ProjPos2, ProjectorView2);
	outa.ProjPos2 = mul(outa.ProjPos2, ProjectorProj2);

	//获取物体在世界空间下的坐标
	outa.Pos_W= (float3)mul(float4(ina.Pos, 1.0f), World);
	return outa;
}


float4 PS(VertexOut outa) : SV_Target
{
	float4 TexColor; //采集基础纹理颜色
    float ShadowMapDepth; //a,g,b存储的都是深度
	float4 DiffuseLight; //点光源照射在像素点的漫反射光
    float2 ShadowTex;   //阴影纹理坐标
	float4 color = {0.0f,0.0f,0.0f,0.0f}; //最终输出的颜色
	float Depth;
	float bias;


	//设置偏斜量
	bias = 0.001f;

	//第一,获取基础纹理的采样颜色
    TexColor = BaseTexture.Sample(WrapSampleType, outa.Tex);

	//第二,不管有没有遮挡,都应该具备环境光,注意环境光不生成阴影,这里仅仅是漫反射光生成阴影
	color = AmbientColor;

	
	//第三,求出相应顶点坐标对应在ShdowMap1上的深度值
	//获取投影相机1下的投影纹理空间的坐标值[0.0,1.0]  u=0.5*x+0.5;   v=-0.5*y+0.5;   -w<=x<=w  -w<=y<=w  
	ShadowTex.x = (outa.ProjPos1.x / outa.ProjPos1.w)*0.5f + 0.5f;
	ShadowTex.y = (outa.ProjPos1.y / outa.ProjPos1.w)*(-0.5f) + 0.5f;
	

	//第四,由于3D模型可能超出投影相机下的视截体,其投影纹理可能不在[0.0,1.0],所以得进行判定这个3D物体投影的部分是否在视截体内(没SV_POSITION签名 显卡不会进行裁剪)
	if (saturate(ShadowTex.x) == ShadowTex.x&&saturate(ShadowTex.y) == ShadowTex.y)
	{
		//求出顶点纹理坐标对应的深度值
		ShadowMapDepth = ShadowMap1.Sample(ClampSampleType, ShadowTex).r;

		//求出顶点坐标相应的深度值(点光源到渲染点的深度值)
		Depth = outa.ProjPos1.z / outa.ProjPos1.w;

		//减去阴影偏斜量
		Depth = Depth - bias;

		//如果不被遮挡,则物体具备漫反射光
		if (ShadowMapDepth >= Depth)
		{
			//求出漫射光
			DiffuseLight =ComputePLightDiffuse(PointLightPos1, outa.Pos_W, outa.W_Normal, diffuseColor1);

			//颜色加上漫反射光
			color += DiffuseLight;
			color = saturate(color);	
		}
	}


	//第五,求出相应顶点坐标对应在ShdowMap2上的深度值
	//获取投影相机1下的投影纹理空间的坐标值[0.0,1.0]  u=0.5*x+0.5;   v=-0.5*y+0.5;   -w<=x<=w  -w<=y<=w  
	ShadowTex.x = (outa.ProjPos2.x / outa.ProjPos2.w)*0.5f + 0.5f;
	ShadowTex.y = (outa.ProjPos2.y / outa.ProjPos2.w)*(-0.5f) + 0.5f;

	//第六,由于3D模型可能超出投影相机下的视截体,其投影纹理可能不在[0.0,1.0],所以得进行判定这个3D物体投影的部分是否在视截体内(没SV_POSITION签名 显卡不会进行裁剪)
	if (saturate(ShadowTex.x) == ShadowTex.x&&saturate(ShadowTex.y) == ShadowTex.y)
	{
		//求出顶点纹理坐标对应的深度值
		ShadowMapDepth = ShadowMap2.Sample(ClampSampleType, ShadowTex).r;

		//求出顶点坐标相应的深度值(点光源到渲染点的深度值)
		Depth = outa.ProjPos2.z / outa.ProjPos2.w;

		//减去阴影偏斜量
		Depth = Depth - bias;

		//如果不被遮挡,则物体具备漫反射光
		if (ShadowMapDepth >= Depth)
		{
			//求出漫射光
			DiffuseLight = ComputePLightDiffuse(PointLightPos2, outa.Pos_W, outa.W_Normal, diffuseColor2);

			//颜色加上漫反射光
			color += DiffuseLight;
			color = saturate(color);
		}
	}
	
	//第七,用灯光颜色调节纹理颜色
	color = color*TexColor;

	return color;
}


这里有两个点光源,PointLight1和PointLight2,位置分别为(-5.0f,8.0f, -5.0f)和(5.0f, 8.0f, -5.0f)


点光源1和点光源2都发出白色的光,  环境光AmbientColor(0.20f, 0.20f, 0.20f, 1.0f)



点光源1发出红色的光,点光源2发出绿色的光,   环境光AmbientColor(0.20f, 0.20f, 0.20f, 1.0f)





最后得注意的是:一个点光源使用一张ShadowMap,多个点光源就使用多张ShadowMap


下面放出我的源代码链接:

http://download.csdn.net/detail/qq_29523119/9673575


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值