Shader 多个点光源

 

原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!636.entry

程序截图

本教程基于教程17中实现的点光源+自阴影,要实现多个光源,原理上并没有什么新东西。

多个点光源

要实现多个点光源,我们需要在shader中使用n次光照方程。因此,如果有三个光源,我们需要为三个光源的漫反射、镜面高光、自阴影和衰减,下面是光照方程:

光照方程

如你所见,除了需要对阴影、漫反射、镜面高光和衰减求和,上面的光照方程与教程17是相同的。

例如有三个光源,一个紫色、一个绿色、一个蓝色位于物体的周围,则结果如下图所示:

多个点光源

实现shader

我们需要计算光照方程n次。本例中,我实现了3个光源。这意味着我需要发送3个位置、光照范围和颜色到shader中:

1float4 LightColor;
2float4 LightColor2;
3float4 LightColor3;
4float3 vecLightPos;
5float3 vecLightPos2;
6float3 vecLightPos3;
7float LightRange;
8float LightRange2;
9float LightRange3;

然后,在顶点着色器中,我想需要计算顶点到光源的距离,将光源位置转换到切线空间中(法线映射)并计算每个光源的衰减:

01// calculate distance to light in world space
02float3 L = vecLightPos - PosWorld;
03float3 L2 = vecLightPos2 - PosWorld;
04float3 L3 = vecLightPos3 - PosWorld;
05  
06// Transform light to tangent space
07Out.Light.xyz = normalize(mul(worldToTangentSpace, L)); // L, light
08Out.Light2.xyz = normalize(mul(worldToTangentSpace, L2)); // L2, light
09Out.Light3.xyz = normalize(mul(worldToTangentSpace, L3)); // L3, light
10  
11// Add range to the light, attenuation
12Out.Light.w = saturate( 1 - dot(L / LightRange, L / LightRange));
13Out.Light2.w = saturate( 1 - dot(L2 / LightRange2, L2 / LightRange2));
14Out.Light3.w = saturate( 1 - dot(L3 / LightRange3, L3 / LightRange3));

其实没什么新东西,只不过将教程17中的步骤做了3次而已。

下面看一下像素着色器。首先需要计算每个光源的方向:

1// Get light direction/view from vertex shader output
2float3 LightDir = normalize(L.xyz);// L
3float3 LightDir2 = normalize(L2.xyz);// L2
4float3 LightDir3 = normalize(L3.xyz);// L3

然后使用上面的光照公式(1)计算漫反射、镜面高光和自阴影:

01// diffuse
02float D = saturate(dot(N, LightDir)); 
03float D2 = saturate(dot(N, LightDir2)); 
04float D3 = saturate(dot(N, LightDir3)); 
05  
06// Self shadow - used to avoid light artifacts
07float Shadow = saturate(4.0 * LightDir.z);
08float Shadow2 = saturate(4.0 * LightDir2.z);
09float Shadow3 = saturate(4.0 * LightDir3.z);
10      
11// reflection
12float3 R = normalize(2 * D * N - LightDir); // R
13float3 R2 = normalize(2 * D2 * N - LightDir2); // R
14float3 R3 = normalize(2 * D3 * N - LightDir3); // R
15  
16// specular
17float S = min(pow(saturate(dot(R, ViewDir)), 3), Color.w);
18float S2 = min(pow(saturate(dot(R2, ViewDir)), 3), Color.w);
19float S3 = min(pow(saturate(dot(R3, ViewDir)), 3), Color.w);

现在我们已经从光照方程中计算得出需要的东西,下面使用公式(2)实现最终的颜色:

1// calculate three point lights:
2// Ambient +  Shadow*((Diffuse + Specular)*Attenuation in L.w);
3float4 light1final = Shadow*((Color * D  * LightColor + S*LightColor) * (L.w));
4float4 light2final = Shadow2*((Color * D2  * LightColor2 + S2*LightColor2) * (L2.w));
5float4 light3final = Shadow3*((Color * D3  * LightColor3 + S3*LightColor3) * (L3.w));
6return 0.1 * Color + light1final + light2final + light3final;

好了,就是这些!简单地说,要获得n个光照的效果,你需要计算光照方程n次。

使用shader

与教程17相比并没有什么新东西。但是这次我们需要传递3个光源的位置、颜色和光照范围:

01// Set the light positions for each of the lights 
02effect.Parameters["vecLightPos"].SetValue(vLightPosition); 
03effect.Parameters["vecLightPos2"].SetValue(vLightPosition2); 
04effect.Parameters["vecLightPos3"].SetValue(vLightPosition3); 
05  
06// Set the light range and color for each of the lights 
07effect.Parameters["LightRange"].SetValue(3.0f); 
08effect.Parameters["LightColor"].SetValue(vLightColor); 
09effect.Parameters["LightRange2"].SetValue(3.0f); 
10effect.Parameters["LightColor2"].SetValue(vLightColor2); 
11effect.Parameters["LightRange3"].SetValue(3.0f); 
12effect.Parameters["LightColor3"].SetValue(vLightColor3);

注意:你可能注意到这里我没有使用effect.commitChanges(); 如果使用这个shader绘制许多物体,你应该在pass.Begin()中添加这个代码,这样改变才会作用到当前pass,而不是下一个pass,如果你在pass内部设置了shader参数这一步是必须的。

文件下载,已下载146次
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值