建设银行网站理财产品为何不让买,苏州公司网站建设,宝安中心医院是三甲医院吗,广东手机网站建设报价1、Shader 开发中常用的光源属性
Unity当中一共支持四种光源类型#xff1a; 平行光#xff08;Directional#xff09;点光源#xff08;Point#xff09;聚光灯#xff08;Spot#xff09;面光源#xff08;Area#xff09;— 面光源仅在烘焙时有用
不管光源类型到…1、Shader 开发中常用的光源属性
Unity当中一共支持四种光源类型 平行光Directional点光源Point聚光灯Spot面光源Area— 面光源仅在烘焙时有用
不管光源类型到底是什么我们在Shader开发当中经常会使用到的光源相关属性有 位置、方向、颜色、强度、衰减 也就是说我们在Shader中处理光照效果时经常会用到这些光的属性参与到计算当中
2、对比平行光、点光源、聚光灯
2.1 平行光
充当角色太阳 照射范围无限制 特点
它不存在固定的位置它的重要属性只有方向可以通过Transform的Rotation属性来改变方向它到场景中所有点的方向都是一样的由于它没有位置因此它没有衰减的概念光的强度不会随着距离而发生变化
2.2 点光源
充当角色灯泡、烛光 等 照射范围有限 特点
它的光是由一个点发出的向四面八方延伸的光它的范围由参数Range来决定它的位置由Transform中的Position来决定它存在衰减随着物体离点光源距离决定衰减强弱
2.3 聚光灯
充当角色探照灯、手电筒 等 照射范围有限 特点
它的光范围由空间中的一块锥形区域定义它的范围由参数Range和Spot Angle 共同决定它的位置由Transform中的Position来决定它存在衰减随着物体离聚光灯距离决定衰减强弱。
但是它相对点光源衰减计算公式更复杂因为需要点是否在锥形范围内
3、判断光源类型
Unity中提供了三个重要的宏分别是
_DIRECTIONAL_LIGHT - 平行光_POINT_LIGHT - 点光源_SPOT_LIGHT - 聚光灯
#if defined(_DIRECTIONAL_LIGHT)平行光逻辑
#elif defined (_POINT_LIGHT)点光源逻辑
#elif defined (_SPOT_LIGHT)聚光灯逻辑
#else其他逻辑
#endif
4、光照衰减
光照衰减通常指的是在渲染过程中考虑光线在空间中传播时的减弱效应比如任何光源的光照亮度会随着物体离光源的距离增加而迅速衰减。一般常见的光照衰减计算方式有
线性衰减光强度与距离成线性关系。即光照衰减与光源到被照射表面的距离成正比。平方衰减光强度与距离的平方成反比。这种模型更符合现实世界中光照的特性因为光在空间中的传播过程中通常会遵循平方衰减规律。
4.1 Unity中的光照衰减
Unity中为了提升性能我们一般不会直接通过数学公式计算光照衰减而是使用一张纹理作为查找表LUT, lookup table 在片元着色器中计算逐像素光照的衰减
Unity Shader中有一个内置的纹理类型的变量 _LightTexture0该纹理中存储了衰减值相关的数据Unity 内部预先就计算好了相关数据 并存入到该纹理中避免重复计算提升性能表现 其中它的对角线上的纹理颜色值表明了光源空间中不同位置的点对应的衰减值纹理中的对角线起点(0, 0) 位置表示和光源重合的点的衰减值终点1,1) 位置表示在光源空间中离光源距离最远的点的衰减值
一般我们直接从 _LightTexture0 中进行纹理采样后利用其中的 UNITY_ATTEN_CHANNEL 宏来得到衰减值所在的分量
tex2D(_LightTexture0, 对应纹理uv坐标).UNITY_ATTEN_CHANNEL
注意如果光源存在cookie也就是灯光遮罩那么衰减查找纹理便是 _LightTextureB0
4.2 光源空间变换矩阵
Unity Shader中 内置的 光源空间变换矩阵是用于将世界空间下的位置转换到光源空间下光源位置为原点
老版本_LightMatrix0新版本unity_WorldToLight
由于我们需要从 _LightTexture0 光照纹理中取出对应的衰减数据因此我们需要将顶点位置从世界空间中转换到光源空间中然后再来从其中取得衰减数据我们可以通过矩阵运算将世界空间下的点转换到光源空间下
mul(unity_WorldToLight, float4(worldPos, 1));
4.3 点光源的衰减计算
注意一般点光源不会为其添加cookie光照遮罩一般想要使用光照遮罩都会在聚光灯中使用
步骤
1将顶点从世界空间转换到光源空间
float3 lightCoord mul(unity_WorldToLight, float4(worldPos, 1)).xyz;
lightCoord 是光源坐标系下顶点根据光源的范围range规范化后的坐标相当于是一个模长为0~1之间的向量
2利用该光源空间下的坐标来计算离光源的距离并利用距离参数从光源纹理中采样
fixed atten tex2D(_LightTexture0, dot(lightCoord,lightCoord).xx).UNITY_ATTEN_CHANNEL;
dot(LightCoord, LightCoord).xx 中dot(LightCoord, LightCoord) 是为了通过点乘得到结果 x² y² z² 离光源距离 distance² xx是一种特殊写法目的是构建一个 float2 代表uv坐标这里的 uv坐标 相当于是(distance², distance²)用distance²做uv坐标而不是distance
为了避免开平方带来性能消耗采用这种平方衰减更符合现实世界中光照的特性
因为人眼对亮部不敏感而对暗部敏感这样我们就可以将 衰减值的精度 集中在比较远的地方 distance是0.5时distance2是0.25这样LUT查找表中大部分值都会留给比较远的部分
4.4 聚光灯衰减计算
灯光组件中有一个Cookie参数是用来关联光照遮罩图片的对于平行光和点光源默认是不会提供任何光照遮罩信息的但是对于聚光灯来说Unity会默认为它提供一个Cookie光照遮罩主要是用于模拟聚光灯的区域性而此时光照纹理中
_LightTexture0 存储的是Cookie纹理信息_LightTextureB0 存储的是光照纹理信息里面包含衰减值
因此获取聚光灯衰减值时需要从_LightTextureB0中进行采样获取遮罩范围相关数据时需要从_LightTexture0中进行采样
1将顶点从世界空间转换到光源空间 float4 lightCoord mul(unity_WorldToLight, float4(i.worldPos, 1));
注意这里我们转换后和点光源不同的是点光源只会获取其中的xyz而聚光灯会获取其中的xyzw这是因为在聚光灯光源空间下的w值有特殊含义会参与后续的计算
2利用光源空间下的坐标信息 我们会通过3个步骤去获取聚光灯的衰减信息
fixed atten (lightCoord.z 0) * //第一步tex2D(_LightTexture0, lightCoord.xy / lightCoord.w 0.5).w * //第二步tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL; //第三步
我们首先分析和点光源相同的部分——第三步
tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;
这一步的规则和点光源规则一致直接根据距离光源原点距离的平方从光照纹理中获取衰减值 需要注意的是
聚光灯的光照衰减纹理为_LightTextureB0dot函数只会计算xyzw不会计算
接着我们来分析用于进行范围判断的部分——第一、二步
第一步(lightCoord.z 0) CG语法中没有显示的bool类型一般情况下 0 表示false1表示true也就是说lightCoord.z 0的返回值条件满足时为1条件不满足为0 这里的z代表的其实是 目标点 相对于 聚光灯照射面 距离如果 lightCoord.z 0 证明在聚光灯照射方向的背面就不应该受到聚光灯的影响 也就是说这一步的主要作用是用来决定顶点是否受到聚光灯光照的影响
第二步tex2D(_LightTexture0, lightCoord.xy / lightCoord.w 0.5).w 我们以前在进行纹理采样时都会进行一个 先缩放 后 平移 的操作比如
uv v.texcoord.xy * _MainTex_ST.xy _MainTex_ST.zw;
而第二步中的 lightCoord.xy / lightCoord.w 0.5 其实也是在做这样的一个操作这样做的主要目的是因为我们需要把uv坐标映射到0~1的范围内再从纹理中采样lightCoord.xy / lightCoord.w 进行缩放后 x, y的取值范围是-0.5~0.5之间再加上0.5后x,y的取值范围就是0~1之间便可以进行正确的纹理采样了而 lightCoord.xy / lightCoord.w 是因为聚光灯有很多横截面我们需要把各横截面映射到最大的面上进行采样
总结一下看似复杂的聚光灯光照衰减计算方式其实就是由 “遮罩衰减” 和 距离衰减 共同决定的
第一步判断是否能有机会照到光 看得到为1看不到为0fixed atten (lightCoord.z 0) 第二步缩放平移映射到遮罩纹理采样 根据遮罩纹理的信息决定衰减叠加tex2D(_LightTexture0, lightCoord.xy / lightCoord.w 0.5).w *第三步从光照衰减纹理中取出按距离得到的衰减值tex2D(_LightTextureB0,dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;