shader_type canvas_item; uniform float patient_scale : hint_range(0.4, 1.0) = 0.82; uniform vec2 anchor = vec2(0.5, 0.985); uniform vec2 patient_offset = vec2(0.0, 0.0); uniform float breathing_speed : hint_range(0.5, 3.0) = 1.0; uniform float breathing_amount : hint_range(0.0, 0.03) = 0.012; uniform float blink_amount : hint_range(0.0, 1.0) = 0.0; void fragment() { // Size the patient around his original centerline, then lower the complete // seated pose until the knee crease meets the front edge of the cushion. vec2 source_uv = (UV - anchor - patient_offset) / patient_scale + anchor; // Deform only the upper body so his hips, knees, and contact with the bench // remain perfectly still. Two slow, slightly different cycles prevent the // idle from reading as a mechanical scale pulse. float torso_mask = smoothstep(0.13, 0.25, source_uv.y) * (1.0 - smoothstep(0.48, 0.58, source_uv.y)); float breath = 0.5 + 0.5 * sin(TIME * breathing_speed * 1.75); float chest_scale = 1.0 + breathing_amount * breath * torso_mask; source_uv.x = 0.5 + (source_uv.x - 0.5) / chest_scale; source_uv.y = 0.37 + (source_uv.y - 0.37) / (1.0 + breathing_amount * 0.45 * breath * torso_mask); float upper_body_mask = 1.0 - smoothstep(0.50, 0.62, source_uv.y); source_uv.x -= sin(TIME * breathing_speed * 0.63) * 0.0015 * upper_body_mask; if (source_uv.x < 0.0 || source_uv.x > 1.0 || source_uv.y < 0.0 || source_uv.y > 1.0) { COLOR = vec4(0.0); } else { vec4 patient_color = texture(TEXTURE, source_uv); // Cover each eye with color sampled from the lower eyelid, then retain a // narrow crease at full closure. Coordinates are in the canonical patient // texture, so scaling and positioning do not disturb the blink placement. vec2 eye_size = vec2(0.0105, 0.0065); vec2 left_eye_delta = (source_uv - vec2(0.4835, 0.1125)) / eye_size; vec2 right_eye_delta = (source_uv - vec2(0.5165, 0.1125)) / eye_size; float left_eye = 1.0 - smoothstep(0.72, 1.0, length(left_eye_delta)); float right_eye = 1.0 - smoothstep(0.72, 1.0, length(right_eye_delta)); float eye_mask = max(left_eye, right_eye) * blink_amount; vec3 lid_color = texture(TEXTURE, source_uv + vec2(0.0, 0.009)).rgb; patient_color.rgb = mix(patient_color.rgb, lid_color, eye_mask); float horizontal_extent = max( 1.0 - smoothstep(0.65, 1.0, abs(left_eye_delta.x)), 1.0 - smoothstep(0.65, 1.0, abs(right_eye_delta.x)) ); float crease = (1.0 - smoothstep(0.0, 0.24, min( abs(left_eye_delta.y), abs(right_eye_delta.y) ))) * horizontal_extent * blink_amount; patient_color.rgb = mix(patient_color.rgb, lid_color * 0.58, crease * 0.72); COLOR = patient_color; } }