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

本文介绍如何在像素着色器中实现聚光灯效果,包括定义光照强度、光锥方向和角度等变量,并通过点乘判断像素是否位于光锥内。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题

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

转载于:https://www.cnblogs.com/AlexCheng/archive/2011/02/14/2120095.html

1. 用户与身体信息管理模块 用户信息管理: 注册登录:支持手机号 / 邮箱注册,密码加密存储,提供第三方快捷登录(模拟) 个人资料:记录基本信息(姓名、年龄、性别、身高、体重、职业) 健康目标:用户设置目标(如 “减重 5kg”“增肌”“维持健康”)及期望周期 身体状态跟踪: 体重记录:定期录入体重数据,生成体重变化曲线(折线图) 身体指标:记录 BMI(自动计算)、体脂率(可选)、基础代谢率(根据身高体重估算) 健康状况:用户可填特殊情况(如糖尿病、过敏食物、素食偏好),系统据此调整推荐 2. 膳食记录与食物数据库模块 食物数据库: 基础信息:包含常见食物(如米饭、鸡蛋、牛肉)的名称、类别(主食 / 肉类 / 蔬菜等)、每份重量 营养成分:记录每 100g 食物的热量(kcal)、蛋白质、脂肪、碳水化合物、维生素、矿物质含量 数据库维护:管理员可添加新食物、更新营养数据,支持按名称 / 类别检索 膳食记录功能: 快速记录:用户选择食物、输入食用量(克 / 份),系统自动计算摄入的营养成分 餐次分类:按早餐 / 午餐 / 晚餐 / 加餐分类记录,支持上传餐食照片(可选) 批量操作:提供常见套餐模板(如 “三明治 + 牛奶”),一键添加到记录 历史记录:按日期查看过往膳食记录,支持编辑 / 删除错误记录 3. 营养分析模块 每日营养摄入分析: 核心指标计算:统计当日摄入的总热量、蛋白质 / 脂肪 / 碳水化合物占比(按每日推荐量对比) 微量营养素分析:检查维生素(如维生素 C、钙、铁)的摄入是否达标 平衡评估:生成 “营养平衡度” 评分(0-100 分),指出摄入过剩或不足的营养素 趋势分析: 周 / 月营养趋势:用折线图展示近 7 天 / 30 天的热量、三大营养素摄入变化 对比分析:将实际摄入与推荐量对比(如 “蛋白质摄入仅达到推荐量的 70%”) 目标达成率:针对健
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值