88 lines
2.5 KiB
GLSL
88 lines
2.5 KiB
GLSL
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);
|
||
} |