icon안동민 개발노트

파티클 속성 읽기 및 쓰기


 나이아가라 스크립트에서 파티클 속성을 효과적으로 읽고 쓰는 것은 동적이고 복잡한 파티클 시스템을 구현하는 데 핵심적인 요소입니다.

 이 절에서는 파티클 속성 관리의 다양한 측면을 살펴보겠습니다.

기본 파티클 속성 접근

 나이아가라는 여러 기본 파티클 속성을 제공합니다. 이들에 접근하고 수정하는 방법은 다음과 같습니다.

  1. 위치 (Position)
void UpdatePosition(inout float3 Position, float3 Velocity, float DeltaTime)
{
    Position += Velocity * DeltaTime;
}
  1. 속도 (Velocity)
void ApplyForce(inout float3 Velocity, float3 Force, float DeltaTime)
{
    Velocity += Force * DeltaTime;
}
  1. 크기 (Size)
void GrowParticle(inout float Size, float GrowthRate, float DeltaTime)
{
    Size *= (1.0 + GrowthRate * DeltaTime);
}
  1. 색상 (Color)
void FadeParticle(inout float4 Color, float FadeRate, float DeltaTime)
{
    Color.a *= (1.0 - FadeRate * DeltaTime);
}
  1. 수명 (Age / Lifetime)
void UpdateAge(inout float Age, float DeltaTime, float Lifetime, out bool IsAlive)
{
    Age += DeltaTime;
    IsAlive = (Age < Lifetime);
}

사용자 정의 속성 생성 및 사용

 사용자 정의 속성을 통해 파티클 시스템의 기능을 확장할 수 있습니다.

  1. 속성 정의 : 나이아가라 에디터에서 새 속성 추가
  2. 스크립트에서 속성 사용
void UpdateCustomAttribute(inout float CustomValue, float UpdateRate, float DeltaTime)
{
    CustomValue += UpdateRate * DeltaTime;
}

 예 : 회전 속도 속성 추가

void UpdateRotation(inout float Rotation, float RotationSpeed, float DeltaTime)
{
    Rotation += RotationSpeed * DeltaTime;
    Rotation = fmod(Rotation, 360.0); // 0-360도 범위 유지
}

동적 행동 구현을 위한 속성 활용

 파티클 속성을 조합하여 복잡한 동작을 만들 수 있습니다.

void CreateSwirlEffect(inout float3 Position, inout float3 Velocity, 
                       float3 CenterPoint, float SwirlStrength, float UpwardForce, 
                       float DeltaTime)
{
    float3 ToCenter = CenterPoint - Position;
    float Distance = length(ToCenter);
    float3 SwirlVelocity = cross(normalize(ToCenter), float3(0, 0, 1)) * SwirlStrength / max(Distance, 1.0);
    
    Velocity += SwirlVelocity * DeltaTime;
    Velocity.z += UpwardForce * DeltaTime;
    
    Position += Velocity * DeltaTime;
}

 이 예제는 중심점 주위로 회전하면서 상승하는 소용돌이 효과를 만듭니다.

속성 간 상호작용 설정

 파티클 속성들은 서로 영향을 주고받을 수 있습니다.

void UpdateParticleProperties(inout float3 Velocity, inout float Size, 
                              inout float4 Color, float Age, float Lifetime)
{
    float LifeRatio = Age / Lifetime;
    
    // 수명에 따른 속도 감소
    Velocity *= (1.0 - LifeRatio);
    
    // 수명에 따른 크기 변화
    Size = lerp(1.0, 0.1, LifeRatio);
    
    // 수명에 따른 색상 변화
    Color = lerp(float4(1, 0, 0, 1), float4(0, 0, 1, 0), LifeRatio);
}

시스템 수준 vs 파티클 수준 속성

  1. 시스템 수준 속성
  • 모든 파티클에 공통적으로 적용
  • 예 : 중력, 바람 방향, 전체 파티클 수
void ApplySystemProperties(inout float3 Velocity, float3 WindDirection, float WindStrength)
{
    Velocity += WindDirection * WindStrength * DeltaTime;
}
  1. 파티클 수준 속성
  • 개별 파티클마다 다른 값을 가짐
  • 예 : 위치, 속도, 크기, 색상
void UpdateIndividualParticle(inout float3 Position, inout float3 Velocity, 
                                inout float Size, float RandomFactor)
{
    Velocity += float3(rand(Position.xy) - 0.5, rand(Position.yz) - 0.5, rand(Position.zx) - 0.5) * RandomFactor;
    Position += Velocity * DeltaTime;
    Size *= (1.0 + sin(Age * 5.0) * 0.1); // 크기 맥동
}

효율적인 속성 관리 및 최적화 기법

  1. 데이터 레이아웃 최적화
  • 자주 사용되는 속성들을 그룹화하여 캐시 효율성 향상
  • 예 : 위치와 속도를 연속된 메모리에 저장
  1. 조건부 업데이트
  • 필요한 경우에만 속성 업데이트
void ConditionalUpdate(inout float Value, float UpdateThreshold, float UpdateAmount)
{
    if (abs(Value) > UpdateThreshold)
    {
        Value += UpdateAmount;
    }
}
  1. 벡터화된 연산 활용
  • SIMD 연산을 활용하여 여러 속성을 동시에 업데이트
void VectorizedUpdate(inout float4 Properties)
{
    Properties += float4(0.1, 0.2, 0.3, 0.4) * DeltaTime;
}
  1. Look-up Tables (LUT) 사용
  • 복잡한 계산을 미리 계산된 테이블로 대체
float GetComplexValue(float Input, Texture2D LookupTexture)
{
    return SampleTexture(LookupTexture, float2(Input, 0)).r;
}

대규모 파티클 시스템에서의 속성 처리 전략

  1. Level of Detail (LOD) 시스템 구현
  • 카메라와의 거리에 따라 업데이트 빈도나 복잡도 조절
void UpdateWithLOD(inout float3 Position, float3 Velocity, float DistanceFromCamera)
{
    float UpdateFactor = saturate(1.0 - DistanceFromCamera / 1000.0);
    Position += Velocity * DeltaTime * UpdateFactor;
}
  1. Spatial Partitioning
  • 공간을 분할하여 근접 파티클만 상호작용 계산
void InteractWithinGrid(inout float3 Force, float3 Position, float3 GridCenter, float GridSize)
{
    if (distance(Position, GridCenter) < GridSize)
    {
        // 상호작용 로직
    }
}
  1. Instancing 활용
  • 유사한 속성을 가진 파티클들을 그룹화하여 일괄 처리
void UpdateParticleGroup(inout float3 GroupPosition, inout float GroupSize, int ParticleCount)
{
    GroupPosition += GroupVelocity * DeltaTime;
    GroupSize = sqrt(float(ParticleCount)) * BaseSize;
}

실제 적용 예시 : 복합 파티클 시스템

 다음은 여러 속성을 조합하여 만든 복합 파티클 시스템의 예입니다.

void UpdateComplexParticle(inout float3 Position, inout float3 Velocity, 
                           inout float Size, inout float4 Color, 
                           inout float Age, float Lifetime, 
                           float3 AttractorPosition, float AttractorStrength, 
                           float3 WindDirection, float WindStrength, 
                           float TurbulenceScale, float TurbulenceStrength)
{
    // 수명 업데이트
    Age += DeltaTime;
    float LifeRatio = Age / Lifetime;
 
    // 중력과 바람의 영향
    Velocity += float3(0, 0, -9.8) * DeltaTime; // 중력
    Velocity += WindDirection * WindStrength * DeltaTime;
 
    // 난류 효과
    float3 TurbulenceForce = float3(
        sin(Position.x * TurbulenceScale + Age),
        cos(Position.y * TurbulenceScale + Age),
        sin(Position.z * TurbulenceScale + Age)
    ) * TurbulenceStrength;
    Velocity += TurbulenceForce * DeltaTime;
 
    // 어트랙터 효과
    float3 ToAttractor = AttractorPosition - Position;
    float DistanceToAttractor = length(ToAttractor);
    Velocity += normalize(ToAttractor) * AttractorStrength / max(DistanceToAttractor, 1.0) * DeltaTime;
 
    // 위치 업데이트
    Position += Velocity * DeltaTime;
 
    // 크기 변화
    Size = lerp(1.0, 0.1, LifeRatio) * (1.0 + sin(Age * 10.0) * 0.1);
 
    // 색상 변화
    Color = lerp(float4(1, 0.5, 0, 1), float4(0, 0, 1, 0), LifeRatio);
 
    // 속도 감쇠
    Velocity *= 0.99;
}

 이 예제는 중력, 바람, 난류, 어트랙터 등 다양한 요소를 고려하여 파티클의 동작을 계산합니다. 또한 파티클의 수명에 따라 크기와 색상을 변화시킵니다.

 파티클 속성을 효과적으로 관리하고 조작함으로써, 복잡하고 역동적인 파티클 시스템을 구현할 수 있습니다. 성능과 시각적 품질 사이의 균형을 유지하면서, 다양한 최적화 기법을 활용하여 효율적인 시스템을 설계하는 것이 중요합니다. 지속적인 실험과 프로파일링을 통해 프로젝트에 가장 적합한 속성 관리 전략을 개발하세요.