uniform vec2 u_resolution; uniform sampler2D u_texture; uniform vec2 u_points[32]; // 최대 8영역 × 4포인트 uniform int u_numAreas; uniform vec2 u_dragVectors[8]; uniform float u_distortionStrengths[8]; varying vec2 vUv; // 사각형 내부의 포인트에 대한 UV 좌표 계산 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; vec2 rectUV = (xy - minP) / rectSize; float u0 = rectUV.x; float v0 = rectUV.y; // Newton-Raphson 반복법으로 정확한 UV 계산 for (int iter = 0; iter < 3; iter++) { vec2 xy0 = mix(mix(p0, p1, u0), mix(p3, p2, u0), v0); vec2 du_vec = mix(p1 - p0, p2 - p3, v0); vec2 dv_vec = mix(p3 - p0, p2 - p1, u0); vec2 dxy = xy - xy0; float det = du_vec.x * dv_vec.y - du_vec.y * dv_vec.x; if (abs(det) < 1e-6) break; float du = (dv_vec.y * dxy.x - dv_vec.x * dxy.y) / det; float dv = (-du_vec.y * dxy.x + du_vec.x * dxy.y) / det; u0 += du; v0 += dv; } // 포인트가 내부에 있는지 확인 if (u0 >= 0.0 && u0 <= 1.0 && v0 >= 0.0 && v0 <= 1.0) { return vec2(u0, v0); } return vec2(-1.0, -1.0); } void main() { vec2 uv = vUv; vec2 pixelCoord = vUv * u_resolution; // 모든 영역의 왜곡 적용 for (int i = 0; i < 8; i++) { if (i >= u_numAreas) break; int baseIndex = i * 4; vec2 p0 = u_points[baseIndex + 0] * u_resolution; vec2 p1 = u_points[baseIndex + 1] * u_resolution; vec2 p2 = u_points[baseIndex + 2] * u_resolution; vec2 p3 = u_points[baseIndex + 3] * u_resolution; vec2 areaUV = computeUV(pixelCoord, p0, p1, p2, p3); if (areaUV.x >= 0.0) { // 이 영역 내부에 포인트가 있음 vec2 center = vec2(0.5, 0.5); float distToCenter = length(areaUV - center); float maxUvRadius = 0.707; // sqrt(0.5^2 + 0.5^2) // 부드러운 감쇠 float influence = 1.0 - smoothstep(0.0, maxUvRadius, distToCenter); // 왜곡 적용 vec2 distortion = (u_dragVectors[i] / u_resolution) * influence * u_distortionStrengths[i]; uv += distortion; } } // 텍스처 외부 샘플링 방지를 위한 클램핑 uv = clamp(uv, 0.0, 1.0); // 텍스처 샘플링 gl_FragColor = texture2D(u_texture, uv); }