fix: Fix coordinate system to match Flutter implementation

- Fix y-coordinate inversion between UI (top-left origin) and WebGL (bottom-left origin)
- Convert UI coordinates to WebGL coordinates when passing to shader
- Invert drag vector y-direction to match coordinate system
- Add getResolution() method to ThreeScene for coordinate conversion
- Update shader to use normalized drag vectors directly

This resolves the issue where distortion appeared at opposite y-position from clicked point.
This commit is contained in:
BaekRyang 2025-11-05 11:20:07 +09:00
parent e371321fd2
commit ef992b5525
3 changed files with 22 additions and 8 deletions

View File

@ -143,22 +143,27 @@ export const ImageDistortion: React.FC<ImageDistortionProps> = ({
useEffect(() => { useEffect(() => {
if (!sceneRef.current || !isReady) return; if (!sceneRef.current || !isReady) return;
// 현재 해상도 가져오기
const resolution = sceneRef.current.getResolution();
// 포인트 배열 생성 // 포인트 배열 생성
// UI는 좌상단 (0,0), WebGL은 좌하단 (0,0)이므로 y 좌표를 반전
const points = new Float32Array(SHADER_CONFIG.MAX_POINTS * 2); const points = new Float32Array(SHADER_CONFIG.MAX_POINTS * 2);
currentAreas.forEach((area, areaIndex) => { currentAreas.forEach((area, areaIndex) => {
area.basePoints.forEach((point, pointIndex) => { area.basePoints.forEach((point, pointIndex) => {
const index = (areaIndex * 4 + pointIndex) * 2; const index = (areaIndex * 4 + pointIndex) * 2;
points[index] = point.x; points[index] = point.x;
points[index + 1] = point.y; points[index + 1] = 1.0 - point.y; // y 좌표 반전
}); });
}); });
// 드래그 벡터 배열 생성 // 드래그 벡터 배열 생성
// dragVector도 y 좌표계를 맞춰야 하므로 y를 반전
const dragVectors = new Float32Array(SHADER_CONFIG.MAX_DRAG_VECTORS * 2); const dragVectors = new Float32Array(SHADER_CONFIG.MAX_DRAG_VECTORS * 2);
currentAreas.forEach((area, index) => { currentAreas.forEach((area, index) => {
const baseIndex = index * 2; const baseIndex = index * 2;
dragVectors[baseIndex] = area.dragVector.x; dragVectors[baseIndex] = area.dragVector.x;
dragVectors[baseIndex + 1] = area.dragVector.y; dragVectors[baseIndex + 1] = -area.dragVector.y; // y 방향 반전
}); });
// 강도 배열 생성 // 강도 배열 생성

View File

@ -115,6 +115,16 @@ export class ThreeScene {
this.renderer.render(this.scene, this.camera); this.renderer.render(this.scene, this.camera);
} }
/**
*
*/
public getResolution(): { x: number; y: number } {
return {
x: this.uniforms.u_resolution.value.x,
y: this.uniforms.u_resolution.value.y,
};
}
/** /**
* *
*/ */

View File

@ -1,8 +1,8 @@
uniform vec2 u_resolution; uniform vec2 u_resolution;
uniform sampler2D u_texture; uniform sampler2D u_texture;
uniform vec2 u_points[32]; // 최대 8영역 × 4포인트 (정규화된 좌표) uniform vec2 u_points[32]; // 최대 8영역 × 4포인트 (정규화된 좌표 0-1)
uniform int u_numAreas; uniform int u_numAreas;
uniform vec2 u_dragVectors[8]; // 정규화된 좌표 uniform vec2 u_dragVectors[8]; // 드래그 벡터 (정규화된 좌표 0-1)
uniform float u_distortionStrengths[8]; uniform float u_distortionStrengths[8];
varying vec2 vUv; varying vec2 vUv;
@ -72,10 +72,9 @@ void main() {
if (distToCenter < maxUvRadius) { if (distToCenter < maxUvRadius) {
float influence = 1.0 - smoothstep(0.0, maxUvRadius, distToCenter); float influence = 1.0 - smoothstep(0.0, maxUvRadius, distToCenter);
// dragVector도 정규화된 좌표이므로 픽셀로 변환 // dragVector는 정규화된 좌표(0-1)이므로 바로 사용 (Flutter와 동일한 결과)
vec2 distortion = (u_dragVectors[i] * u_resolution) * influence * u_distortionStrengths[i]; vec2 distortion = u_dragVectors[i] * influence * u_distortionStrengths[i];
// texCoord는 이미 정규화된 좌표이므로 정규화된 왜곡 적용 texCoord += distortion;
texCoord += distortion / u_resolution;
texCoord = clamp(texCoord, 0.0, 1.0); texCoord = clamp(texCoord, 0.0, 1.0);
} }
found = true; found = true;