{web
}
效果以下:
我最开始的想法是,先提早作两张分形噪声(每张都叠了8次柏林噪声)纹理,而后经过_Time.x控制采样,根据采样结果混合颜色插值,而后效果通常,个人颜色配置的很差,感性计算也不是很到位,而后在shadertoy上看到了
https://www.shadertoy.com/view/4tdSWr
第一反应是amazing,而后再看看本身苟的效果然是惨不忍睹。。。
关于原理,固然他也用了噪声,不过是单形噪声(Simplex噪声),是柏林噪声的改进版,计算复杂度低,越高维度优点越明显,天空的颜色是一个过渡色,而后云的颜色和云彩边缘,云的形状都是用单形噪声得来的,仔细想一想套路同样,而后效果差距巨大
shadertoy上都是用GLSL写的,和unity的shaderlab有些区别,我参考了https://www.jianshu.com/p/0dd606730177
按照他的套路改了一下,先预约义一些函数app
#define vec2 float2 #define vec3 float3 #define vec4 float4 #define mat2 float2x2 #define mat3 float3x3 #define mat4 float4x4 #define iGlobalTime _Time.y #define mod fmod #define mix lerp #define fract frac #define texture2D tex2D #define iResolution _ScreenParams #define gl_FragCoord ((_iParam.scrPos.xy/_iParam.scrPos.w) * _ScreenParams.xy)
这些不是所有,根据状况增减
,把矩阵*法改成mul
好比svg
vec2 n; mat2 m; n*=m; //改成 n = mul(m , n);
还有函数
const float speed = 0.03; const float clouddark = 0.5; const float cloudlight = 0.3; //这些都要改成 #define speed 0.03 #define clouddark 0.5 #define cloudlight 0.3
其实转换仍是比较容易的,不用从头至尾翻译一遍。
我转换完的代码以下:ui
Shader "Shadertoy/sky1" { Properties{ _MainTex("_MainTex",2D)="white"{} } CGINCLUDE #include "UnityCG.cginc" #pragma target 3.0 #define vec2 float2 #define vec3 float3 #define vec4 float4 #define mat2 float2x2 #define mat3 float3x3 #define mat4 float4x4 #define iGlobalTime _Time.y #define mod fmod #define mix lerp #define fract frac #define texture2D tex2D #define iResolution _ScreenParams #define gl_FragCoord ((_iParam.scrPos.xy/_iParam.scrPos.w) * _ScreenParams.xy) #define iTime _Time.y #define PI2 6.28318530718 #define pi 3.14159265358979 #define halfpi (pi * 0.5) #define oneoverpi (1.0 / pi) #define cloudscale 1.1 #define speed 0.03 #define clouddark 0.5 #define cloudlight 0.3 #define cloudcover 0.2 #define cloudalpha 8.0 #define skytint 0.5 #define skycolour1 float3(0.2, 0.4, 0.6) #define skycolour2 float3(0.4, 0.7, 1.0) #define m float2x2( 1.6, 1.2, -1.2, 1.6 ) //_time.x sampler2D _MainTex; struct v2f { float4 pos : SV_POSITION; float4 scrPos : TEXCOORD0; float4 uv:TEXCOORD1; }; v2f vert(appdata_base v) { v2f o; o.pos = UnityObjectToClipPos (v.vertex); o.scrPos = ComputeScreenPos(o.pos); o.uv.xy=v.texcoord.xy; return o; } vec4 main(vec2 fragCoord); fixed4 frag(v2f _iParam) : COLOR0 { vec2 fragCoord =gl_FragCoord;//_iParam.uv.xy*_ScreenParams.xy;// return main(fragCoord); } vec2 hash( vec2 p ) { p = vec2(dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3))); return -1.0 + 2.0*fract(sin(p)*43758.5453123); } float noise( in vec2 p ) { float K1 = 0.366025404; // (sqrt(3)-1)/2; float K2 = 0.211324865; // (3-sqrt(3))/6; vec2 i = floor(p + (p.x+p.y)*K1); vec2 a = p - i + (i.x+i.y)*K2; vec2 o = (a.x>a.y) ? vec2(1.0,0.0) : vec2(0.0,1.0); //vec2 of = 0.5 + 0.5*vec2(sign(a.x-a.y), sign(a.y-a.x)); vec2 b = a - o + K2; vec2 c = a - 1.0 + 2.0*K2; vec3 h = max(0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 ); vec3 n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0))); return dot(n, vec3(70.0,70,70)); // } float fbm(vec2 n) { float total = 0.0, amplitude = 0.1; for (int i = 0; i < 7; i++) { total += noise(n) * amplitude; n = mul(m , n);// amplitude *= 0.4; } return total; } // ----------------------------------------------- float4 main(vec2 fragCoord ) { vec2 p = fragCoord.xy / iResolution.xy; vec2 uv = p*vec2(iResolution.x/iResolution.y,1.0); float time = iTime * speed; float q = fbm(uv * cloudscale * 0.5); //ridged noise shape float r = 0.0; uv *= cloudscale; uv -= q - time; float weight = 0.8; for (int i=0; i<8; i++){ r += abs(weight*noise( uv )); uv = mul(m,uv) + time;// weight *= 0.7; } //noise shape float f = 0.0; uv = p*vec2(iResolution.x/iResolution.y,1.0); uv *= cloudscale; uv -= q - time; weight = 0.7; for (int j=0; j<8; j++){ f += weight*noise( uv ); uv = mul(m,uv) + time;// weight *= 0.6; } f *= r + f; //noise colour float c = 0.0; time = iTime * speed * 2.0; uv = p*vec2(iResolution.x/iResolution.y,1.0); uv *= cloudscale*2.0; uv -= q - time; weight = 0.4; for (int k=0; k<7; k++){ c += weight*noise( uv ); uv = mul(m,uv) + time; weight *= 0.6; } //noise ridge colour float c1 = 0.0; time = iTime * speed * 3.0; uv = p*vec2(iResolution.x/iResolution.y,1.0); uv *= cloudscale*3.0; uv -= q - time; weight = 0.4; for (int l=0; l<7; l++){ c1 += abs(weight*noise( uv )); uv = mul(m,uv) + time; weight *= 0.6; } c += c1; vec3 skycolour = mix(skycolour2, skycolour1, p.y); vec3 cloudcolour = vec3(1.1, 1.1, 0.9) * clamp((clouddark + cloudlight*c), 0.0, 1.0); f = cloudcover + cloudalpha*f*r; vec3 result = mix(skycolour, clamp(skytint * skycolour + cloudcolour, 0.0, 1.0), clamp(f + c, 0.0, 1.0)); return vec4( result, 1.0 ); } ENDCG SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest ENDCG } } FallBack Off }
如今把shader拖到着色器中就能够直接用了吗?固然不行,它的一切相关计算都是根据屏幕位置得来的,就会出现下面的现象
修改的方法很简单,咱们让它根据自身的uv坐标进行计算就能够了
关键修改以下:spa
vec2 fragCoord =_iParam.uv.xy*_ScreenParams.xy;
如今:
Ok,下一次写多种体积光shader并添加一些场景物品,不过得等我先考完3个科目,交完结课论文以后了。。。.net