shader_type canvas_item; // 탑다운 바다의 물빛 오버레이. 바닥 위에 덮여서 "물을 통해 내려다본다"는 느낌을 만든다. // 구역 하나를 담당하고, 좌우 끝 색을 이웃과 공유해 이음매 없이 이어진다. uniform vec4 tint_left : source_color = vec4(0.27, 0.70, 0.80, 1.0); uniform vec4 tint_right : source_color = vec4(0.16, 0.51, 0.57, 1.0); // 깊을수록 물이 두꺼워 바닥이 흐려진다. uniform float murk_left : hint_range(0.0, 1.0) = 0.20; uniform float murk_right : hint_range(0.0, 1.0) = 0.30; // 물결 무늬가 구역 경계에서 끊기지 않도록 스트립 전체에서의 위치를 넘겨받는다. uniform float x_offset = 0.0; uniform vec2 rect_size = vec2(300.0, 220.0); uniform float caustic_strength : hint_range(0.0, 0.4) = 0.13; // 수면에서 내려오는 빛의 양. 밤에는 0에 가까워져 물결도 빛줄기도 잦아든다. uniform float sun : hint_range(0.0, 1.0) = 1.0; // 수면에서 내려오는 빛줄기. 얕은 구역에서만 뚜렷하고 깊어질수록 사라진다. uniform float ray_left : hint_range(0.0, 1.0) = 0.7; uniform float ray_right : hint_range(0.0, 1.0) = 0.6; void fragment() { vec2 px = vec2(x_offset, 0.0) + UV * rect_size; vec3 tint = mix(tint_left.rgb, tint_right.rgb, UV.x); float murk = mix(murk_left, murk_right, UV.x); // 수면에서 갈라진 빛이 바닥에 드리우는 그물 무늬. vec2 p = px / 78.0; float c = sin(p.x + TIME * 0.45) * sin(p.y * 1.3 - TIME * 0.31); c += sin(p.x * 1.7 - TIME * 0.38) * sin(p.y * 0.8 + TIME * 0.44); float caustic = pow(max(c * 0.5 + 0.5, 0.0), 3.0) * sun; // 밝은 물결 자리는 물이 얇아 보이도록 살짝 걷어낸다. float alpha = clamp(murk - caustic * caustic_strength * 0.5, 0.0, 1.0); vec3 col = tint + caustic * caustic_strength; // 비스듬히 내려오는 빛줄기. 3/4 시점이라 화면 위쪽(먼 곳)에서 가장 밝고 // 앞으로 올수록 흩어진다. 물속임을 알려주는 가장 강한 신호다. float rs = mix(ray_left, ray_right, UV.x) * sun; if (rs > 0.001) { // 거의 세로로 서되 살짝 기운다. y 계수를 크게 잡으면 화면이 높을 때 // 무늬가 가로로 누워버려 빛줄기로 안 보인다. float g = px.x * 0.010 + px.y * 0.0035; float r = (sin(g + TIME * 0.09) * 0.5 + 0.5) * (sin(g * 2.3 - TIME * 0.06) * 0.5 + 0.5); float rays = pow(r, 2.6) * rs * smoothstep(1.0, 0.02, UV.y); // 빛줄기는 물을 걷어내는 게 아니라 물 속에 떠 있는 밝은 기둥이다. // 알파를 낮추면 바닥만 밝아지고 물기둥은 텅 빈 채로 남는다. col += rays * 0.38; alpha = clamp(alpha + rays * 0.20, 0.0, 1.0); } COLOR = vec4(col, alpha); }