在场景中添加光线——使用HLSL定义聚光灯
2011-02-14 14:50
357 查看
问题 前面教程中定义的点光源从一个点发出四面八方的光。你想定义一个聚光灯,它与点光源很很像,但光线只照亮一个圆锥区域,如图6-10。
图6-10 定义一个聚光灯的变量
解决方案 在pixel shader中,判断当前像素是否在光照圆锥中,这可以通过将光线方向和圆锥方向进行点乘做到。
工作原理 开始的代码与前面的教程中的是一样的。因为聚光灯比点光源需要设置的东西更多,你需要将下列XNA-to-HLSL变量添加到. fx文件中:
第一个变量让你可以增加/减少光照强度。这个变量对其他类型的光也是很有用的,当场景中有多个光源时它也是必须的(见教程6-10)。然后定义光锥的中心线方向、光锥宽度。最后定义光照的衰减。
除此之外,你还要扩展pixel shader。基本上与逐像素点光源中(见教程6-7)做的一样,只是多了一个检查像素是否在光锥中的步骤:
归一化法线和光线方向之后,你需要检测当前像素是否在光锥之内。这可以检测两个方向间的夹角做到:
当前像素到光源的方向
光锥的中心线的方向
第一个方向就是lightDirection,第二个方向由xConeDirection变量定义。只有这两个方向的夹角小于某个临界值,像素才会被照亮。
检测的一个快速方法是计算这两个方向的点乘。结果接近于1表示两者的夹角很小,结果越小表示夹角越大。
要判断角度是否太大,你要检测点乘结果是否小于某个临界值,这个临界值存储在ConeAngle变量中。如果像素在光锥中,就计算光照因子。要在接近光锥边缘的地方减弱光照,你要计算变量coneDot的xConeDecay次幂。结果是,对那些远离光锥中心线方向的像素来说,当coneDot变量小于等于1时,幂的结果会变得更小(见图6-11的右图)。
光锥之外的像素光照值为0,光线对这些像素没有影响。
代码
完整的pixel shader代码前面已经有了。
在XNA代码的Draw方法中,开启effect,设置参数并绘制场景:
图6-10 定义一个聚光灯的变量
解决方案 在pixel shader中,判断当前像素是否在光照圆锥中,这可以通过将光线方向和圆锥方向进行点乘做到。
工作原理 开始的代码与前面的教程中的是一样的。因为聚光灯比点光源需要设置的东西更多,你需要将下列XNA-to-HLSL变量添加到. fx文件中:
float xLightStrength; float3 xConeDirection; float xConeAngle; float xConeDecay;
第一个变量让你可以增加/减少光照强度。这个变量对其他类型的光也是很有用的,当场景中有多个光源时它也是必须的(见教程6-10)。然后定义光锥的中心线方向、光锥宽度。最后定义光照的衰减。
除此之外,你还要扩展pixel shader。基本上与逐像素点光源中(见教程6-7)做的一样,只是多了一个检查像素是否在光锥中的步骤:
SLPixelToFrame SLPixelShader(SLVertexToPixel PSIn) : COLOR0 { SLPixelToFrame Output = (SLPixelToFrame)0; float4 baseColor = float4(0,0,1,1); float3 normal = normalize(PSIn.Normal); float3 lightDirection = normalize(PSIn.LightDirection); float coneDot = dot(lightDirection, normalize(xConeDirection)); float shading = 0; if (coneDot > xConeAngle) { float coneAttenuation = pow(coneDot, xConeDecay); shading = dot(normal, -lightDirection); shading *= xLightStrength; shading *= coneAttenuation; } Output.Color = baseColor*(shading+xAmbient); return Output; }
归一化法线和光线方向之后,你需要检测当前像素是否在光锥之内。这可以检测两个方向间的夹角做到:
当前像素到光源的方向
光锥的中心线的方向
第一个方向就是lightDirection,第二个方向由xConeDirection变量定义。只有这两个方向的夹角小于某个临界值,像素才会被照亮。
检测的一个快速方法是计算这两个方向的点乘。结果接近于1表示两者的夹角很小,结果越小表示夹角越大。
要判断角度是否太大,你要检测点乘结果是否小于某个临界值,这个临界值存储在ConeAngle变量中。如果像素在光锥中,就计算光照因子。要在接近光锥边缘的地方减弱光照,你要计算变量coneDot的xConeDecay次幂。结果是,对那些远离光锥中心线方向的像素来说,当coneDot变量小于等于1时,幂的结果会变得更小(见图6-11的右图)。
光锥之外的像素光照值为0,光线对这些像素没有影响。
代码
完整的pixel shader代码前面已经有了。
在XNA代码的Draw方法中,开启effect,设置参数并绘制场景:
effect.CurrentTechnique = effect.Techniques["SpotLight"]; effect.Parameters["xWorld"].SetValue(Matrix.Identity); effect.Parameters["xView"].SetValue(fpsCam.ViewMatrix); effect.Parameters["xProjection"].SetValue(fpsCam.ProjectionMatrix); effect.Parameters["xAmbient"].SetValue(0.2f); effect.Parameters["xLightPosition"].SetValue(new Vector3(5.0f, 2.0f, -15.0f+variation)); effect.Parameters["xConeDirection"].SetValue(new Vector3(0,-1,0)); effect.Parameters["xConeAngle"].SetValue(0.5f); effect.Parameters["xConeDecay"].SetValue(2.0f); effect.Parameters["xLightStrength"].SetValue(0.7f); effect.Begin(); foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Begin(); device.VertexDeclaration = myVertexDeclaration; device.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleStrip,vertices, 0, 6); pass.End(); } effect.End();
相关文章推荐
- 在场景中添加光线——使用HLSL定义点光源
- 在场景中添加光线——定义法线和使用BasicEffect
- 在场景中添加光线——添加HLSL逐像素光照
- 在场景中添加光线——添加HLSL镜面高光
- 在场景中添加光线——使用Deferred Shading在场景中添加多光源
- 在场景中添加光线——添加HLSL Vertex Shading
- 在VS.NET的"添加新选项"对话框中使用定义的代码生成器模板
- Java的幽灵引用定义与使用场景
- 提供3D虚拟内容与场景套件 使用SceneKit为您的AR体验添加逼真的三维对象
- ios frame、bound和center定义及使用场景总结
- NGUI使用教程(2) 使用NGUI创建2D场景并且添加标签和按钮
- Block的基本使用、typedef给Block定义别名、Block的应用场景、Block的注意事项
- 【unity编辑器拓展】使用脚本添加Prefab到场景中
- Blockd的使用(定义,作用,typedef,使用场景,注意事项)
- 使用Scenes(场景)和Transitions(转场)为视图添加动画效果
- LINQ entityset 不包含GetEnumerator的定义,在MVC中使用entity framework(EF)出现“必须添加对程序集“System.Data.Entity”解决方法
- Xcode7如何添加PCH文件以及解决添加后定义的宏使用不了的问题
- 使用白鹭引擎对场景添加删除和替换的封装
- tookit2D使用6——给场景添加音乐
- 11_5_3给people添加GetOldest()方法,使用上面定义的重载运算符,返回一个Age最大的对象数组