GODOT Shader 类似 glsl 语法.

着色器类型 shader_type canvas_item;

处理函数 不同着色器you固定的着色器入口,其中 particles 仅支持 vertex;

  • vertex 定点处理
  • fragment 片段处理,根据输入的材质处理
  • light 光照处理

渲染模式 不同类型着色器支持模式不同 查看渲染模式

  • blend_mix 混合混合模式(alpha是透明度),默认.
  • unshaded 结果只是反照率。 材质中不会发生照明/阴影。
  • cull_disabled

语法 查看支持的类型

一些常用类型

  • vec2, vec3, vec4, float
  • sampler2D 2d材质
  • sampler3D 3d材质
uniform float some_value;

在 gdscript 中可以调用,来设置参数,以来变动效果。

material.set_shader_param("some_value", some_value)

能量盾 Space Marine Shield

shield

shader_type spatial;
render_mode unshaded, cull_back;

uniform float rimWidth : hint_range(1.0, 3.0) = 2.0;
uniform vec4 rimColor : hint_color;
uniform vec4 outerRimColor : hint_color;
uniform sampler2D normalMap : hint_normal;
uniform float normalStrength : hint_range(0.0, 1.0);
uniform vec2 normalTiling = vec2(1.0, 1.0);
uniform vec2 normalOffset = vec2(0.0, 0.0);

void fragment(){
	vec2 uvModifier = (texture(normalMap, (UV * normalTiling) + (normalOffset * TIME)).xy * normalStrength) - normalStrength * 0.5;
	vec3 color = texture(SCREEN_TEXTURE, SCREEN_UV + uvModifier).rgb;

	float rim = 1.0 - abs(dot(VIEW, NORMAL));
	float outerRim = pow(rim, 4.0);
	rim = pow(rim, rimWidth);
	color = color + rim * rimColor.rgb;
	color = color + outerRim * outerRimColor.rgb;
	ALBEDO = color;
}

dancing

dancing

参数:

  • Time Factor (float) 时间 2
  • Amplitude (Vec2) 振幅 10,10
shader_type canvas_item;

uniform float time_factor = 2;
uniform vec2 amplitude = vec2(10, 10);

void vertex() {
	VERTEX.x += sin(TIME * time_factor) * amplitude.x;
	VERTEX.y += cos(TIME * time_factor) * amplitude.y;
}

water01 水波纹

water01


shader_type canvas_item;

uniform float initialize = 0.0;

void fragment()
{
	// GET THE HEIGHT AND VELOCITY OF THIS UV
	float h = texture( SCREEN_TEXTURE, SCREEN_UV ).r - 0.5;
	float v = texture( SCREEN_TEXTURE, SCREEN_UV ).g - 0.5;
	
	// COMPUTE NEW VELOCITY AND HEIGHT
	vec2 ps = SCREEN_PIXEL_SIZE;
	v -= 0.1 * h; // velocity of a point depends on the height of that point, to have a spring effect
	// velocity of a point also depends on the height of the points around it
	v += ( 
			( texture( SCREEN_TEXTURE, SCREEN_UV + vec2( 0, -ps.y ) ).x - 0.5 ) +
			( texture( SCREEN_TEXTURE, SCREEN_UV + vec2( 0, ps.y ) ).x - 0.5 ) +
			( texture( SCREEN_TEXTURE, SCREEN_UV + vec2( -ps.x, 0 ) ).x - 0.5 ) +
			( texture( SCREEN_TEXTURE, SCREEN_UV + vec2( ps.x, 0 ) ).x - 0.5 ) -
			4.0 * h ) * 0.2;
	v *= 0.98; // Dampen the velocity, otherwise it would oscillate forever
	h += v; // change the height with the new velocity - NOT FRAME RATE INDEPENDENT!
	
	// Generate drops
	if ( mod( TIME, 1.0 ) < .05 && initialize < 0.5 )
	{
		vec2 drop_pos = vec2( 0.5 + 0.5 * sin( floor( TIME * 5.0 ) * 20.0 ), 0.5 );
		if( length( UV - drop_pos ) < 0.01 )
		{
			h = -0.5;
		}
	}
	
	// INITIALIZATION
	if( initialize > 0.5 )
	{
		h *= 0.0;
		v *= 0.0;
	}
	
	// SET FRAGMENT COLOR BASED ON HEIGHT (RED) AND VELOCITY (GREEN)
	COLOR = vec4( h + 0.5, v + 0.5, 0.0, 1.0 );
}

water shadow

水中倒影

shader_type canvas_item;

void fragment()
{
	//vec2 uv = UV;
	//float r = TEXTURE_PIXEL_SIZE.y / SCREEN_PIXEL_SIZE.y;
	//vec2 suv = vec2( SCREEN_UV.x, 1.0-SCREEN_UV.y );
	
	//float mix_ratio = 0.5;
	//float vstretch = 1.0;
	
	// compute ration between the screen uv and the texture uv
	vec2 tex_to_screen_uv_ratio = SCREEN_PIXEL_SIZE / TEXTURE_PIXEL_SIZE;
	
	// compute UV of the flipped screen
	vec2 flipped_screen_uv = vec2( SCREEN_UV.x, 
		SCREEN_UV.y + 2.0 * UV.y * tex_to_screen_uv_ratio.y );
	vec2 suv = vec2( SCREEN_UV.x, SCREEN_UV.y + 2.0 * UV.y * tex_to_screen_uv_ratio.y );
	suv.x += 10.0 * SCREEN_PIXEL_SIZE.x * sin( 20.0 * UV.y  + TIME ) * UV.y;
	
	
	vec4 c1 = textureLod( SCREEN_TEXTURE, suv, 0.0 );
	//vec4 c2 = textureLod( SCREEN_TEXTURE, SCREEN_UV, 0.0 );
	c1 = mix( c1, vec4( 0.1, 0.1, 0.25, 1.0 ), 0.3 );
	
	COLOR = c1;//mix( c1, c2, 0.0 );
}

clock shader

clock 通过遮罩环形显示,显示类似钟表效果。

脚本中控制参数 max_angle0.1 到 0.5 (material.set_shader_param( "max_angle", ang ))。

shader_type canvas_item;

uniform float max_angle = 0.1;

void fragment()
{
	vec2 pos = UV - vec2( 0.5 );
	float r = length( pos );
	float a = atan( pos.y,pos.x );
	
	float alpha = step( a, ( max_angle - 0.5 ) * 6.28318530718 );
	vec4 c = texture( TEXTURE, UV );
	COLOR = vec4( c.rgb, c.a * alpha );
}

snow shader

snow

粒子效果

shader_type particles;

float rand_from_seed(inout uint seed) {
	int k;
	int s = int(seed);
	if (s == 0)
	s = 305420679;
	k = s / 127773;
	s = 16807 * (s - k * 127773) - 2836 * k;
	if (s < 0)
		s += 2147483647;
	seed = uint(s);
	return float(seed % uint(65536)) / 65535.0;
}

float rand_from_seed_m1_p1(inout uint seed) {
	return rand_from_seed(seed) * 2.0 - 1.0;
}

uint hash(uint x) {
	x = ((x >> uint(16)) ^ x) * uint(73244475);
	x = ((x >> uint(16)) ^ x) * uint(73244475);
	x = (x >> uint(16)) ^ x;
	return x;
}

float pos2vel_x( float pos0 )
{
	float half_block = 32.0;
	float pos = mod( pos0, 2.0 * half_block ) - half_block;
	float vel = sin( pos / half_block );
	return vel;
}

void vertex() {
	vec2 Extents = vec2( 320, 0 );
	vec2 InitVelXRange = vec2( 5, 20 );
	
	uint base_number = NUMBER;// / uint(trail_divisor);
	uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);
	

	if( RESTART )
	{
		// place particles randomly on top
		TRANSFORM[3].x = Extents.x * ( 2.0 * rand_from_seed( alt_seed ) - 1.0 );
		TRANSFORM[3].xy += EMISSION_TRANSFORM[3].xy;
		VELOCITY.y = InitVelXRange.x + ( InitVelXRange.y - InitVelXRange.x ) * rand_from_seed( alt_seed );// + 3.0 * rand_from_seed( alt_seed );
		CUSTOM.w = rand_from_seed( alt_seed ) * 100.0; // random initial phase
		//VELOCITY.x = pos2vel_x( TRANSFORM[3].x ) * 20.0;
		if( rand_from_seed( alt_seed ) < 0.5 )
		{
			COLOR = vec4( 0.7254901960784314, 0.7490196078431373, 0.9843137254901961, 1.0 );
		}
	}
	else
	{
		//VELOCITY.x += 5.0 * ( rand_from_seed( alt_seed ) - 0.5 );
		//VELOCITY.x *= 0.9;
		VELOCITY.x += 0.2 * cos( ( TRANSFORM[3].y - CUSTOM.w ) * 0.5 );
	}
}

cave light

为 light2D 追加摇曳效果

cave light

shader_type canvas_item;

void light()
{
	vec4 c = texture( TEXTURE, UV ).rgba;
	if( c.r > 0.5 || c.b > 0.5 )
	{
		//LIGHT *= 1.0;
		if( LIGHT.a > 0.3 )
		{
			LIGHT = LIGHT_COLOR;
		}
		else
		{
			LIGHT *= 0.0;
		}
	}
	else
	{
		LIGHT *= 0.0;
	}
	
}

border shader

shader_type canvas_item;

uniform float outline_width = 2.0;
uniform vec4 outline_color: hint_color;

void fragment() {
	vec4 col = texture(TEXTURE, UV);
	vec2 ps = TEXTURE_PIXEL_SIZE;
	float a;
	float maxa = col.a;
	float mina = col.a;

	a = texture(TEXTURE, UV + vec2(0.0, -outline_width) * ps).a;
	maxa = max(a, maxa);
	mina = min(a, mina);

	a = texture(TEXTURE, UV + vec2(0.0, outline_width) * ps).a;
	maxa = max(a, maxa);
	mina = min(a, mina);

	a = texture(TEXTURE, UV + vec2(-outline_width, 0.0) * ps).a;
	maxa = max(a, maxa);
	mina = min(a, mina);

	a = texture(TEXTURE, UV + vec2(outline_width, 0.0) * ps).a;
	maxa = max(a, maxa);
	mina = min(a, mina);

	COLOR = mix(col, outline_color, maxa - mina);
}

shadow

shader_type canvas_item;
render_mode blend_mix;

uniform vec2 offset = vec2(8.0, 8.0);
uniform vec4 modulate : hint_color;

void fragment() {
	vec2 ps = TEXTURE_PIXEL_SIZE;

	# 偏移处理
	vec4 shadow = vec4(modulate.rgb, texture(TEXTURE, UV - offset * ps).a * modulate.a);
	vec4 col = texture(TEXTURE, UV);

	COLOR = mix(shadow, col, col.a);
}

silhouette 剪影

shader_type canvas_item;

render_mode blend_mix;
uniform vec4 modulate: hint_color;

void fragment() {
	# 直接覆盖
	COLOR = vec4(modulate.rgb, texture(TEXTURE, UV).a * modulate.a);
}

光效处理

shader_type canvas_item;

// 材质输入
uniform sampler2D emission_teture;
// 色彩输入
uniform vec4 glow_color : hint_color = vec4(1.0);

void fragment()
{
	// 精灵当前像素
	vec4 current_color = texture(TEXTURE,UV); 
	// 要覆盖的材质
	vec4 emission_color = texture(emission_teture,UV); 
	
	// 检查在材质中不是黑色的部分
	if(emission_color.r > 0f)
	{
		// 在当前材质部分追加亮度
		COLOR = (emission_color + glow_color) 
	}
	else
	{
		// 未覆盖的部分默认当前
		COLOR = current_color; 
	}
}