나이아가라 스크립트에서 기본 수학 함수와 벡터 연산은 복잡한 파티클 동작을 구현하는 데 필수적인 도구입니다.
이러한 연산들을 효과적으로 활용하면 다양하고 역동적인 파티클 효과를 만들 수 있습니다.
기본 수학 함수
삼각 함수
sin(x)
, cos(x)
, tan(x)
: 기본 삼각 함수
asin(x)
, acos(x)
, atan(x)
: 역삼각 함수
atan2(y, x)
: 2인자 아크탄젠트 함수
예제 : 원형 움직임 생성
void CircularMotion ( inout float3 Position, float Time, float Radius)
{
Position.x = cos (Time) * Radius;
Position.y = sin (Time) * Radius;
}
Copy
지수와 로그 함수
pow(x, y)
: x의 y승
exp(x)
: e의 x승
log(x)
, log2(x)
, log10(x)
: 자연로그, 밑이 2인 로그, 밑이 10인 로그
예제 : 지수적 감소
float ExponentialDecay ( float InitialValue, float DecayRate, float Time)
{
return InitialValue * exp (-DecayRate * Time);
}
Copy
보간 함수
lerp(a, b, t)
: 선형 보간
smoothstep(a, b, t)
: 부드러운 에르미트 보간
예제 : 색상 변화
float4 ColorChange ( float4 StartColor, float4 EndColor, float Progress)
{
return lerp (StartColor, EndColor, smoothstep ( 0.0 , 1.0 , Progress));
}
Copy
기타 유용한 함수
abs(x)
: 절대값
min(x, y)
, max(x, y)
: 최소값, 최대값
clamp(x, min, max)
: 값을 특정 범위로 제한
saturate(x)
: 값을 0과 1 사이로 제한 (clamp(x, 0, 1)와 동일)
예제 : 범위 제한 움직임
float3 LimitedMovement ( float3 Position, float3 MinBounds, float3 MaxBounds)
{
return clamp (Position, MinBounds, MaxBounds);
}
Copy
벡터 연산
기본 벡터 연산
덧셈 : float3 result = a + b;
뺄셈 : float3 result = a - b;
스칼라 곱 : float3 result = a * scalar;
내적 (Dot Product)
예제 : 방향 벡터 사이의 각도 계산
float AngleBetweenVectors ( float3 a, float3 b)
{
return acos ( dot ( normalize (a), normalize (b)));
}
Copy
외적 (Cross Product)
예제 : 수직 벡터 생성
float3 GeneratePerpendicularVector ( float3 Normal)
{
return normalize ( cross (Normal, float3 ( 0 , 1 , 0 )));
}
Copy
정규화 (Normalization)
normalize(v)
: 벡터를 단위 벡터로 변환
예제 : 방향 벡터 생성
float3 GetDirectionVector ( float3 Start, float3 End)
{
return normalize (End - Start);
}
Copy
파티클 움직임 제어
복잡한 파티클 움직임은 이러한 수학 함수와 벡터 연산을 조합하여 구현할 수 있습니다.
예제 : 나선형 움직임
void SpiralMotion ( inout float3 Position, float Time, float Radius, float Height, float Frequency)
{
float Angle = Time * Frequency;
Position.x = cos (Angle) * Radius;
Position.y = sin (Angle) * Radius;
Position.z = Height * Time;
}
Copy
예제 : 중력 영향을 받는 파티클
void ApplyGravity ( inout float3 Velocity, float3 GravityDirection, float GravityStrength, float DeltaTime)
{
Velocity += GravityDirection * GravityStrength * DeltaTime;
}
Copy
복잡한 파티클 동작 구현
여러 수학 함수와 벡터 연산을 조합하여 더욱 복잡한 동작을 만들 수 있습니다.
예제 : 소용돌이 효과
void VortexEffect ( inout float3 Position, inout float3 Velocity, float3 VortexCenter, float VortexStrength, float UpwardForce, float DeltaTime)
{
float3 ToCenter = VortexCenter - Position;
float Distance = length (ToCenter);
float3 TangentialDir = normalize ( cross ( float3 ( 0 , 0 , 1 ), ToCenter));
// 회전력 적용
Velocity += TangentialDir * (VortexStrength / max (Distance, 1.0 )) * DeltaTime;
// 상승력 적용
Velocity.z += UpwardForce * DeltaTime;
// 속도 적용
Position += Velocity * DeltaTime;
}
Copy
이 예제에서는 파티클이 중심점 주위를 회전하면서 상승하는 소용돌이 효과를 만듭니다. cross
함수를 사용하여 접선 방향을 계산하고, 거리에 따라 회전력을 조절합니다.
성능을 고려한 효율적인 수학 연산 팁
사전 계산 활용 : 자주 사용되는 값은 미리 계산하여 저장
float SinTime = sin (Time);
float CosTime = cos (Time);
// 여러 번 사용되는 SinTime과 CosTime 재활용
Copy
복잡한 함수 근사 : 고비용 함수를 간단한 다항식으로 근사
// 예: 빠른 역제곱근 근사 (Fast Inverse Square Root)
float FastInvSqrt ( float x)
{
float xhalf = 0.5f * x;
int i = *( int *)&x;
i = 0x5f3759df - (i >> 1 );
x = *( float *)&i;
x = x * ( 1.5f - xhalf * x * x);
return x;
}
Copy
벡터 연산 최적화 : 불필요한 정규화 피하기
// 방향만 필요한 경우, 길이가 1이 아니어도 됨
float3 Direction = Target - Position;
float DistanceSq = dot (Direction, Direction);
// normalize(Direction) 대신 Direction 직접 사용
Copy
조건문 대신 수학 식 사용 : 분기 없이 연산으로 해결
// 조건문 대신
float Sign = step ( 0 , Value) * 2 - 1 ; // -1 또는 1
Copy
SIMD 활용 : 벡터 연산을 통한 병렬 처리
float4 Result = float4 ( 1 , 2 , 3 , 4 ) * float4 ( 5 , 6 , 7 , 8 );
// 4개의 곱셈을 동시에 수행
Copy
실제 적용 예시 : 불꽃놀이 효과
다양한 수학 함수와 벡터 연산을 조합하여 불꽃놀이 효과를 만들어 보겠습니다.
void InitializeFirework ( out float3 Position, out float3 Velocity, float3 LaunchPosition, float LaunchSpeed)
{
Position = LaunchPosition;
Velocity = float3 ( 0 , 0 , LaunchSpeed);
}
void UpdateFirework ( inout float3 Position, inout float3 Velocity, inout float4 Color,
float Time, float Lifetime, float3 Gravity, float ExplosionTime)
{
if (Time < ExplosionTime)
{
// 상승 단계
Velocity += Gravity * DeltaTime;
Position += Velocity * DeltaTime;
Color = float4 ( 1 , 0.5 , 0 , 1 ); // 밝은 노란색
}
else
{
// 폭발 단계
float ExplosionProgress = (Time - ExplosionTime) / (Lifetime - ExplosionTime);
float ExplosionRadius = sin (ExplosionProgress * PI) * 50.0 ;
float Angle = rand (Position.xy) * 2 * PI;
float Elevation = rand (Position.yz) * PI;
Velocity = float3 (
cos (Angle) * sin (Elevation),
sin (Angle) * sin (Elevation),
cos (Elevation)
) * ExplosionRadius;
Position += Velocity * DeltaTime;
// 색상 변화
Color = lerp ( float4 ( 1 , 0 , 0 , 1 ), float4 ( 0 , 0 , 1 , 0 ), ExplosionProgress);
}
}
Copy
이 스크립트는 초기 발사, 상승, 폭발, 그리고 소멸의 단계를 거치는 불꽃놀이 효과를 구현합니다. 삼각 함수, 벡터 연산, 보간 함수 등을 활용하여 복잡한 움직임과 시각 효과를 만들어냅니다.
나이아가라 스크립트에서 수학 함수와 벡터 연산을 능숙하게 활용하면, 복잡하고 아름다운 파티클 효과를 구현할 수 있습니다. 이러한 기본적인 연산들을 조합하고 최적화하여 효율적이면서도 시각적으로 인상적인 효과를 만들어보세요. 지속적인 실험과 최적화를 통해 더욱 발전된 파티클 시스템을 구축할 수 있을 것입니다.