shader学习之路(1)- half lambert

本文介绍了Half Lambert光照模型,一种提高物体在背光时亮度的算法,常见于游戏开发。通过Unity3D自定义surface shader实现,详细讲解了关键代码段和效果对比,帮助理解其工作原理。
在学习这个shader之前先提个常用概念,即光照模型,LightModel(光照模型)即是对于物体怎么对打在其上的光做出视觉反应的数学模型,意即表达物体对光反应产生的视觉效果与入射光、物体表面属性等数值相关联的数学表达。
大致了解了光照模型的概念,接下来介绍下今天的主角,Half Lambert模型,该模型是Valve在开发经典游戏《Half-Life(半衰期)》(半条命这个译名真是后无古人的误翻啊……)是发明的,在以前的游戏中,一旦模型背对着光源,模型表面的亮度会立刻降低,使得整个模型显得平面化,毕竟游戏世界并非像现实中有各种漫散射光能照亮背光的一面,所以half-lambert算法提高了物体在背对光源时的亮度,由于其并非根据真实物理推算出来的结果,而仅仅是一种视觉感受的提升,所以其实现方式并不复杂,很多shader入门书籍都介绍过这种算法,不必担心完全看不懂。

未启用/启用half-lambert算法(右侧为启用)
现在我们来看看怎么实现这个算法,首先因为vs对shader关键字高亮支持并不太好(联网工具包中的shader高亮插件其实还行),所以可以用引擎自带的mono dev或者sublime text来编写Cg文件,这个看大家个人喜好了,有空我会介绍下vs和sublime text对shader关键字高亮的设置。
打开unity3d,在project栏中的Assets下建立Materials Shader两个文件夹(良好的资源管理是开发工程的必要前提),在shader中创建一个surface shader并将之命名为halfLambert。

打开shader文件,可以看到默认的属性栏Properties,这下面的变量不仅要在下面的代码中使用,同时也能在引擎的inspector中进行调整。

现在我们将其修改为如下属性:
<think>好的,我需要解决用户的问题:在Unity 3D Shader中将数值从0-10范围转换到0-7。首先,我得回忆一下数值映射的基本方法。一般来说,线性映射可以通过缩放和平移实现。例如,如果原始范围是[a, b],目标范围是[c, d],公式应该是:c + (value - a) * (d - c)/(b - a)。这里a=0,b=10,c=0,d=7,所以公式应该是value * (7/10)。不过需要注意在Shader中如何处理浮点数运算,以及是否需要考虑精度问题。 然后,考虑到用户提到的Shader代码中的引用部分,例如法线和切线空间的转换,可能需要将这种映射应用到特定的通道或者纹理中。在Shader中,通常使用乘法操作即可完成缩放。例如,将输入值乘以0.7,就能将0-10映射到0-7。但是用户需要确保输入值确实在0-10范围内,否则结果会超出预期。 另外,用户可能希望保留原始数值的比例关系,所以线性映射是最直接的办法。如果输入值可能超出0-10,可能需要使用clamp函数来限制范围,但用户的问题中并没有提到需要处理超出范围的情况,所以可能不需要。 接下来,我需要参考用户提供的引用内容。引用[1]中的代码展示了如何在顶点着色器中处理法线和切线,这里涉及到坐标转换,可能与当前问题无关。引用[2]提到了Unity的官方文档,建议用户查阅相关手册或API,确保方法符合Unity的最佳实践。 可能的实现方式是在Shader中使用简单的乘法,例如: float scaledValue = originalValue * 0.7; 或者在代码块中更详细地展示如何应用到具体的Shader属性上。同时,需要考虑是否需要使用HLSL或者CG语言中的语法,确保语法正确。 用户可能还想知道是否有其他方法,比如使用材质参数来控制缩放比例,或者结合其他Shader节点在Shader Graph中实现。不过问题可能更关注代码层面的解决方案。 最后,生成相关问题需要考虑用户可能遇到的后续问题,比如如何处理超出范围的值,或者如何反向映射,以及性能优化等。</think>在Unity Shader中实现数值范围映射可以通过线性插值公式实现。根据线性映射公式$y = kx + b$,其中$k = (目标上限 - 目标下限)/(原始上限 - 原始下限)$,这里需要将0-10映射到0-7: $$ y = \frac{7 - 0}{10 - 0} \times x = 0.7x $$ 具体实现方式根据数值来源有所不同: **1. 顶点着色器/片元着色器直接计算** ```glsl // 在Shader代码中直接乘以0.7 float scaledValue = originalValue * 0.7; ``` **2. 材质参数控制映射比例** ```glsl // 在Properties中声明参数 _RangeScale("Scale Factor", Range(0,1)) = 0.7 // 片元着色器中使用 float scaledValue = originalValue * _RangeScale; ``` **3. 完整示例(基于表面着色器)** ```glsl Shader "Custom/RangeMapper" { Properties { _OriginalValue ("Original Value", Range(0,10)) = 5 } SubShader { Tags { "RenderType"="Opaque" } CGPROGRAM #pragma surface surf Lambert struct Input { float2 uv_MainTex; }; float _OriginalValue; void surf (Input IN, inout SurfaceOutput o) { float scaledValue = _OriginalValue * 0.7; // 核心映射 o.Albedo = fixed3(scaledValue, scaledValue, scaledValue); } ENDCG } } ``` **注意事项**: - 如果原始值可能超出0-10范围,建议使用`clamp(originalValue, 0, 10)`限制输入范围 -Shader中进行浮点运算时,注意使用`half`或`fixed`类型优化性能[^2] - 通过Unity的`UnityObjectToWorldNormal`等内置函数进行坐标转换时,要确保输入值在正确空间[^1]
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值