responsive-image-canvas/dist/distortion.frag.glsl
2025-11-04 10:17:17 +09:00

88 lines
2.5 KiB
GLSL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}