기본 물리 기반 파티클 시뮬레이션
나이아가라에서 물리 기반 파티클 시뮬레이션을 구현하면 더욱 사실적이고 동적인 시각 효과를 만들 수 있습니다.
이 절에서는 기본적인 물리 법칙을 적용한 파티클 시뮬레이션 구현 방법을 살펴보겠습니다.
기본 물리 현상 시뮬레이션
중력
중력은 가장 기본적인 물리 현상으로, 파티클에 일정한 가속도를 적용하여 구현할 수 있습니다.
void ApplyGravity(inout float3 Velocity, float DeltaTime)
{
float3 GravityAcceleration = float3(0, 0, -9.81);
Velocity += GravityAcceleration * DeltaTime;
}
공기 저항
공기 저항은 파티클의 속도에 반비례하는 힘으로 구현할 수 있습니다.
void ApplyAirResistance(inout float3 Velocity, float DragCoefficient, float DeltaTime)
{
float Speed = length(Velocity);
float3 DragForce = -normalize(Velocity) * DragCoefficient * Speed * Speed;
Velocity += DragForce * DeltaTime;
}
바람의 영향
바람은 시간에 따라 변화하는 외부 힘으로 모델링할 수 있습니다.
void ApplyWind(inout float3 Velocity, float Time, float DeltaTime)
{
float3 WindDirection = float3(sin(Time * 0.5), cos(Time * 0.3), 0);
float WindStrength = 10.0 + sin(Time) * 5.0;
Velocity += WindDirection * WindStrength * DeltaTime;
}
물리적 속성 적용
질량
질량은 파티클에 작용하는 힘의 효과를 조절합니다.
void ApplyForce(inout float3 Velocity, float3 Force, float Mass, float DeltaTime)
{
Velocity += Force * (1.0 / Mass) * DeltaTime;
}
탄성
탄성은 충돌 시 파티클의 반발력을 결정합니다.
void ApplyBounce(inout float3 Velocity, float3 SurfaceNormal, float Elasticity)
{
Velocity = reflect(Velocity, SurfaceNormal) * Elasticity;
}
마찰
마찰은 표면과 접촉 시 파티클의 운동을 감소시킵니다.
void ApplyFriction(inout float3 Velocity, float3 SurfaceNormal, float FrictionCoefficient)
{
float3 NormalVelocity = dot(Velocity, SurfaceNormal) * SurfaceNormal;
float3 TangentialVelocity = Velocity - NormalVelocity;
TangentialVelocity *= max(0, 1 - FrictionCoefficient);
Velocity = NormalVelocity + TangentialVelocity;
}
간단한 강체 동역학 시뮬레이션
강체 동역학을 시뮬레이션하려면 파티클의 회전도 고려해야 합니다.
struct RigidBody
{
float3 Position;
float3 Velocity;
float3 AngularVelocity;
float3x3 Orientation;
};
void UpdateRigidBody(inout RigidBody Body, float DeltaTime)
{
// 선형 운동 업데이트
Body.Position += Body.Velocity * DeltaTime;
// 회전 운동 업데이트
float Angle = length(Body.AngularVelocity) * DeltaTime;
float3 Axis = normalize(Body.AngularVelocity);
float3x3 RotationMatrix = AngleAxis3x3(Angle, Axis);
Body.Orientation = mul(RotationMatrix, Body.Orientation);
}
파티클 간 상호작용
충돌
파티클 간 충돌은 거리 체크와 속도 조정으로 구현할 수 있습니다.
void ParticleCollision(inout float3 Position1, inout float3 Velocity1,
float3 Position2, float3 Velocity2, float Radius)
{
float3 Direction = Position1 - Position2;
float Distance = length(Direction);
if (Distance < Radius * 2)
{
float3 CollisionNormal = normalize(Direction);
float3 RelativeVelocity = Velocity1 - Velocity2;
float Speed = dot(RelativeVelocity, CollisionNormal);
if (Speed < 0)
{
float3 ImpulseForce = -2 * Speed * CollisionNormal;
Velocity1 += ImpulseForce * 0.5;
Position1 += CollisionNormal * (Radius * 2 - Distance) * 0.5;
}
}
}
인력과 척력
파티클 간 인력이나 척력은 거리에 따른 힘으로 모델링할 수 있습니다.
void ApplyParticleForce(inout float3 Velocity, float3 OtherPosition, float3 Position,
float Strength, float DeltaTime)
{
float3 Direction = OtherPosition - Position;
float Distance = length(Direction);
float3 Force = normalize(Direction) * Strength / (Distance * Distance);
Velocity += Force * DeltaTime;
}
성능 최적화 전략
1. 공간 분할
- 그리드 또는 옥트리를 사용하여 파티클 간 상호작용 체크 최적화
2. GPU 가속
- 대량의 파티클 계산을 GPU에서 수행
3. LOD (Level of Detail) 시스템
- 거리에 따라 시뮬레이션 복잡도 조절
4. 시뮬레이션 섹션화
- 파티클을 그룹으로 나누어 순차적으로 업데이트
5. 고정 시간 스텝
- 일정한 시간 간격으로 시뮬레이션하여 안정성 확보
현실적인 물리 효과 구현 팁
1. 다중 입자 시스템 활용
- 여러 파티클 시스템을 조합하여 복잡한 효과 생성
2. 노이즈 함수 활용
- 자연스러운 랜덤성 추가
3. 서브스텝 구현
- 큰 시간 간격을 여러 작은 스텝으로 나누어 계산
4. 물리 기반 파라미터 사용
- 실제 물리량을 참고하여 파라미터 설정
적용 예시 : 물리 기반 폭발 효과
다음은 물리 법칙을 적용한 폭발 효과의 구현 예시입니다.
struct ExplosionParticle
{
float3 Position;
float3 Velocity;
float Mass;
float Lifetime;
float4 Color;
};
void UpdateExplosionParticle(inout ExplosionParticle Particle, float DeltaTime,
float3 ExplosionCenter, float ExplosionForce, float Time)
{
// 중력 적용
Particle.Velocity += float3(0, 0, -9.81) * DeltaTime;
// 폭발력 적용 (시간에 따라 감소)
float3 ExplosionDirection = Particle.Position - ExplosionCenter;
float Distance = length(ExplosionDirection);
float DecayFactor = exp(-Distance * 0.1);
float3 ExplosionImpulse = normalize(ExplosionDirection) * ExplosionForce * DecayFactor / Particle.Mass;
Particle.Velocity += ExplosionImpulse * DeltaTime;
// 공기 저항
float DragCoefficient = 0.47; // 구형 물체 기준
float AirDensity = 1.225; // 해수면 기준 (kg/m^3)
float ParticleArea = 3.14159 * 0.01; // 반지름 0.1m 가정
float3 DragForce = -0.5 * DragCoefficient * AirDensity * ParticleArea *
Particle.Velocity * length(Particle.Velocity);
Particle.Velocity += DragForce * (1.0 / Particle.Mass) * DeltaTime;
// 위치 업데이트
Particle.Position += Particle.Velocity * DeltaTime;
// 수명 및 색상 업데이트
Particle.Lifetime -= DeltaTime;
float LifeRatio = Particle.Lifetime / 2.0; // 전체 수명을 2초로 가정
Particle.Color = lerp(float4(1, 0, 0, 0), float4(0.5, 0.5, 0, 1), LifeRatio);
// 지면 충돌 처리
if (Particle.Position.z < 0)
{
Particle.Position.z = 0;
Particle.Velocity = reflect(Particle.Velocity, float3(0, 0, 1)) * 0.6; // 60% 탄성
// 마찰 적용
float FrictionCoefficient = 0.3;
float2 HorizontalVelocity = Particle.Velocity.xy;
HorizontalVelocity *= max(0, 1 - FrictionCoefficient);
Particle.Velocity.xy = HorizontalVelocity;
}
// 난류 효과 추가
float3 Turbulence = float3(
sin(Time * 5.0 + Particle.Position.x * 0.1),
cos(Time * 4.0 + Particle.Position.y * 0.1),
sin(Time * 3.0 + Particle.Position.z * 0.1)
) * 2.0;
Particle.Velocity += Turbulence * DeltaTime;
}
이 예시에서는 중력, 폭발력, 공기 저항, 지면 충돌, 마찰, 난류 등 다양한 물리적 요소를 고려하여 폭발 파티클의 움직임을 시뮬레이션합니다.
각 파티클은 질량, 수명, 색상 등의 속성을 가지며, 시간에 따라 이들이 변화합니다.
물리 기반 파티클 시뮬레이션을 통해 더욱 사실적이고 역동적인 시각 효과를 만들 수 있습니다.
기본 물리 법칙을 이해하고 이를 효과적으로 구현하는 것이 중요합니다.