- 마우스 움직임에 따라 왜곡 영역이 튕기는 효과를 추가했습니다. - `useMouseVelocity` 훅을 사용하여 마우스 속도와 가속도를 추적합니다. - `SpringPhysics` 클래스를 구현하여 스프링 기반 물리 효과를 시뮬레이션합니다. - `useMouseInteraction` 훅은 마우스 이벤트를 감지하고 `SpringPhysics`를 제어하여 왜곡 영역의 `dragVector`를 업데이트합니다. - `ImageDistortion` 컴포넌트에서 `mouseInteraction` prop을 통해 이 기능을 활성화/설정할 수 있습니다.
543 lines
15 KiB
TypeScript
543 lines
15 KiB
TypeScript
import React$1 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;
|
||
}
|
||
|
||
/**
|
||
* 스프링 물리 파라미터
|
||
*/
|
||
interface SpringPhysicsConfig {
|
||
/** 스프링 탄성 계수 (높을수록 빠르게 복원) */
|
||
stiffness: number;
|
||
/** 감쇠 계수 (높을수록 빨리 멈춤) */
|
||
damping: number;
|
||
/** 질량 (높을수록 느리게 움직임) */
|
||
mass: number;
|
||
/** 영향 반경 (정규화 좌표, 기본값 0.2) */
|
||
influenceRadius: number;
|
||
/** 최대 왜곡 강도 */
|
||
maxStrength: number;
|
||
}
|
||
/**
|
||
* 마우스 인터랙션 설정
|
||
*/
|
||
interface MouseInteractionConfig {
|
||
/** 마우스 인터랙션 활성화 여부 */
|
||
enabled: boolean;
|
||
/** 스프링 물리 파라미터 */
|
||
physics: SpringPhysicsConfig;
|
||
/** 최소 속도 임계값 (이보다 느리면 효과 없음) */
|
||
minVelocity?: number;
|
||
/** 최대 속도 제한 (이보다 빠르면 클램핑) */
|
||
maxVelocity?: number;
|
||
/** 속도 승수 (마우스 속도에 곱해지는 값) */
|
||
velocityMultiplier?: number;
|
||
}
|
||
/**
|
||
* 마우스 상태
|
||
*/
|
||
interface MouseState {
|
||
/** 현재 마우스 위치 (정규화 좌표) */
|
||
position: Point | null;
|
||
/** 이전 마우스 위치 */
|
||
prevPosition: Point | null;
|
||
/** 속도 벡터 */
|
||
velocity: Point;
|
||
/** 가속도 벡터 */
|
||
acceleration: Point;
|
||
/** 마우스가 컨테이너 위에 있는지 */
|
||
isHovering: boolean;
|
||
/** 드래그 중인지 */
|
||
isDragging: boolean;
|
||
}
|
||
/**
|
||
* 스프링 물리 상태
|
||
*/
|
||
interface SpringState {
|
||
/** 현재 변위 (displacement) */
|
||
displacement: Point;
|
||
/** 현재 속도 */
|
||
velocity: Point;
|
||
/** 목표 위치 (평형 상태는 {x:0, y:0}) */
|
||
target: Point;
|
||
}
|
||
|
||
/**
|
||
* ImageDistortion 컴포넌트 Props
|
||
*/
|
||
interface ImageDistortionProps {
|
||
/** 이미지 소스 URL */
|
||
imageSrc: string;
|
||
/** 왜곡 영역 배열 */
|
||
areas: DistortionArea[];
|
||
/** 버텍스 셰이더 경로 (선택사항) */
|
||
vertexShaderPath?: string;
|
||
/** 프래그먼트 셰이더 경로 (선택사항) */
|
||
fragmentShaderPath?: string;
|
||
/** 애니메이션 재생 여부 */
|
||
isPlaying?: boolean;
|
||
/** 컨테이너 스타일 */
|
||
style?: React$1.CSSProperties;
|
||
/** 컨테이너 클래스명 */
|
||
className?: string;
|
||
/** 마우스 인터랙션 설정 */
|
||
mouseInteraction?: MouseInteractionConfig;
|
||
}
|
||
/**
|
||
* GPU 가속 이미지 왜곡 컴포넌트
|
||
* Three.js와 GLSL 셰이더를 사용하여 실시간 이미지 왜곡 효과를 제공합니다.
|
||
*/
|
||
declare const ImageDistortion: React$1.FC<ImageDistortionProps>;
|
||
|
||
/**
|
||
* 에디터 편집 모드
|
||
*/
|
||
type EditMode = 'normal' | 'point-edit' | 'parameter-edit';
|
||
/**
|
||
* 에디터 상태
|
||
*/
|
||
interface EditorState {
|
||
/** 현재 선택된 영역 ID */
|
||
selectedAreaId: string | null;
|
||
/** 모든 왜곡 영역 */
|
||
areas: DistortionArea[];
|
||
/** 현재 편집 모드 */
|
||
editMode: EditMode;
|
||
/** 드래그 중인 포인트 인덱스 (0-3) */
|
||
draggingPointIndex: number | null;
|
||
}
|
||
/**
|
||
* 왜곡 영역 원 레벨 스타일
|
||
*/
|
||
interface CircleLevelStyle {
|
||
/** 반지름 (0.0 - 1.0, UV 좌표) */
|
||
radius: number;
|
||
/** 투명도 (0.0 - 1.0) */
|
||
opacity: number;
|
||
/** 선 두께 (픽셀) */
|
||
lineWidth: number;
|
||
/** 선 색상 (CSS color) */
|
||
color?: string;
|
||
/** 대시 패턴 [dash, gap] */
|
||
dashPattern?: [number, number];
|
||
}
|
||
/**
|
||
* 중심점 스타일
|
||
*/
|
||
interface CenterPointStyle {
|
||
/** 반지름 (픽셀) */
|
||
radius?: number;
|
||
/** 채우기 색상 */
|
||
fillColor?: string;
|
||
/** 테두리 색상 */
|
||
strokeColor?: string;
|
||
/** 테두리 두께 */
|
||
strokeWidth?: number;
|
||
}
|
||
/**
|
||
* 포인트 핸들 스타일
|
||
*/
|
||
interface PointHandleStyle {
|
||
/** 핸들 크기 (픽셀) */
|
||
size?: number;
|
||
/** 채우기 색상 */
|
||
fillColor?: string;
|
||
/** 테두리 색상 */
|
||
strokeColor?: string;
|
||
/** 테두리 두께 */
|
||
strokeWidth?: number;
|
||
/** 레이블 색상 */
|
||
labelColor?: string;
|
||
/** 레이블 폰트 크기 */
|
||
labelFontSize?: number;
|
||
}
|
||
/**
|
||
* 영역 외곽선 스타일
|
||
*/
|
||
interface AreaOutlineStyle {
|
||
/** 선택된 영역 색상 */
|
||
selectedColor?: string;
|
||
/** 선택되지 않은 영역 색상 */
|
||
unselectedColor?: string;
|
||
/** 선택된 영역 선 두께 */
|
||
selectedWidth?: number;
|
||
/** 선택되지 않은 영역 선 두께 */
|
||
unselectedWidth?: number;
|
||
/** 선택되지 않은 영역 대시 패턴 */
|
||
unselectedDashPattern?: [number, number];
|
||
/** 선택된 영역 배경 채우기 색상 */
|
||
selectedFillColor?: string;
|
||
/** 선택되지 않은 영역 배경 채우기 색상 */
|
||
unselectedFillColor?: string;
|
||
}
|
||
/**
|
||
* 에디터 캔버스 스타일
|
||
*/
|
||
interface EditorCanvasStyle {
|
||
/** 왜곡 영역 원 레벨 스타일 배열 (외부 -> 내부 순) */
|
||
circleLevels?: CircleLevelStyle[];
|
||
/** 왜곡 영역 내부 채우기 색상 */
|
||
circleFillColor?: string;
|
||
/** 중심점 스타일 */
|
||
centerPoint?: CenterPointStyle;
|
||
/** 포인트 핸들 스타일 */
|
||
pointHandle?: PointHandleStyle;
|
||
/** 영역 외곽선 스타일 */
|
||
areaOutline?: AreaOutlineStyle;
|
||
}
|
||
/**
|
||
* 에디터 Props
|
||
*/
|
||
interface DistortionEditorProps {
|
||
/** 초기 영역 배열 */
|
||
initialAreas?: DistortionArea[];
|
||
/** 이미지 소스 */
|
||
imageSrc: string;
|
||
/** 영역 변경 콜백 */
|
||
onAreasChange?: (areas: DistortionArea[]) => void;
|
||
/** 선택된 영역 변경 콜백 */
|
||
onSelectedAreaChange?: (areaId: string | null) => void;
|
||
/** 캔버스 너비 */
|
||
width?: number;
|
||
/** 캔버스 높이 */
|
||
height?: number;
|
||
/** 에디터 캔버스 스타일 커스터마이징 */
|
||
canvasStyle?: EditorCanvasStyle;
|
||
}
|
||
|
||
declare const DistortionEditor: React$1.FC<DistortionEditorProps>;
|
||
|
||
declare const useDistortionEditor: (initialAreas?: DistortionArea[]) => {
|
||
state: EditorState;
|
||
selectArea: (areaId: string | null) => void;
|
||
addArea: (area: DistortionArea) => void;
|
||
removeArea: (areaId: string) => void;
|
||
updateArea: (areaId: string, updates: Partial<DistortionArea>) => void;
|
||
updatePoint: (areaId: string, pointIndex: number, point: Point) => void;
|
||
startDragging: (pointIndex: number) => void;
|
||
stopDragging: () => void;
|
||
setEditMode: (mode: EditorState["editMode"]) => void;
|
||
getSelectedArea: () => DistortionArea | null;
|
||
};
|
||
|
||
/**
|
||
* 진행도에 이징 함수를 적용
|
||
* @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;
|
||
/**
|
||
* 현재 해상도 가져오기
|
||
*/
|
||
getResolution(): {
|
||
x: number;
|
||
y: number;
|
||
};
|
||
/**
|
||
* 리소스 정리
|
||
*/
|
||
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[];
|
||
}
|
||
|
||
/**
|
||
* 스프링 기반 물리 시뮬레이션 엔진
|
||
* Hooke's Law와 감쇠를 적용한 스프링-댐퍼 시스템
|
||
*/
|
||
declare class SpringPhysics {
|
||
private config;
|
||
private state;
|
||
constructor(config: SpringPhysicsConfig);
|
||
/**
|
||
* 물리 파라미터 업데이트
|
||
*/
|
||
setConfig(config: Partial<SpringPhysicsConfig>): void;
|
||
/**
|
||
* 목표 위치 설정 (마우스 속도 기반)
|
||
*/
|
||
setTarget(velocity: Point, velocityMultiplier?: number): void;
|
||
/**
|
||
* 초기 속도 설정 (드래그 방향과 속도를 즉시 반영)
|
||
* 드래그 방향으로 즉시 튕기는 효과
|
||
*/
|
||
setInitialVelocity(velocity: Point, multiplier?: number): void;
|
||
/**
|
||
* 스프링 물리 업데이트 (Hooke's Law + Damping)
|
||
* F = -k * x - c * v
|
||
* a = F / m
|
||
* v += a * dt
|
||
* x += v * dt
|
||
*/
|
||
update(deltaTime: number): Point;
|
||
/**
|
||
* 즉시 충격 적용 (마우스 가속도 기반)
|
||
*/
|
||
applyImpulse(acceleration: Point, multiplier?: number): void;
|
||
/**
|
||
* 현재 변위 가져오기
|
||
*/
|
||
getDisplacement(): Point;
|
||
/**
|
||
* 현재 속도 가져오기
|
||
*/
|
||
getVelocity(): Point;
|
||
/**
|
||
* 상태 리셋
|
||
*/
|
||
reset(): void;
|
||
/**
|
||
* 마우스가 멈췄을 때 목표를 0으로 설정 (평형 상태로 복귀)
|
||
*/
|
||
returnToEquilibrium(): void;
|
||
}
|
||
|
||
/**
|
||
* requestAnimationFrame을 사용한 애니메이션 루프 훅
|
||
* @param callback 매 프레임마다 호출될 콜백 (deltaTime을 인자로 받음)
|
||
* @param isPlaying 애니메이션 재생 여부
|
||
*/
|
||
declare const useAnimationFrame: (callback: (deltaTime: number) => void, isPlaying?: boolean) => void;
|
||
|
||
/**
|
||
* 마우스 위치, 속도, 가속도를 추적하는 훅
|
||
*/
|
||
declare const useMouseVelocity: (containerRef: React.RefObject<HTMLElement | null>) => {
|
||
getState: () => MouseState;
|
||
};
|
||
|
||
/**
|
||
* 마우스 인터랙션 기반 기존 영역 제어 훅
|
||
* 기존 영역을 손으로 튕기는 효과
|
||
*/
|
||
declare const useMouseInteraction: (containerRef: React.RefObject<HTMLElement | null>, config: MouseInteractionConfig) => {
|
||
updateInteraction: (areas: DistortionArea[], deltaTime: number) => DistortionArea[];
|
||
updateConfig: (newConfig: Partial<MouseInteractionConfig>) => void;
|
||
reset: () => void;
|
||
};
|
||
|
||
export { ANIMATION_CONFIG, AnimationLoop, type AnimationState, type AnimationTicker, type AreaBounds, DEFAULT_AREA, type DistortionArea, DistortionEditor, type DistortionEditorProps, type DistortionMovement, type EasingFunction, type EditMode, type EditorState, ImageDistortion, type ImageDistortionProps, type MouseInteractionConfig, type MouseState, type Point, SHADER_CONFIG, type ShaderConfig, ShaderManager, type ShaderUniforms, SpringPhysics, type SpringPhysicsConfig, type SpringState, ThreeScene, applyEasing, useAnimationFrame, useDistortionEditor, useMouseInteraction, useMouseVelocity };
|