uniform vec2 u_resolution; uniform sampler2D u_texture; uniform vec2 u_points[32]; // 최대 8영역 × 4포인트 (정규화된 좌표 0-1) uniform int u_numAreas; uniform vec2 u_dragVectors[8]; // 드래그 벡터 (정규화된 좌표 0-1) uniform float u_distortionStrengths[8]; varying vec2 vUv; // Flutter 원본 computeUV 함수 (정확히 동일하게 변환) vec2 computeUV(vec2 xy, vec2 p0, vec2 p1, vec2 p2, vec2 p3) { vec2 minP = min(min(p0, p1), min(p2, p3)); vec2 maxP = max(max(p0, p1), max(p2, p3)); if (xy.x < minP.x || xy.x > maxP.x || xy.y < minP.y || xy.y > maxP.y) { return vec2(-1.0, -1.0); // 외부 } vec2 rectSize = maxP - minP; if (rectSize.x == 0.0 || rectSize.y == 0.0) { return vec2(-1.0, -1.0); // 축퇴 } vec2 rectMin = minP; vec2 rectUV = (xy - rectMin) / rectSize; float u0 = rectUV.x; float v0 = rectUV.y; // 1회 Newton-Raphson (Flutter 원본과 동일) vec2 left = mix(p0, p1, u0); vec2 right = mix(p3, p2, u0); vec2 xy0 = mix(left, right, v0); vec2 dxy = xy - xy0; vec2 du_vec = mix(p1 - p0, p2 - p3, v0); vec2 dv_vec = mix(p3 - p0, p2 - p1, u0); float det = du_vec.x * dv_vec.y - du_vec.y * dv_vec.x; if (abs(det) > 1e-6) { float inv_det = 1.0 / det; float du = (dv_vec.y * dxy.x - dv_vec.x * dxy.y) * inv_det; float dv = (-du_vec.y * dxy.x + du_vec.x * dxy.y) * inv_det; u0 += du; v0 += dv; } return vec2(u0, v0); } void main() { vec2 xy = vUv * u_resolution; // 픽셀 좌표 vec2 texCoord = vUv; // 모든 겹치는 영역의 왜곡을 누적 적용 for (int i = 0; i < 8; i++) { if (i >= u_numAreas) break; // 포인트는 정규화된 좌표로 전달받았으므로 픽셀 좌표로 변환 vec2 p0 = u_points[i * 4 + 0] * u_resolution; vec2 p1 = u_points[i * 4 + 1] * u_resolution; vec2 p2 = u_points[i * 4 + 2] * u_resolution; vec2 p3 = u_points[i * 4 + 3] * u_resolution; vec2 uv_local = computeUV(xy, p0, p1, p2, p3); if (uv_local.x >= 0.0 && uv_local.x <= 1.0 && uv_local.y >= 0.0 && uv_local.y <= 1.0) { vec2 uvCenter = vec2(0.5, 0.5); float distToCenter = distance(uv_local, uvCenter); float maxUvRadius = 0.5; if (distToCenter < maxUvRadius) { float influence = 1.0 - smoothstep(0.0, maxUvRadius, distToCenter); // dragVector는 정규화된 좌표(0-1)이므로 바로 사용 vec2 distortion = u_dragVectors[i] * influence * u_distortionStrengths[i]; texCoord += distortion; // clamp를 루프 내에서 제거: 모든 왜곡을 완전히 누적한 후 마지막에 한 번만 clamp } } } // 모든 왜곡을 누적한 후 최종적으로 한 번만 clamp texCoord = clamp(texCoord, 0.0, 1.0); gl_FragColor = texture2D(u_texture, texCoord); }