extends RefCounted class_name WowLiquidMaterial static var _shader: Shader static var _cache: Dictionary = {} static func clear_cache() -> void: _cache.clear() 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 _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; varying vec3 world_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); } void vertex() { world_pos = (MODEL_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 = color; ALPHA = clamp(alpha_base + fresnel * 0.18 + ripple * 0.06, 0.0, 1.0); } """ return _shader