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 }
最后得比几句:
困死了,睡。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。