• 在场景中添加光线——使用HLSL定义聚光灯


    问题

    前面教程中定义的点光源从一个点发出四面八方的光。你想定义一个聚光灯,它与点光源很很像,但光线只照亮一个圆锥区域,如图6-10。

    image

    图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(); 

    image

  • 相关阅读:
    第八章 多线程编程
    Linked List Cycle II
    Swap Nodes in Pairs
    Container With Most Water
    Best Time to Buy and Sell Stock III
    Best Time to Buy and Sell Stock II
    Linked List Cycle
    4Sum
    3Sum
    Integer to Roman
  • 原文地址:https://www.cnblogs.com/AlexCheng/p/2120095.html
Copyright © 2020-2023  润新知