icon안동민 개발노트

기본 물리 기반 파티클 시뮬레이션


 나이아가라에서 물리 기반 파티클 시뮬레이션을 구현하면 더욱 사실적이고 동적인 시각 효과를 만들 수 있습니다.

 이 절에서는 기본적인 물리 법칙을 적용한 파티클 시뮬레이션 구현 방법을 살펴보겠습니다.

기본 물리 현상 시뮬레이션

 중력

 중력은 가장 기본적인 물리 현상으로, 파티클에 일정한 가속도를 적용하여 구현할 수 있습니다.

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;
}

 이 예시에서는 중력, 폭발력, 공기 저항, 지면 충돌, 마찰, 난류 등 다양한 물리적 요소를 고려하여 폭발 파티클의 움직임을 시뮬레이션합니다.

 각 파티클은 질량, 수명, 색상 등의 속성을 가지며, 시간에 따라 이들이 변화합니다.

 물리 기반 파티클 시뮬레이션을 통해 더욱 사실적이고 역동적인 시각 효과를 만들 수 있습니다.

 기본 물리 법칙을 이해하고 이를 효과적으로 구현하는 것이 중요합니다.