Files

196 lines
5.4 KiB
GDScript

extends RefCounted
class_name WowLiquidMaterial
static var _shader: Shader
static var _cache: Dictionary = {}
static func clear_cache() -> void:
_cache.clear()
static func _ensure_wow_shader_globals() -> void:
pass
static func build(liquid_id: int) -> ShaderMaterial:
var key := "adt:%d" % liquid_id
if _cache.has(key):
return _cache[key]
var style := _style_for_liquid(liquid_id)
var mat := _create_material(style)
_cache[key] = mat
return mat
static func build_wmo(material_id: int) -> ShaderMaterial:
var key := "wmo:%d" % material_id
if _cache.has(key):
return _cache[key]
var style := {
"color": Color(0.10, 0.30, 0.48, 0.60),
"foam": Color(0.58, 0.80, 1.00, 0.22),
"wave_strength": 0.045,
"wave_scale": 0.095,
"wave_speed": 0.38,
"fresnel_power": 2.2,
"emission_strength": 0.025,
"magma_mode": 0.0,
}
var mat := _create_material(style)
_cache[key] = mat
return mat
static func _create_material(style: Dictionary) -> ShaderMaterial:
var mat := ShaderMaterial.new()
mat.shader = _get_shader()
mat.render_priority = 1
mat.set_shader_parameter("liquid_color", style["color"])
mat.set_shader_parameter("foam_color", style["foam"])
mat.set_shader_parameter("wave_strength", float(style["wave_strength"]))
mat.set_shader_parameter("wave_scale", float(style["wave_scale"]))
mat.set_shader_parameter("wave_speed", float(style["wave_speed"]))
mat.set_shader_parameter("alpha_base", (style["color"] as Color).a)
mat.set_shader_parameter("fresnel_power", float(style["fresnel_power"]))
mat.set_shader_parameter("emission_strength", float(style["emission_strength"]))
mat.set_shader_parameter("magma_mode", float(style["magma_mode"]))
return mat
static func _style_for_liquid(liquid_id: int) -> Dictionary:
match liquid_id:
3, 15, 19:
return {
"color": Color(0.78, 0.22, 0.03, 0.78),
"foam": Color(1.00, 0.66, 0.10, 0.38),
"wave_strength": 0.025,
"wave_scale": 0.12,
"wave_speed": 0.22,
"fresnel_power": 1.7,
"emission_strength": 0.42,
"magma_mode": 1.0,
}
4, 20:
return {
"color": Color(0.16, 0.38, 0.12, 0.66),
"foam": Color(0.50, 0.80, 0.32, 0.24),
"wave_strength": 0.035,
"wave_scale": 0.11,
"wave_speed": 0.28,
"fresnel_power": 2.0,
"emission_strength": 0.05,
"magma_mode": 0.0,
}
2, 14:
return {
"color": Color(0.05, 0.16, 0.30, 0.64),
"foam": Color(0.48, 0.72, 1.00, 0.20),
"wave_strength": 0.060,
"wave_scale": 0.075,
"wave_speed": 0.32,
"fresnel_power": 2.5,
"emission_strength": 0.025,
"magma_mode": 0.0,
}
_:
return {
"color": Color(0.08, 0.28, 0.46, 0.58),
"foam": Color(0.58, 0.82, 1.00, 0.24),
"wave_strength": 0.050,
"wave_scale": 0.085,
"wave_speed": 0.36,
"fresnel_power": 2.3,
"emission_strength": 0.025,
"magma_mode": 0.0,
}
static func _get_shader() -> Shader:
if _shader:
return _shader
_ensure_wow_shader_globals()
_shader = Shader.new()
_shader.code = """
shader_type spatial;
render_mode blend_mix, cull_disabled, unshaded;
uniform vec4 liquid_color : source_color = vec4(0.08, 0.28, 0.46, 0.58);
uniform vec4 foam_color : source_color = vec4(0.58, 0.82, 1.00, 0.24);
uniform float wave_strength = 0.05;
uniform float wave_scale = 0.085;
uniform float wave_speed = 0.36;
uniform float alpha_base = 0.58;
uniform float fresnel_power = 2.3;
uniform float emission_strength = 0.025;
uniform float magma_mode = 0.0;
global uniform vec4 wow_fog_color;
global uniform vec2 wow_fog_range;
global uniform float wow_fog_density;
varying vec3 world_pos;
varying vec3 view_pos;
float hash21(vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
}
float noise21(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
vec2 u = f * f * (3.0 - 2.0 * f);
float a = hash21(i);
float b = hash21(i + vec2(1.0, 0.0));
float c = hash21(i + vec2(0.0, 1.0));
float d = hash21(i + vec2(1.0, 1.0));
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}
vec3 apply_wow_fog(vec3 color) {
float dist = length(view_pos);
float range_fog = smoothstep(wow_fog_range.x, wow_fog_range.y, dist);
float fog_amount = range_fog * clamp(wow_fog_density, 0.0, 1.0);
return mix(color, wow_fog_color.rgb, fog_amount);
}
void vertex() {
world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
view_pos = (MODELVIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
float t = TIME * wave_speed;
float wave_a = sin(world_pos.x * wave_scale + t);
float wave_b = cos(world_pos.z * wave_scale * 1.37 - t * 1.21);
VERTEX.y += (wave_a + wave_b) * wave_strength;
}
void fragment() {
vec3 n = normalize(NORMAL);
vec3 v = normalize(VIEW);
float facing = clamp(abs(dot(n, v)), 0.0, 1.0);
float fresnel = pow(1.0 - facing, fresnel_power);
vec2 p = world_pos.xz * wave_scale;
float n1 = noise21(p * 0.70 + vec2(TIME * wave_speed, -TIME * wave_speed * 0.60));
float n2 = noise21(p * 1.80 + vec2(-TIME * wave_speed * 0.35, TIME * wave_speed * 0.45));
float ripple = smoothstep(0.52, 0.86, n1 * 0.65 + n2 * 0.35);
vec3 color = mix(liquid_color.rgb, foam_color.rgb, ripple * foam_color.a);
color += fresnel * foam_color.rgb * 0.35;
if (magma_mode > 0.5) {
float glow = smoothstep(0.45, 1.0, ripple + fresnel * 0.45);
color += vec3(1.0, 0.35, 0.05) * glow * 0.45;
EMISSION = color * max(emission_strength, 0.35);
} else {
EMISSION = color * emission_strength;
}
ALBEDO = apply_wow_fog(color);
ALPHA = clamp(alpha_base + fresnel * 0.18 + ripple * 0.06, 0.0, 1.0);
}
"""
return _shader