[翻译]XNA 3.0 Game Programming Recipes之forty-four

PS:自己翻译的,转载请著明出处格
                                                                6-8 用HLSL定义一个聚光灯
问题
                        一个光照点作为在前面定义的一样,闪耀的光从一个点向所有方向。你想定义一个聚光灯,它它的行为完全像一个点光源,除了它照耀的象一个光核一样,如图6-10所显示。

解决方案
                        在你的象素着色器中,判断当前的象素是否在光照核内。你可以通过使用点乘积在光的方向和核的方向之间来实现这个。
它是如何工作的
                        开始前面小节的代码。由于一个聚光灯比一个光照点更个性化,你添加这些额外的XNA-to-HLSL变量到你的.fx文件中:
1 float xLightStrength;
2 float3 xConeDiection;
3 float xConeAngle;
4 float xConeDecay;
                        第一个变量将允许你增加/减少你的光照的强度。这同样很有用为任何光照的类型也是非常有必要的,当你有多个光照在你的屏幕中。接下来,你可以指定聚光灯核心的中心方向,和核心的宽度。最后,你可以指定多大的光照强度应该减少朝着核心的边缘。
                         除了这个,你需要扩展一下你的象素着色器。一般来说,你将会做相同的per-pixel光照点,但是你要添加一个检查去核实象素在光的核心中:
 1 SLPixelToFrame SLPixelShader(SLVertexToPixel PSIn):COLOR0
 2 {
 3      SLPixelToFrame Output=(SLPixelToFrame)0;
 4      float4 baseColor=float4(0,0,1,1);
 5      float3 normal=normalize(PSIn.Normal);
 6      float3 lightDirection=normalize(PSIn.LightDirection);
 7      float coneDot=dot(lightDirection,normalize(xConeDiection));
 8      float shading=0;
 9      if(coneDot>xConeAngle)
10      {
11               float coneAttenuation=pow(coneDot,xConeDecay);
12               shading=dot(normal,-lightDirection);
13               shading*=xLightStrength;
14               shading*=coneAttenuation;
15      }
16      Output.Color=baseColor*(shading+xAmbient);
17      return Output;
18 }
                          一旦你已经规格化法线和光照方向,你应该检测当前的象素是否在光的核心内。要做到这一点,你要检查两个方向之间的角度:
                        1。当前象素和光源之间的方向。
                        2。核心的中心方向。
                          第一个方向是lightDirection,同时第二个被指定在xConeDirection变量。只有在这个角度是低于某一临界值,像素应点亮。
                          一种为这个的快速检查是通过接收点乘积在两个方向之间 。一个值接近到1,意思是一个非常小的角度在两个方向之间,同时值越小表明角度越大。
                         为了测定角度是否太大,你检查这点乘积是否比临界值小,保存在xConeAngle内,如果象素是在核心内,你计算光照因子,称为shading.为了削弱光照效果接近于核心的边,你使用coneDot值到指定的强度在xConeDecay里,作为一个结果,coneDot值等于或者比1小,象素将变的更小,它离核心中心方向就越远。
                         核心以外的象素会得到一个shading值为0,所以光将有没有影响这些象素。
代码
                         你的完整的象素着色器已经列出来了。
                         在你的XNA代码的Draw方法中,一个有活力的效果,设置它的参数,绘制到你的屏幕中:
 1 effect.CurrentTechnique=effect.Technique["SpotLight"];
 2 effect.Parameters["xWorld"].SetValue(Matrix.Identity);
 3 effect.Parameters["xView"].SetValue(fpsCam.ViewMatrix);
 4 effect.Parameters["xProjection"].SetValue(fpsCam.ProjectionMatrix);
 5 effect.Parameters["xLightDirection"].SetValue(new Vector3(5.0f,2.0f,-15.0f+variation));
 6 effect.Parameters["xAmbient"].SetValue(2.0f);
 7 effect.Parameters["xConeDirection"].SetValue(new Vector3(0,-1,0));
 8 effect.Parameters["xConeAngle"].SetValue(0.5f);
 9 effect.Parameters["xConeDecay"].SetValue(2.0f);
10 effect.Parameters["xLightStrength"].SetValue(0.7f);
11 effect.Begin();
12 foreach(EffectPass pass in effect.CurrentTechnique.Passes)
13 {
14      pass.Begin();
15      device.VertexDeclaration=myVertexDeclaration;
16      device.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList,vertices,0,6);
17      pass.End();
18 }
19 effect.End();

posted on 2009-08-12 17:20  一盘散沙  阅读(277)  评论(0编辑  收藏  举报

导航