diff --git a/package.json b/package.json index 447d967..6fa1bdb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@baekryang/responsive-image-canvas", - "version": "1.5.0", + "version": "1.5.2", "publishConfig": { "registry": "https://git.bnovalab.com/api/packages/baekryang/npm/" }, diff --git a/src/components/ImageDistortion.tsx b/src/components/ImageDistortion.tsx index 26c3677..afb8b3c 100644 --- a/src/components/ImageDistortion.tsx +++ b/src/components/ImageDistortion.tsx @@ -115,7 +115,7 @@ export const ImageDistortion: React.FC = ({ return; } - console.log('[ImageDistortion] 초기화 시작'); + console.log('[ImageDistortion] v1.5.1 초기화 시작'); const scene = new ThreeScene(containerRef.current); sceneRef.current = scene; @@ -277,13 +277,15 @@ export const ImageDistortion: React.FC = ({ // 스프라이트 이펙트 업데이트 (왜곡 영역과 독립적) if (spriteManagerRef.current) { const mouseState = mouseInteractionHook.getMouseState(); + const resolution = sceneRef.current?.getResolution() ?? { x: 1, y: 1 }; spriteManagerRef.current.update( spriteEffectAreas, deltaTime, { position: mouseState.position ?? null, isDragging: mouseState.isDragging, - } + }, + resolution, ); // 스프라이트 메쉬 변경 후 렌더링 필요 diff --git a/src/engine/SpriteEffectInstance.ts b/src/engine/SpriteEffectInstance.ts index 534387d..8e23b1e 100644 --- a/src/engine/SpriteEffectInstance.ts +++ b/src/engine/SpriteEffectInstance.ts @@ -240,7 +240,7 @@ export class SpriteEffectInstance { */ private _logCounter = 0; - update(deltaTime: number, emitCenter: Point): void { + update(deltaTime: number, emitCenter: Point, resolution?: { x: number; y: number }): void { if (!this.ready) return; // ambient 방출 @@ -297,7 +297,7 @@ export class SpriteEffectInstance { particle.position.y += particle.velocity.y * deltaTime; // Three.js 메쉬 동기화 - this.syncMesh(particle); + this.syncMesh(particle, resolution); } } @@ -328,7 +328,7 @@ export class SpriteEffectInstance { * 파티클 상태를 Three.js 메쉬에 동기화 * 정규화 좌표(0-1) → NDC(-1~1) 변환, y축 반전 */ - private syncMesh(particle: SpriteParticle): void { + private syncMesh(particle: SpriteParticle, resolution?: { x: number; y: number }): void { const mesh = this.meshes[particle.index]; if (!mesh) return; @@ -344,7 +344,9 @@ export class SpriteEffectInstance { mesh.position.y = -(particle.position.y * 2 - 1); mesh.position.z = -0.01; // 카메라가 -z를 바라보므로 음수가 앞쪽 - mesh.scale.set(particle.scale, particle.scale, 1); + // 종횡비 보정: OrthographicCamera(-1,1,1,-1) 기준 정사각형 NDC에서 직사각형 뷰포트 왜곡 방지 + const aspect = resolution ? resolution.x / resolution.y : 1; + mesh.scale.set(particle.scale / aspect, particle.scale, 1); mesh.rotation.z = particle.rotation; const mat = mesh.material as THREE.MeshBasicMaterial; diff --git a/src/engine/SpriteEffectManager.ts b/src/engine/SpriteEffectManager.ts index 7f20a10..8a27aab 100644 --- a/src/engine/SpriteEffectManager.ts +++ b/src/engine/SpriteEffectManager.ts @@ -90,7 +90,7 @@ export class SpriteEffectManager { * @param deltaTime 초 단위 프레임 시간 * @param touchState 마우스/터치 상태 */ - update(effectAreas: SpriteEffectArea[], deltaTime: number, touchState: SpriteEffectTouchState): void { + update(effectAreas: SpriteEffectArea[], deltaTime: number, touchState: SpriteEffectTouchState, resolution?: { x: number; y: number }): void { // 현재 터치 중인 영역 감지 const currentTouchingAreas = new Set(); @@ -120,7 +120,7 @@ export class SpriteEffectManager { } // 매 프레임 업데이트 (ambient 방출 + 파티클 물리) - instance.update(deltaTime, area.position); + instance.update(deltaTime, area.position, resolution); } }