[Godot] 使用柏林噪声制作动态水波 shader

543 阅读1分钟

这是一个用于 canvas_item 的 shader

掉san

图片叠加得像猪肉绦虫 莫得办法,因为我的柏林噪声函数是抄来的:

Dynamic noise shader on Mobile Devices (Help!) - Unity Forum

我只是想知道噪声图采样出来的纹路怎么动态扭曲,而不是简单的位移 但是一时半会我又看不懂柏林噪声的函数 于是我就把 +0.5*sin(TIME) 放在各个地方看效果 最后在 SimplexPerlin2D 的梯度计算这里有明显效果,我就这么用了hhh

遗憾就在于三角函数是有周期的,最好的方法应该是找一个一维的柏林噪声看看 但是找不到好的,就这样了

虽然我的效果图很丑,但是柏林噪声生成函数可以复用

最好的效果应该是 Going Under 里面的冥河币关卡切换界面的样子

shader_type canvas_item;

uniform vec4 _Tint = vec4(1, 1, 1, 1);
uniform int _Octaves = 5;
uniform float _Frequency = 5;
uniform float _Amplitude = 1;
uniform float _Lacunarity = 5;
uniform float _Persistence;
uniform vec2 _Offset;
uniform float _RidgeOffset;

void FAST32_hash_2D(vec2 gridcell, out vec4 hash_0, out vec4 hash_1)
{
	const vec2 OFFSET = vec2( 26.0, 161.0 );
	const float DOMAIN = 71.0;
	const vec2 SOMELARGEFLOATS = vec2( 951.135664, 642.949883 );
	vec4 P = vec4( gridcell, gridcell + 1.0 );
	P = P - floor(P * ( 1.0 / DOMAIN )) * DOMAIN;
	P += OFFSET.xyxy;
	P *= P;
	P = P.xzxz * P.yyww;
	hash_0 = fract( P * ( 1.0 / SOMELARGEFLOATS.x ) );
	hash_1 = fract( P * ( 1.0 / SOMELARGEFLOATS.y ) );
}

float SimplexPerlin2D( vec2 P )
{
	const float SKEWFACTOR = 0.36602540378443864676372317075294;            // 0.5*(sqrt(3.0)-1.0)
	const float UNSKEWFACTOR = 0.21132486540518711774542560974902;            // (3.0-sqrt(3.0))/6.0
	const float SIMPLEX_TRI_HEIGHT = 0.70710678118654752440084436210485;    // sqrt( 0.5 )    height of simplex triangle
	const vec3 SIMPLEX_POINTS = vec3( 1.0-UNSKEWFACTOR, -UNSKEWFACTOR, 1.0-2.0*UNSKEWFACTOR );      

	P *= SIMPLEX_TRI_HEIGHT;
	vec2 Pi = floor( P + dot( P, vec2( SKEWFACTOR, SKEWFACTOR ) ) );

	vec4 hash_x, hash_y;
	FAST32_hash_2D( Pi, hash_x, hash_y );

	vec2 v0 = Pi - dot( Pi, vec2( UNSKEWFACTOR, UNSKEWFACTOR ) ) - P ;
	vec4 v1pos_v1hash = (v0.x < v0.y) ? vec4(SIMPLEX_POINTS.xy, hash_x.y, hash_y.y) : vec4(SIMPLEX_POINTS.yx, hash_x.z, hash_y.z);
	vec4 v12 = vec4( v1pos_v1hash.xy, SIMPLEX_POINTS.zz ) + v0.xyxy;

	vec3 grad_x = vec3( hash_x.x, v1pos_v1hash.z, hash_x.w ) - 0.49999 + 0.1*cos(TIME);
	vec3 grad_y = vec3( hash_y.x, v1pos_v1hash.w, hash_y.w ) - 0.49999 + 0.1*sin(TIME);
	vec3 grad_results = inversesqrt( grad_x * grad_x + grad_y * grad_y ) * ( grad_x * vec3( v0.x, v12.xz ) + grad_y * vec3( v0.y, v12.yw ) );

	const float FINAL_NORMALIZATION = 99.204334582718712976990005025589;

	vec3 m = vec3( v0.x, v12.xz ) * vec3( v0.x, v12.xz ) + vec3( v0.y, v12.yw ) * vec3( v0.y, v12.yw );
	m = max(0.5 - m, 0.0);
	m = m*m;
	m = m*m;
	return dot(m, grad_results) * FINAL_NORMALIZATION;
}

float SimplexRidged(vec2 p, int octaves, vec2 offset, float frequency, float amplitude, float lacunarity, float persistence, float ridgeOffset)
{
	float sum = 0.0;
	for (int i = 0; i < octaves; i++)
	{
		float h = 0.0;
		h = 0.5 * (ridgeOffset - abs(4.0*SimplexPerlin2D((p + offset) * frequency)));
		sum += h*amplitude;
		frequency *= lacunarity;
		amplitude *= persistence;
	}
	return sum;
}

void fragment() {
	float h = SimplexRidged(UV, _Octaves, _Offset, _Frequency, _Amplitude, _Lacunarity, _Persistence, _RidgeOffset);
	COLOR = texture(TEXTURE, UV)-0.1*vec4(h,h,h,h);
	COLOR *= _Tint;
}