Unity动态天空shader实现

{

目录
  • 人物移动+相机跟随脚本修改
  • Gpuinstance实现大面积草地
  • 风吹麦浪+人物影响
  • 后处理动态天空实现
  • 动态天空实现
  • 体积光实现的三种方法

}
效果如下:

我最开始的想法是,先提前做两张分形噪声(每张都叠了8次柏林噪声)纹理,然后通过_Time.x控制采样,根据采样结果混合颜色插值,然后效果一般,我的颜色配置的不好,感性计算也不是很到位,然后在shadertoy上看到了
https://www.shadertoy.com/view/4tdSWr
第一反应是amazing,然后再看看自己苟的效果真是惨不忍睹。。。
关于原理,当然他也用了噪声,不过是单形噪声(Simplex噪声),是柏林噪声的改进版,计算复杂度低,越高维度优势越明显,天空的颜色是一个过渡色,然后云的颜色和云彩边缘,云的形状都是用单形噪声得来的,仔细想想套路一样,然后效果差距巨大
shadertoy上都是用GLSL写的,和unity的shaderlab有些区别,我参考了https://www.jianshu.com/p/0dd606730177
按照他的套路改了一下,先预定义一些函数

	#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
比如

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

其实转换还是比较容易的,不用从头到尾翻译一遍。
我转换完的代码如下:

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坐标进行计算就可以了
关键修改如下:

        vec2 fragCoord =_iParam.uv.xy*_ScreenParams.xy;

现在:

Ok,下一次写多种体积光shader并添加一些场景物品,不过得等我先考完3个科目,交完结课论文之后了。。。

你可能感兴趣的:(Unity)