unity shader——体积光

(本文纯属自创,难免有疏漏之处,还望各位大侠不吝指正。)

看了各种体积光的教程,尝试了做了一下,发现了很多BUG,其中有一个教材是添加了顶点位移功能,以节省GPU。但是移动之后整个模型全部散架了,而且其中的平方运算就执行了4次,而且原理作者也讲的很勉强。看完之后心情很糟糕。就自己造一个调节一下情绪。

********************

首先观察现实中的体积光:

1.固定的形状;

2.半透明

3.存在渐变特性,

4.观察距离足够近后完全透明;

**************

两条路:

1是几何着色器;2是多边形加色彩。

unity内部不支持几何着色器,所以这条路不可取了;只能采用多边形+色彩了。

可以使用3dmax建立几个常用的模型:cube、cylinder等等。也可以在脚本中,使用mesh类建立模型。省事的方法肯定还是用3dmax了,哈哈^_^

**************

一、要实现这些特性,先考虑数据结构吧:

    float _FadeOutDistNear;    // 淡出的最近距离,小于该值则透明度为最小,不再变化
    float _FadeOutDistFar;    // 淡出最大距离,大于该值则透明度为最大,不再变化
    float _MaxAlpha;        // 最大透明度
    float _MinAlpha;        // 最小透明度

    float _DampX;            // X轴衰减系数
    float _DampY;            // Y轴衰减系数
    float _DampZ;            // Z轴衰减系数

我添加了注释,不难理解含义的。
二、核心功能部分

首先实现透明度渐变的效果,这个一般都是“手动”控制的,所以有了数据结构中的 _DampX、DampY、DampZ。(数据结构部分应该放在算法设计的过程中,这样看起来才合理。)

这部分我是在物体局部坐标系进行运算的。在顶点转换到世界坐标系前,以物体中心为原点。这样就大大减小了阻力了,,,只要模型形状大致规则,那不需要到世界坐标系中来回运算了。(所以建模的时候一定要小心了,中心尽量在一端面中心)

数学公式也非常简单,我只用了一次方运算,如果想要实现更圆滑的效果,可以多平方几次。代码如下:

 1 float DampParam(float3 pos, float3 len, float minA, float maxA)
 2     {
 3         // 光线的基本衰减函数
 4         float att;
 5         att = 1 - pos.z*len.z;    // 以平方计衰减
 6
 7         att *= (1 - abs(pos.x * len.x * len.x));
 8         att *= (1 - abs(pos.y * len.y * len.y));
 9
10         return lerp( minA, maxA, att);
11     }

然后是根据观察点位置调节顶点透明度了,这个难度更小,直接上代码吧:

1 float DampViewParam(float dist, float nFade, float fFade, float minA, float maxA)
2     {
3         // 由于观察点位置引起的衰减
4         return ( lerp(nFade, fFade, dist) - nFade ) * (maxA-minA) / (fFade - nFade);
5     }

程序的最终运行结果:

原谅我只截这么小的图,哈哈,最终作品出来之前,其他细节不能过多透露。^_^

完整版代码:

  1 Shader "Custom/godRay" {
  2
  3 Properties {
  4     _MainTex ("Base texture", 2D) = "white" {}
  5     _MainColor ("Color", color) = (1,1,1,1)
  6     _FadeOutDistNear ("Near fadeout dist", float) = 3
  7     _FadeOutDistFar ("Far fadeout dist", float) = 10000
  8     _MaxAlpha ("MaxAlpha", range(0, 1)) = 1
  9     _MinAlpha ("MinAlpha", range(0.001, 1)) = 0.01
 10
 11
 12     _DampX ("DampX", range(0, 6) ) = 0.3    // 体积光的衰减系数
 13     _DampY ("DampY", range(0, 6) ) = 0.3    //
 14     _DampZ ("DampZ", float ) = 0.3    //
 15
 16 }
 17
 18
 19 SubShader {
 20     Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Opaque" }
 21
 22     Blend One OneMinusSrcColor
 23     Cull Off Lighting Off ZWrite Off Fog { Color (0,0,0,0) }
 24
 25     LOD 100
 26
 27
 28     CGINCLUDE
 29     #include "UnityCG.cginc"
 30     sampler2D _MainTex;
 31     fixed4 _MainColor;
 32     float _FadeOutDistNear;    // 淡出的最近距离,小于该值则透明度为最小,不再变化
 33     float _FadeOutDistFar;    // 淡出最大距离,大于该值则透明度为最大,不再变化
 34     float _MaxAlpha;        // 最大透明度
 35     float _MinAlpha;        // 最小透明度
 36
 37     float _DampX;            // X轴衰减系数
 38     float _DampY;            // Y轴衰减系数
 39     float _DampZ;            // Z轴衰减系数
 40
 41     struct v2f {
 42         float4    pos    : SV_POSITION;
 43         float2    uv        : TEXCOORD0;
 44         fixed4    color    : TEXCOORD1;
 45     };
 46
 47
 48     float DampParam(float3 pos, float3 len, float minA, float maxA)
 49     {
 50         // 光线的基本衰减函数
 51         float att;
 52         att = 1 - pos.z*len.z;    // 以平方计衰减
 53
 54         att *= (1 - abs(pos.x * len.x * len.x));
 55         att *= (1 - abs(pos.y * len.y * len.y));
 56
 57         return lerp( minA, maxA, att);
 58     }
 59
 60     float DampViewParam(float dist, float nFade, float fFade, float minA, float maxA)
 61     {
 62         // 由于观察点位置引起的衰减
 63         return ( lerp(nFade, fFade, dist) - nFade ) * (maxA-minA) / (fFade - nFade);
 64     }
 65
 66
 67     v2f vert (appdata_full v)
 68     {
 69         v2f o;
 70
 71         // 模型的局部空间
 72         float3 mPos = v.vertex.xyz;
 73
 74         // gl坐标中,摄像机坐标始终是(0,0,0)
 75         // 所以顶点世界坐标的长度就是与摄像机的距离
 76         float3 viewPos    = mul(UNITY_MATRIX_MV,v.vertex).xyz;
 77         float dist        = length(viewPos);
 78
 79         float3 len = float3(_DampX, _DampY, _DampZ);
 80         float att = DampParam(mPos, len, _MinAlpha, _MaxAlpha);
 81
 82         att *= DampViewParam(dist, _FadeOutDistNear, _FadeOutDistFar, _MinAlpha, _MaxAlpha);
 83         o.color.a = att;
 84
 85         o.uv        = v.texcoord.xy;
 86         o.pos    = mul(UNITY_MATRIX_MVP, v.vertex);
 87
 88     //    o.color.rgb    = _MainColor;
 89
 90         return o;
 91
 92     }
 93     ENDCG
 94
 95
 96     Pass {
 97         CGPROGRAM
 98         #pragma vertex vert
 99         #pragma fragment frag
100         #pragma fragmentoption ARB_precision_hint_fastest
101         fixed4 frag (v2f i) : COLOR
102         {
103             fixed4 finalColor;
104             finalColor = tex2D (_MainTex, i.uv)* (i.color.a);
105
106             return finalColor;
107         }
108         ENDCG
109     }
110 }
111 }

最后得比几句:

困死了,睡。

时间: 2024-08-24 19:20:29

unity shader——体积光的相关文章

【Unity Shaders】ShadowGun系列之二——雾和体积光

写在前面 体积光,这个名称是God Rays的中文翻译,感觉不是很形象.God Rays其实是Crepuscular rays在图形学中的说法,而Crepuscular rays的意思是云隙光.曙光.曙暮辉的意思.在现实生活中,它的样子大概是下面这样: 体积光的翻译大概就是由于这种光可见好像有体积似的.这些光一般是由于强烈的阳光从一些缝隙,如云间缝隙.窗户的缝隙中,透到较暗的环境中所造成的.如果要真实模拟体积光,可能需要很复杂的粒子渲染.但这在移动设备上基本是不可能实现的. ShadowGun中

关于unity shader的BUG

(shader这方面的教材.尤其体积光讲的暧昧不清,浑浑昏昏!) 由于将要做的一款作品里面要用到体积光特效,于是对这块知识进行了相应的研究.成果: 1.发现了unity shader的一个BUG: 参照之前所学的DX的知识,将混合状态设置成这样,进行颜色混合的时候,发现无法进行纯色混色(颜色值,相对于贴图而言),以及部分贴图出现无法混合成功的情况.于是顺着这条线一直往下探索.测试,发现了事件的真相: unity的fragment着色器在“采色”结束后,不会按照上面标注的那句blend进行操作,也

【Unity Shader编程】之十四 边缘发光Shader(Rim Shader)的两种实现形态

本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://blog.csdn.net/poem_qianmo/article/details/51764028 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 本文工程使用的Unity3D版本: 5.2.1  这篇文章主要讲解了如何在Unity3D中分别使用Surface Shader和Vertex & Fragment Shader来编写边缘发光Shader. 一.最终实现的效果

[Unity Shader笔记]渲染路径--Forward渲染路径

[Unity Shader笔记]渲染路径--Forward渲染路径 (2014-04-22 20:08:25) 转载▼ 标签: shader unity renderingpath forward 游戏 分类: UnityShader *ForwardBase.ForwardAdd的LightMode只能运行在Came为Forward.DeferredLighting的渲染模式下 *ForwardAdd这个Pass需要和ForwardBase一起使用,否则会被Unity忽视掉 * Forward

Unity3D for VR 学习(9): Unity Shader 光照模型 (illumination model)

关于光照模型 所谓模型,一般是由学术算法发起, 经过大量实际数据验证而成的可靠公式 现在还记得2009年做TD-SCDMA移动通信算法的时候,曾经看过自由空间传播模型(Free space propagation Model),目的为了得出移动信号的传播损耗.当时是基于普通的PC实时运算,非常非常耗时–如北京五环内的传播模型渲染GIS图用了超过20分钟. 光照模型来源有2类: 一类是基于学术论文的算法,如Lambert模型.Phong模型. 另一类基于算法的变种–在实际生产实践中修正得到的模型,

《Unity Shader 与 计算机图形学》第二章

提示:本篇将会非常长~ 本系列文章分为 硬件 编程入门 工程实践 上一篇 主要介绍了GPU的特征工作原理 以及渲染的底层流程 其实对于新架构而言还有所不同 Shader描述了如何渲染物体的信息,包括: Texture Setup.纹理设置 Material Property.材质设置 Render State.渲染状态 Blend Setup.混合设置 Pixel Shader.像素着色 Vertex Shader.定点着色 Render Target Setup 渲染目标设置 Shader并不

Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照

转自冯乐乐的<Unity Shader入门精要> 通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑3种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交:一些光线被物体吸收了,而另一些光线被散射到其他方向. 最后,摄像机吸收了一些光,产生了一张图像. 在光学中,我们使用辐照度来量化光.对于平行光来说,它的辐照度可通过计算在垂直于l的单位面积上单位时间内穿过的能量来得到.在计算光照模型时,我们需要知道一个物体表面的辐照度,而物体表面往往是和l不垂直的,我们可以

Unity Shader 阶段性反思与总结(一)

Unity Shader 阶段性反思与总结(一) 最近在写Shader的时候,总是感觉力不从心,感觉自己已经看了蛮久的书了,也有一定的积累了,但是一想写什么效果,完完全全就是脑袋一团空白.典型的例子就是,我想写边缘光效果的时候,完完全全就是不知道怎么下手这样子. 然后,感觉自己在看书,也没什么提升,每天好像就从书上抄代码一样.....让我很有挫败感. 现在记录一下我在学Shader的时候,读<unity shader 入门精要>这本书的时候感觉困惑.不能理解的几个点.希望有一天我能回来进行回答

【Unity Shader】(七) ------ 复杂的光照(下)

笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题.              [Unity Shader](三)------ 光照模型原理及漫反射和高光反射的实现         [Unity Shader](四)------ 纹理之法线纹理.单张纹理和遮罩纹理的实现              [Unity Shader](五) ------ 透明效果之半透明效果的原理及实现