- Fix distortion.frag.glsl to match Flutter original implementation - Update computeUV function with single Newton-Raphson iteration - Fix coordinate transformation (normalized to pixel) - Fix distortion application logic - Add break after first matching area (Flutter behavior) - Add image loading state management - Add imageLoaded state - Add loading progress callback - Add loading UI indicator - Improve error handling - Add comprehensive debug logging - ShaderManager: fetch status and shader lengths - ThreeScene: shader compilation check, render calls - ImageDistortion: lifecycle and loading status - Add test/debug shaders for troubleshooting - test.frag.glsl: Simple pass-through shader - debug.frag.glsl: Area visualization shader - Fix infinite loop bug in animationCallback - Use setState updater function to avoid dependency 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
276 lines
7.7 KiB
TypeScript
276 lines
7.7 KiB
TypeScript
import React from 'react';
|
||
import * as THREE from 'three';
|
||
|
||
/**
|
||
* 정규화된 좌표계의 2D 포인트 (0.0 - 1.0)
|
||
*/
|
||
interface Point {
|
||
x: number;
|
||
y: number;
|
||
}
|
||
/**
|
||
* 애니메이션 이징 함수 타입
|
||
*/
|
||
type EasingFunction = 'linear' | 'easeIn' | 'easeOut' | 'easeInOut' | 'easeInQuad' | 'easeOutQuad';
|
||
/**
|
||
* 왜곡 애니메이션 움직임 설정
|
||
*/
|
||
interface DistortionMovement {
|
||
/** 왜곡 시작 벡터 */
|
||
vectorA: Point;
|
||
/** 왜곡 종료 벡터 */
|
||
vectorB: Point;
|
||
/** 애니메이션 지속 시간 (초) */
|
||
duration: number;
|
||
/** 적용할 이징 함수 */
|
||
easing: EasingFunction;
|
||
}
|
||
/**
|
||
* 사각형 포인트와 애니메이션 설정을 포함하는 왜곡 영역
|
||
*/
|
||
interface DistortionArea {
|
||
/** 고유 식별자 */
|
||
id: string;
|
||
/** 사각형의 네 모서리 포인트 [topLeft, topRight, bottomRight, bottomLeft] */
|
||
basePoints: [Point, Point, Point, Point];
|
||
/** 움직임 애니메이션 설정 */
|
||
movement: DistortionMovement;
|
||
/** 왜곡 강도 (0.0 - 1.0) */
|
||
distortionStrength: number;
|
||
/** 현재 애니메이션 진행도 (0.0 - 1.0) */
|
||
progress: number;
|
||
/** 현재 드래그 벡터 (progress로부터 계산됨) */
|
||
dragVector: Point;
|
||
}
|
||
/**
|
||
* 영역 충돌 감지를 위한 경계 상자
|
||
*/
|
||
interface AreaBounds {
|
||
minX: number;
|
||
minY: number;
|
||
maxX: number;
|
||
maxY: number;
|
||
}
|
||
|
||
/**
|
||
* 셰이더 유니폼 변수 타입
|
||
*/
|
||
interface ShaderUniforms {
|
||
[uniform: string]: THREE.IUniform;
|
||
/** 화면 해상도 */
|
||
u_resolution: THREE.IUniform<THREE.Vector2>;
|
||
/** 이미지 텍스처 */
|
||
u_texture: THREE.IUniform<THREE.Texture | null>;
|
||
/** 모든 영역의 포인트 배열 (최대 32개 포인트 = 8영역 × 4포인트) */
|
||
u_points: THREE.IUniform<Float32Array>;
|
||
/** 활성 영역 개수 */
|
||
u_numAreas: THREE.IUniform<number>;
|
||
/** 각 영역의 드래그 벡터 배열 */
|
||
u_dragVectors: THREE.IUniform<Float32Array>;
|
||
/** 각 영역의 왜곡 강도 배열 */
|
||
u_distortionStrengths: THREE.IUniform<Float32Array>;
|
||
}
|
||
/**
|
||
* 셰이더 설정
|
||
*/
|
||
interface ShaderConfig {
|
||
/** 최대 영역 개수 */
|
||
maxAreas: number;
|
||
/** 최대 포인트 개수 (maxAreas × 4) */
|
||
maxPoints: number;
|
||
}
|
||
|
||
/**
|
||
* 애니메이션 상태
|
||
*/
|
||
interface AnimationState {
|
||
/** 재생 중 여부 */
|
||
isPlaying: boolean;
|
||
/** 현재 시간 (초) */
|
||
currentTime: number;
|
||
/** 델타 타임 (프레임 간 시간 차이, 초) */
|
||
deltaTime: number;
|
||
/** 현재 FPS */
|
||
fps: number;
|
||
}
|
||
/**
|
||
* 애니메이션 틱 컨트롤러
|
||
*/
|
||
interface AnimationTicker {
|
||
/** 애니메이션 시작 */
|
||
start: () => void;
|
||
/** 애니메이션 정지 */
|
||
stop: () => void;
|
||
/** 애니메이션 일시정지 */
|
||
pause: () => void;
|
||
/** 애니메이션 재개 */
|
||
resume: () => void;
|
||
}
|
||
|
||
/**
|
||
* ImageDistortion 컴포넌트 Props
|
||
*/
|
||
interface ImageDistortionProps {
|
||
/** 이미지 소스 URL */
|
||
imageSrc: string;
|
||
/** 왜곡 영역 배열 */
|
||
areas: DistortionArea[];
|
||
/** 버텍스 셰이더 경로 (선택사항) */
|
||
vertexShaderPath?: string;
|
||
/** 프래그먼트 셰이더 경로 (선택사항) */
|
||
fragmentShaderPath?: string;
|
||
/** 애니메이션 재생 여부 */
|
||
isPlaying?: boolean;
|
||
/** 컨테이너 스타일 */
|
||
style?: React.CSSProperties;
|
||
/** 컨테이너 클래스명 */
|
||
className?: string;
|
||
}
|
||
/**
|
||
* GPU 가속 이미지 왜곡 컴포넌트
|
||
* Three.js와 GLSL 셰이더를 사용하여 실시간 이미지 왜곡 효과를 제공합니다.
|
||
*/
|
||
declare const ImageDistortion: React.FC<ImageDistortionProps>;
|
||
|
||
/**
|
||
* 진행도에 이징 함수를 적용
|
||
* @param progress 진행도 (0.0 - 1.0)
|
||
* @param easingType 적용할 이징 함수 타입
|
||
* @returns 이징이 적용된 진행도 (0.0 - 1.0)
|
||
*/
|
||
declare const applyEasing: (progress: number, easingType: EasingFunction) => number;
|
||
|
||
/**
|
||
* 셰이더 관련 설정
|
||
*/
|
||
declare const SHADER_CONFIG: {
|
||
/** 최대 영역 개수 */
|
||
readonly MAX_AREAS: 8;
|
||
/** 최대 포인트 개수 (8영역 × 4포인트) */
|
||
readonly MAX_POINTS: 32;
|
||
/** 최대 드래그 벡터 개수 */
|
||
readonly MAX_DRAG_VECTORS: 8;
|
||
/** 최대 강도 배열 크기 */
|
||
readonly MAX_STRENGTHS: 8;
|
||
};
|
||
/**
|
||
* 애니메이션 관련 설정
|
||
*/
|
||
declare const ANIMATION_CONFIG: {
|
||
/** 목표 FPS */
|
||
readonly TARGET_FPS: 60;
|
||
/** 델타 타임 (약 16.67ms) */
|
||
readonly DELTA_TIME: number;
|
||
};
|
||
/**
|
||
* 기본 영역 설정값
|
||
*/
|
||
declare const DEFAULT_AREA: {
|
||
/** 기본 왜곡 강도 */
|
||
readonly DISTORTION_STRENGTH: 0.5;
|
||
/** 기본 애니메이션 지속 시간 (초) */
|
||
readonly DURATION: 2;
|
||
/** 기본 이징 함수 */
|
||
readonly EASING: "easeInOut";
|
||
/** 기본 벡터 A */
|
||
readonly VECTOR_A: {
|
||
readonly x: 0.1;
|
||
readonly y: 0.1;
|
||
};
|
||
/** 기본 벡터 B */
|
||
readonly VECTOR_B: {
|
||
readonly x: -0.1;
|
||
readonly y: -0.1;
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Three.js 씬 관리 클래스
|
||
*/
|
||
declare class ThreeScene {
|
||
private container;
|
||
private scene;
|
||
private camera;
|
||
private renderer;
|
||
private mesh;
|
||
private uniforms;
|
||
constructor(container: HTMLElement);
|
||
/**
|
||
* 윈도우 리사이즈 핸들러
|
||
*/
|
||
private handleResize;
|
||
/**
|
||
* 셰이더 머티리얼 설정
|
||
* @param vertexShader 버텍스 셰이더 소스
|
||
* @param fragmentShader 프래그먼트 셰이더 소스
|
||
*/
|
||
setShaderMaterial(vertexShader: string, fragmentShader: string): void;
|
||
/**
|
||
* 유니폼 값 업데이트
|
||
* @param updates 업데이트할 유니폼 값들
|
||
*/
|
||
updateUniforms(updates: Partial<ShaderUniforms>): void;
|
||
/**
|
||
* 씬 렌더링
|
||
*/
|
||
render(): void;
|
||
/**
|
||
* 리소스 정리
|
||
*/
|
||
dispose(): void;
|
||
}
|
||
|
||
/**
|
||
* 셰이더 파일 로딩 및 관리 클래스
|
||
*/
|
||
declare class ShaderManager {
|
||
private vertexShaderSource;
|
||
private fragmentShaderSource;
|
||
/**
|
||
* 셰이더 파일들을 비동기로 로드
|
||
* @param vertexPath 버텍스 셰이더 파일 경로
|
||
* @param fragmentPath 프래그먼트 셰이더 파일 경로
|
||
* @returns 로드된 셰이더 소스 코드
|
||
*/
|
||
loadShaders(vertexPath: string, fragmentPath: string): Promise<{
|
||
vertex: string;
|
||
fragment: string;
|
||
}>;
|
||
/**
|
||
* 버텍스 셰이더 소스 코드 반환
|
||
*/
|
||
getVertexShader(): string;
|
||
/**
|
||
* 프래그먼트 셰이더 소스 코드 반환
|
||
*/
|
||
getFragmentShader(): string;
|
||
}
|
||
|
||
/**
|
||
* 애니메이션 루프 관리 클래스
|
||
*/
|
||
declare class AnimationLoop {
|
||
/**
|
||
* 영역들의 드래그 벡터를 현재 진행도에 따라 업데이트
|
||
* @param areas 왜곡 영역 배열
|
||
* @returns 업데이트된 영역 배열
|
||
*/
|
||
static updateAreaDragVectors(areas: DistortionArea[]): DistortionArea[];
|
||
/**
|
||
* 모든 영역의 진행도를 델타 타임만큼 업데이트
|
||
* @param areas 왜곡 영역 배열
|
||
* @param deltaTime 델타 타임 (초)
|
||
* @returns 업데이트된 영역 배열
|
||
*/
|
||
static updateProgress(areas: DistortionArea[], deltaTime: number): DistortionArea[];
|
||
}
|
||
|
||
/**
|
||
* requestAnimationFrame을 사용한 애니메이션 루프 훅
|
||
* @param callback 매 프레임마다 호출될 콜백 (deltaTime을 인자로 받음)
|
||
* @param isPlaying 애니메이션 재생 여부
|
||
*/
|
||
declare const useAnimationFrame: (callback: (deltaTime: number) => void, isPlaying?: boolean) => void;
|
||
|
||
export { ANIMATION_CONFIG, AnimationLoop, type AnimationState, type AnimationTicker, type AreaBounds, DEFAULT_AREA, type DistortionArea, type DistortionMovement, type EasingFunction, ImageDistortion, type ImageDistortionProps, type Point, SHADER_CONFIG, type ShaderConfig, ShaderManager, type ShaderUniforms, ThreeScene, applyEasing, useAnimationFrame };
|