소프트 바디 물리 엔진으로 구현한 프로시저럴 개구리 애니메이션
Processing으로 만든 소프트 바디(Soft Body) 개구리를 React 환경으로 포팅하며 배운 물리 시뮬레이션과 크로스 플랫폼 개발 경험을 공유해요.
프론트엔드 개발자로서 게임 엔진이나 물리 시뮬레이션 라이브러리에 관심이 많았지만, 직접 구현해볼 기회는 많지 않았어요. 그러던 중 우연히 발견한 GitHub 리포지토리가 호기심을 자극했어요. 소프트 바디 물리 엔진으로 구현된 개구리 애니메이션 - '귀엽다'는 첫인상 너머로, 실제로 작동하는 물리 엔진을 분석하고 다른 플랫폼으로 포팅하는 도전적인 작업이었죠.
원래 Processing 코드가 보여준 가능성
소프트 바디 물리의 마법 같은 현실감
기존의 개구리 애니메이션은 대부분 뼈대 구조를 기반으로 한 리깅(Rigging) 방식을 사용해요. 하지만 이 프로젝트는 완전히 다른 접근법을 택했어요. 개구리의 몸통을 수십 개의 점으로 구성된 '블롭(Blob)'으로 만들고, 이 점들이 서로 연결되어 물리적인 상호작용을 하는 구조죠.
class Blob {
ArrayList<BlobPoint> points;
Blob(PVector origin, int numPoints, float radius, float puffiness) {
points = new ArrayList<BlobPoint>();
for (int i = 0; i < numPoints; i++) {
PVector offset = new PVector(
cos(TWO_PI * i / numPoints - HALF_PI) * radius,
sin(TWO_PI * i / numPoints - HALF_PI) * radius
);
points.add(new BlobPoint(PVector.add(origin, offset)));
}
}
}이 블롭은 단순한 모양이 아니에요. 베를레 적분(Verlet Integration)을 사용한 물리 엔진이 각 점에 중력을 적용하고, 인접한 점들 사이의 거리를 유지하며 부드러운 변형을 만들어내요.
팔다리의 유기적인 움직임
개구리의 팔다리는 두 개의 관절로 구성된 역운동학(Inverse Kinematics, IK) 체계를 사용해요. 몸통의 앵커 포인트(Anchor Point)에서 시작해서 팔꿈치와 발끝까지 이어지는 체인 구조죠.
class Limb {
LimbPoint elbow;
LimbPoint foot;
Limb(PVector origin, float distance, float elbowRange, float elbowOffset,
float footRange, float footOffset) {
elbow = new LimbPoint(PVector.add(origin, new PVector(0, distance)));
foot = new LimbPoint(PVector.add(elbow.pos, new PVector(0, distance)));
}
}특히 인상적인 부분은 땅에 닿았을 때의 반응이에요. 발이 땅에 가까워지면 자연스럽게 자세를 교정하는 로직이 구현되어 있어, 실제 동물처럼 보이게 만들어요.
React 환경으로의 포팅 과정
p5.js: Processing의 JavaScript 형제
Processing 코드를 웹에서 실행하기 위해 선택한 도구는 p5.js였어요. Processing의 JavaScript 버전인 p5.js는 동일한 API를 제공하면서도 브라우저 환경에 최적화되어 있어요.
// React 컴포넌트에서 p5.js 사용
const sketch = (p: p5) => {
let frog: Frog;
p.setup = () => {
p.createCanvas(800, 600);
frog = new Frog(new p5.Vector(p.width / 2, p.height - 256));
};
p.draw = () => {
p.background(40, 44, 52);
frog.update(p);
frog.display(p);
};
};
const p5Instance = new p5(sketch, containerRef.current);호환성 문제와 해결 과정
포팅 과정에서 가장 큰 어려움은 p5.js 버전 차이로 인한 API 변경이었어요. 원래 Processing 코드는 curveVertex()를 사용해 부드러운 곡선을 그렸지만, p5.js v2에서는 이 함수가 제대로 작동하지 않는 문제가 발생했어요.
// 원래 Processing 코드
beginShape();
curveVertex(points.get(0).x, points.get(0).y);
curveVertex(points.get(1).x, points.get(1).y);
// ... 더 많은 curveVertex 호출
endShape();
// 수정된 p5.js 코드
beginShape();
for (const point of points) {
vertex(point.pos.x, point.pos.y);
}
endShape(CLOSE);결과적으로 vertex()를 사용한 폴리곤(Polygon) 렌더링으로 변경했는데, 오히려 이 방식이 더 간단하고 성능도 좋았어요.
기술적 세부사항과 배운 점
물리 엔진의 핵심: 베를레 적분
베를레 적분은 위치 기반의 물리 시뮬레이션 방법이에요. 기존의 속도-가속도 기반 방식과 달리, 이전 위치와 현재 위치만으로 다음 위치를 계산해요.
void verletIntegrate() {
PVector temp = pos.copy();
PVector vel = PVector.sub(pos, ppos).mult(0.99); // damping
pos.add(vel);
ppos = temp;
}이 방식의 장점은 안정성과 단순성이에요. 복잡한 미분 방정식을 풀 필요 없이, 직관적인 위치 기반 제약조건으로 자연스러운 움직임을 만들 수 있어요.
다중 제약 조건 해결
블롭의 부드러운 변형을 위해 세 가지 제약 조건을 동시에 해결해요:
- 거리 제약: 인접한 점들 사이의 거리를 유지
- 부피 제약: 블롭의 전체 면적을 일정하게 유지
- 충돌 처리: 경계와 마우스 상호작용
충돌 처리 부분이 특히 인상적이었어요:
void collideWithMouse() {
PVector mouse = new PVector(mouseX, mouseY);
if (mousePressed && PVector.dist(pos, mouse) < 100) {
PVector diff = PVector.sub(pos, mouse).setMag(100);
pos = PVector.add(mouse, diff);
}
}마우스로 블롭을 밀면 실제 물체처럼 반발하는 효과를 줘요.
성능 최적화와 실시간 렌더링
60fps 유지하기 위한 최적화
실시간 애니메이션을 위해 여러 최적화 기법을 적용했어요:
- 반복 횟수를 10회로 제한한 수렴 알고리즘
- 선택적 렌더링 (필요한 부분만 다시 그림)
- 효율적인 벡터 연산
크로스 플랫폼 호환성
Processing에서 p5.js로, 다시 React 컴포넌트로 포팅하면서 깨달은 점은 플랫폼 중립적인 설계의 중요성이에요. 물리 엔진 로직은 플랫폼에 종속되지 않도록 분리했고, 렌더링 부분만 각 플랫폼에 맞게 조정했어요.
이 프로젝트가 주는 교훈
물리 시뮬레이션의 실용성
게임 엔진처럼 복잡해 보이는 물리 시뮬레이션도 기본적인 수학적 원리와 반복적인 최적화로 구현할 수 있다는 것을 배웠어요. 베를레 적분, 제약 조건 해결, 충돌 감지 등의 개념은 게임 개발뿐 아니라 UI 애니메이션, 데이터 시각화 등 다양한 분야에 적용할 수 있어요.
크로스 플랫폼 개발의 가치
한 플랫폼에서 개발된 코드를 다른 플랫폼으로 포팅하는 과정에서, 플랫폼별 차이점을 극복하는 방법을 배웠어요. p5.js의 버전 차이로 인한 API 변경을 해결하는 과정은 실제 프로젝트에서 자주 마주치는 상황이기도 했어요.
오픈소스 코드 분석의 중요성
GitHub에서 발견한 코드를 분석하면서, 다른 개발자들의 문제 해결 방식을 배울 수 있었어요. 물리 엔진 구현에서 보여준 창의적인 접근법은 개발 방식에 큰 영감을 주었어요.
마치며
이 소프트 바디 개구리 애니메이션은 단순한 재미를 넘어, 물리 시뮬레이션의 가능성을 보여주는 좋은 사례였어요. Processing에서 시작해 React로 포팅하는 과정에서 배운 기술적 교훈들은 앞으로의 개발에 큰 도움이 될 것 같아요.
'복잡한 기술 = 복잡한 구현'이라는 편견을 깨준 프로젝트이기도 했어요. 기본적인 물리 법칙과 반복적인 최적화만으로도 충분히 인상적인 결과를 만들 수 있었죠.
물리 시뮬레이션이나 크로스 플랫폼 개발에 관심 있는 분들에게 작은 영감이 되었으면 좋겠어요. 개구리가 마우스 클릭에 어떻게 반응하는지, 직접 확인해 보세요.
At
Sun Dec 15 2024
