Unity Fog 原理 源码分析 案例

效果图

简述

  • 背景知识

    • clip空间坐标的范围

      • d3d (near,0), unity remapping to (0,far) 越靠近相机z值越小
      • opengl (near,-far) unity remapping to (0,far) 越靠近相机z越小
      • 所以最终都被映射成(0,far)
  • 原理
    • 通过clip空间的pos.z的值计算雾效的强弱,z越大雾越大,z越小雾越小
    • 雾效因子越小雾越强,雾效因子越大雾越弱
    • clipPos.z和雾效因子成反比,z越大雾效因子越小,雾越大
  • unity_FogParams:(density / sqrt(ln(2)), density / ln(2), –1/(end-start), end/(end-start))
  • 线性雾效举例
    • float unityFogFactor = (coord) * unity_FogParams.z + unity_FogParams.w
    • 代码中的coord即使clipPos.z,当clipPos.z接近1时雾效因子最大,因为unity_FogParams.z是负值
  • 自然对数公式的雾效举例
    • float unityFogFactor = unity_FogParams.y * (coord); unityFogFactor = exp2(-unityFogFactor)
    • z越大,雾效因子越小,雾越大
  • 具体逻辑参见下方源码

使用

struct v2f
{float2 uv : TEXCOORD0;UNITY_FOG_COORDS(1) //声明雾效因子数据float4 vertex : SV_POSITION;float3 worldNormal : NORMAL;
};v2f vert (appdata v)
{v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.uv, _MainTex);o.worldNormal = mul(unity_ObjectToWorld, v.normal);UNITY_TRANSFER_FOG(o,o.vertex);//转换坐标return o;
}UNITY_APPLY_FOG(i.fogCoord, lambertCol);//应用雾效

Unity设置雾效参数的菜单

  • Window/Rendering/Lighting Settings/Fog标签下

Unity 雾效Shader关键源码

  • 声明雾效因子
#define UNITY_FOG_COORDS_PACKED(idx, vectype) vectype fogCoord : TEXCOORD##idx;#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)#define UNITY_FOG_COORDS(idx) UNITY_FOG_COORDS_PACKED(idx, float1)
  • 计算雾效因子
#if defined(FOG_LINEAR)// factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))#define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = (coord) * unity_FogParams.z + unity_FogParams.w
#elif defined(FOG_EXP)// factor = exp(-density*z)#define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = unity_FogParams.y * (coord); unityFogFactor = exp2(-unityFogFactor)
#elif defined(FOG_EXP2)// factor = exp(-(density*z)^2)#define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = unity_FogParams.x * (coord); unityFogFactor = exp2(-unityFogFactor*unityFogFactor)
#else#define UNITY_CALC_FOG_FACTOR_RAW(coord) float unityFogFactor = 0.0
#endif#define UNITY_CALC_FOG_FACTOR(coord) UNITY_CALC_FOG_FACTOR_RAW(UNITY_Z_0_FAR_FROM_CLIPSPACE(coord))#define UNITY_FOG_COORDS_PACKED(idx, vectype) vectype fogCoord : TEXCOORD##idx;#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)#define UNITY_FOG_COORDS(idx) UNITY_FOG_COORDS_PACKED(idx, float1)#if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE)// mobile or SM2.0: calculate fog factor per-vertex#define UNITY_TRANSFER_FOG(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.fogCoord.x = unityFogFactor#define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.tSpace1.y = tangentSign; o.tSpace2.y = unityFogFactor#define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.worldPos.w = unityFogFactor#define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.eyeVec.w = unityFogFactor#else// SM3.0 and PC/console: calculate fog distance per-vertex, and fog factor per-pixel#define UNITY_TRANSFER_FOG(o,outpos) o.fogCoord.x = (outpos).z#define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos) o.tSpace2.y = (outpos).z#define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos) o.worldPos.w = (outpos).z#define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos) o.eyeVec.w = (outpos).z#endif
#else#define UNITY_FOG_COORDS(idx)#define UNITY_TRANSFER_FOG(o,outpos)#define UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,outpos)#define UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,outpos)#define UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o,outpos)
#endif
  • clip空间坐标remapping
#if defined(UNITY_REVERSED_Z)#if UNITY_REVERSED_Z == 1//D3d with reversed Z => z clip range is [near, 0] -> remapping to [0, far]//max is required to protect ourselves from near plane not being correct/meaningfull in case of oblique matrices.#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(((1.0-(coord)/_ProjectionParams.y)*_ProjectionParams.z),0)#else//GL with reversed z => z clip range is [near, -far] -> should remap in theory but dont do it in practice to save some perf (range is close enough)#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) max(-(coord), 0)#endif
#elif UNITY_UV_STARTS_AT_TOP//D3d without reversed z => z clip range is [0, far] -> nothing to do#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord)
#else//Opengl => z clip range is [-near, far] -> should remap in theory but dont do it in practice to save some perf (range is close enough)#define UNITY_Z_0_FAR_FROM_CLIPSPACE(coord) (coord)
#endif
  • 应用雾效
#define UNITY_FOG_LERP_COLOR(col,fogCol,fogFac) col.rgb = lerp((fogCol).rgb, (col).rgb, saturate(fogFac))#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)#if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE)// mobile or SM2.0: fog factor was already calculated per-vertex, so just lerp the color#define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) UNITY_FOG_LERP_COLOR(col,fogCol,(coord).x)#else// SM3.0 and PC/console: calculate fog factor and lerp fog color#define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) UNITY_CALC_FOG_FACTOR((coord).x); UNITY_FOG_LERP_COLOR(col,fogCol,unityFogFactor)#endif#define UNITY_EXTRACT_FOG(name) float _unity_fogCoord = name.fogCoord#define UNITY_EXTRACT_FOG_FROM_TSPACE(name) float _unity_fogCoord = name.tSpace2.y#define UNITY_EXTRACT_FOG_FROM_WORLD_POS(name) float _unity_fogCoord = name.worldPos.w#define UNITY_EXTRACT_FOG_FROM_EYE_VEC(name) float _unity_fogCoord = name.eyeVec.w
#else#define UNITY_APPLY_FOG_COLOR(coord,col,fogCol)#define UNITY_EXTRACT_FOG(name)#define UNITY_EXTRACT_FOG_FROM_TSPACE(name)#define UNITY_EXTRACT_FOG_FROM_WORLD_POS(name)#define UNITY_EXTRACT_FOG_FROM_EYE_VEC(name)
#endif#ifdef UNITY_PASS_FORWARDADD#define UNITY_APPLY_FOG(coord,col) UNITY_APPLY_FOG_COLOR(coord,col,fixed4(0,0,0,0))
#else#define UNITY_APPLY_FOG(coord,col) UNITY_APPLY_FOG_COLOR(coord,col,unity_FogColor)
#endif

使用Lambert光照模型的支持雾效的shader

Shader "DC/Fog/UnityFog"
{Properties{}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag// make fog work#pragma multi_compile_fog#include "UnityCG.cginc"#include "Lighting.cginc"struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f{UNITY_FOG_COORDS(1)float4 vertex : SV_POSITION;float3 worldNormal : NORMAL;};v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.worldNormal = mul(unity_ObjectToWorld, v.normal);UNITY_TRANSFER_FOG(o,o.vertex);return o;}fixed4 frag (v2f i) : SV_Target{fixed4 lambertCol = saturate(dot(i.worldNormal, normalize(_WorldSpaceLightPos0.xyz))) * _LightColor0;// apply fogUNITY_APPLY_FOG(i.fogCoord, lambertCol);return lambertCol;}ENDCG}}
}

Unity Fog 原理 源码分析 案例相关推荐

  1. Anbox源码分析(四)——Anbox渲染原理(源码分析)

    Anbox源码分析(四) 上篇文章我们从源码分析了一下Anbox是怎样一步步的准备了OpenGL ES的渲染环境的,这篇文章,我们继续分析Android的渲染指令是如何到达宿主机进行渲染的. 宿主机端 ...

  2. Anbox源码分析(三)——Anbox渲染原理(源码分析)

    Anbox源码分析(三) 上一篇,我们介绍了Anbox视频渲染的原理,这一篇,我们从源码入手,更深入的理解Anbox与渲染的机制和原理 session manager入口 session manage ...

  3. 阿里面试这样问:Nacos配置中心交互模型是 push 还是 pull ?(原理+源码分析)...

    本文来源:公众号「 程序员内点事」 对于Nacos大家应该都不太陌生,出身阿里名声在外,能做动态服务发现.配置管理,非常好用的一个工具.然而这样的技术用的人越多面试被问的概率也就越大,如果只停留在使用 ...

  4. Runloop底层原理--源码分析

    什么是Runloop? Runloop不仅仅是一个运行循环(do-while循环),也是提供了一个入口函数的对象,消息机制处理模式.运行循环从两种不同类型的源接收事件. 输入源提供异步事件,通常是来自 ...

  5. java类加载机制为什么双亲委派_[五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的...

    Launcher启动类 本文是双亲委派机制的源码分析部分,类加载机制中的双亲委派模型对于jvm的稳定运行是非常重要的不过源码其实比较简单,接下来简单介绍一下我们先从启动类说起有一个Launcher类 ...

  6. Mybatis Interceptor 拦截器原理 源码分析

    Mybatis采用责任链模式,通过动态代理组织多个拦截器(插件),通过这些拦截器可以改变Mybatis的默认行为(诸如SQL重写之类的),由于插件会深入到Mybatis的核心,因此在编写自己的插件前最 ...

  7. 滑动平均模型原理+源码分析

    滑动平均原理部分: 注释:原理部分参考http://www.mbalib.com/,不过这个讲解的太菜了,评论清一色都是看不懂,大家简单看一下原理,例子别看了,越看越糊涂~~ 一.简单移动平均法 简单 ...

  8. 【多线程】LockSupport 使用 原理 源码 分析

    1.概述 1. LockSupport类介绍 LockSupport用来创建锁和其他同步类的基本线程阻塞原语.简而言之,当调用LockSupport.park时,表示当前线程将会等待,直至获得许可,当 ...

  9. 从vuex源码分析module与namespaced

    使用vue已经有半年有余, 在各种正式非正式项目中用过, 开始专注于业务比较多, 用到现在也遇见不少因为理解不深导致的问题. 有问题就有找原因的勇气, 所以带着问题搞一波. 带着问题看源码 所以来整理 ...

最新文章

  1. 药师帮完成1.33亿美元D轮融资,投资方为老虎环球基金、H Capital和DCM
  2. 软件版本命名规范(转载)
  3. 机器学习的发展和硬件发展的关系
  4. 《汇编语言》-王爽-实验7
  5. 数据仓库中的SQL性能优化 - Hive篇
  6. 软考信息系统项目管理师_信息系统安全管理---软考高级之信息系统项目管理师026
  7. ChEMBL数据库的官方python工具包
  8. 将windbg设置为默认调试器命令
  9. L1-009 N个数求和 (20 分)—团体程序设计天梯赛
  10. 《中国科学》中文论文模板使用CCTTEX编译
  11. android webview权限申请_android中使用WebView请求网页
  12. win10鼠标停留任务栏不显示预览小窗口
  13. Firefox 火狐下自动刷新的插件 ReloadEvery
  14. Opengl glm配置出错
  15. 湘西纪行 芷江 芋头侗寨 通道 黔阳 高椅村
  16. oracle中对于TableSpace理解
  17. 程序员的吵架,跟女朋友能讲理吗?
  18. R语言作业一:矩估计、极大似然估计、拟合、对数正态分布、泊松分布、负二项分布
  19. JS生成gif动态图下载
  20. google AdSense广告不显示的原因

热门文章

  1. 创业十诫之一:过早迈出创业第一步
  2. 定积分之积分上限函数分段问题
  3. 数据同步工具—DataX 初识
  4. 基于单片机的寻迹小车——硬件介绍
  5. Mac Mini2018 开箱(视频)全球首映!Kindle 开箱一并奉上(文字)
  6. 方便ppt制作--iSlide插件
  7. vi实践——vi编辑器使用实践小记
  8. 有源带通滤波器电路频率案例
  9. pycharm远程连接服务器,解释器已安装所需的包,导入包均红色下划线
  10. PS2手柄代码移植-合泰平台