Unity에서 슬로우 모션(Slow Motion)효과 주기 - TimeScale/AudioSource
# Introduce
Unity 메소드를 활용해 슬로우 모션(Slow Motion)효과를 적용해봅시다.
> Time.timeScale
> Time.fixedDeltaTime
> Time.unscaledDeltaTime
> Audio Source Pitch
> Fade Effect
> Delegate
# For example
1. Time.timeScale (시간 조절)
Time.timeScale은 시간이 경과하는 크기를 나타냅니다.
해당 값을 수정하여 시간이 흐르는 속도(배율)를 조절할 수 있습니다.
using UnityEngine;
public class SlowMationClass : MonoBehaviour {
public float slowFactor = 0.05f;
public void DoSlowMotion()
{
Time.timeScale = slowFactor;
}
}
Time.timeScale의 기본 값은 1.0f 입니다. 실제 시간(real time) 의 같은 속도(1배)로 시간이 흐르게 됩니다.
값을 2.0f 으로 설정하면 시간이 흐르는 속도가 2배 빨라집니다.
값을 0.5f 으로 설정하면 시간이 흐르는 속도가 절반으로 느려집니다.
값을 0f 으로 설정하면 시간이 흐르지 않습니다. 일시정지(Pause) 상태가 됩니다.
2. Time.fixedDeltaTime (물리 연산 프레임 조절)
Time.timsScale은 보통 Unity를 접해본 사람이라면 흔히 알고 있는 개념입니다.
그러나 Time.fixedDeltaTime은 생소하게 느껴질 수 있습니다.
Time.fixedDeltaTime은 물리 연산(physics)과 고정 프레임률(MonoBehaviour의 FixedUpdate)을 나타냅니다.
Time.timeScale의 값만 변경하면 물리 효과를 받는 오브젝트의 움직임이 뚝.뚝. 끊겨보입니다.
그 이유는 Time.fixedDeltaTime 값이 Time.timeScale 에 의해 영향을 받는 상대적인 값이기 때문입니다.
유니티에서 물리 연산을 담당하는 FixedUpdate()는 timeScale이 아닌, fixedDeltaTime의 시간마다 호출됩니다.
using UnityEngine;
public class SlowMationClass : MonoBehaviour {
public float slowFactor = 0.05f;
public void DoSlowMotion()
{
Time.timeScale = slowFactor;
Time.fixedDeltaTime = Time.timeScale * 0.02f;
}
}
따라서 Time.timeScale 의 값을 변경했다면, Time.fixedDeltaTime 의 값도 같이 변경해줍시다. (1초/50회 = 0.02f)
3. Fade Effect (페이드 효과)
이번에는 정해진 시간이 지나면 원래대로 돌아오는 효과도 만들어 봅시다.
using UnityEngine;
public class SlowMotionClass : MonoBehaviour
{
public float slowFactor = 0.05f;
public float slowLength = 4f;
public void DoSlowMotion()
{
Time.timeScale = slowFactor;
Time.fixedDeltaTime = Time.timeScale * 0.02f;
}
private void Update()
{
Time.timeScale += (1f / slowLength) * Time.unscaledDeltaTime;
Time.timeScale = Mathf.Clamp(Time.timeScale, 0f, 1f);
Time.fixedDeltaTime = Time.timeScale * 0.02f;
}
}
Time.unscaledDeltaTime은 주로 Time.deltaTime과 같은 방식으로 사용됩니다.
두 값의 차이점은 Time.deltaTime은 Time.timeScale의 영향을 받습니다.
Time.unscaledDeltaTime은 실제 시간(real time)의 속도로 흐르며, Time.timeScale의 영향을 받지 않습니다.
즉, 슬로우 모션 효과를 줄 때 Time.timeScale의 값을 변경했기 때문에,
우리는 실제 시간을 확인하기 위해 Time.unscaledDeltaTime값을 사용합시다.
float Mathf.Clamp(float value, float min, float max) 메소드 : value의 값이 min보다 값이 작으면 min을 반환, max보다 값이 크면 max를 반환, 그 이외에는 value의 값을 반환합니다. |
위 소스 코드에서 DoSlowMotion() 을 실행시키면,
실행 직후 Unity 의 시간이 slowFactor(0.05f) 값으로 변하며, slowLength(4초) 동안 천천히 원래의 속도(1f)로 돌아옵니다.
4. Audio Source Pitch (오디오 속도 조절)
이제 우리는 Unity의 시간을 조절해서 자연스러운 슬로우 모션 효과를 줄 수 있습니다.
하지만 Time.timeScale의 영향을 받지 않는 것이 하나 더 있습니다.
그건 바로 Audio/Sound의 속도 입니다.
using UnityEngine;
public class SlowMotionAudio : MonoBehaviour
{
public void DoSlowMotion()
{
GetComponent<AudioSource>().pitch = Time.timeScale;
}
}
AudioSource와 Time.timeScale은 독립적으로 재생됩니다.
따라서 Audio/Sound에도 슬로우 모션 효과를 주고 싶다면 AudioSource의 Pitch값을 변경해야 합니다.
Pitch 값은 오디오 클립의 감속/속도 증가로 인한 피치 변화량을 뜻 합니다. 일반 재생 속도는 1.0f 입니다.
5. Audio Fade Effect (오디오 페이드 효과)
시간 값에 페이드 효과를 적용했으니, 오디오에도 페이드 효과를 만들어봅시다.
이전 글인 <설정자와 Delegate로 사운드 온/오프 구현해보기> 를 읽어보셨나요?
해당 글에 나오는 Delegate를 응용해 페이드 효과를 주었습니다. 따라서 자세한 설명이 생략 될 수 있습니다.
using UnityEngine;
using System;
public class SlowMotionClass : MonoBehaviour
{
public static SlowMotionClass instance { get; protected set; }
void Awake()
{
if (instance != null && instance != this)
Destroy(this);
else
instance = this;
}
public float slowFactor = 0.05f;
public float slowLength = 4f;
public Action OnSlowMotionAudio;
public void DoSlowMotion()
{
Time.timeScale = slowFactor;
Time.fixedDeltaTime = Time.timeScale * 0.02f;
}
private void Update()
{
Time.timeScale += (1f / slowLength) * Time.unscaledDeltaTime;
Time.timeScale = Mathf.Clamp(Time.timeScale, 0f, 1f);
Time.fixedDeltaTime = Time.timeScale * 0.02f;
OnSlowMotionAudio.Invoke();
}
}
Delegate인 OnSlowMotionAudio를 추가해주었습니다.
Time.timeScale이 변경될 때 OnSlowMotionAudio도 동시에 호출됩니다.
다음은 AudioSource가 추가된 게임 오브젝트에 붙여 줄 스크립트입니다.
using UnityEngine;
public class SlowMotionAudio : MonoBehaviour
{
private void OnEnable()
{
SlowMotionClass.instance.OnSlowMotionAudio += OnSlowMotionAudio;
}
private void OnDisable()
{
SlowMotionClass.instance.OnSlowMotionAudio -= OnSlowMotionAudio;
}
void OnSlowMotionAudio()
{
GetComponent<AudioSource>().pitch = Time.timeScale;
}
}
게임 오브젝트가 활성화(OnEnable)되면 OnSlowMotionAudio에 OnSlowMotionAudio가 적용됩니다.
반대로 게임 오브젝트가 비활성화(OnDisable)되면 OnSlowMotionAudio가 제거됩니다.
이렇게 만든 스크립트를 AudioSource가 추가된 게임 오브젝트에 적용해줍니다.
SlowMotionClass의 Update가 호출되면, 활성화 된 AudioSource의 Pitch가 Time.timeScale의 속도에 맞춰 변경됩니다.
# Comment
장점
DoSlowMotion() 메소드 하나로 간편하게 시각적, 청각적 슬로우 모션 효과를 줄 수 있습니다.
단점
슬로우 모션이 진행되지 않을 때도 SlowMotionClass의 Update가 호출됩니다.
조건연산자 등을 통해 이를 제한할 수 있습니다. 다만, 해당 글에는 관련 내용이 적혀있지 않습니다.
개별 오브젝트의 속도를 제한하지 못합니다. Unity Scene의 속도를 조절합니다.
# Epilogue
슬로우 모션을 주는 방법은 이를 응용해서 다양하게 만들 수 있습니다.
해당 글에 적혀있지 않은 효과, 부족한 부분, 최적화 등 내용을 추가하여 더 멋진 슬로우 모션 효과를 만들어봅시다.
감사합니다!
# Reference
https://docs.unity3d.com/ScriptReference/Time.html
https://docs.unity3d.com/Manual/class-AudioSource.html
https://nanalistudios.tistory.com/10
'개발 > Unity3D' 카테고리의 다른 글
설정자와 Delegate로 사운드 온/오프 구현해보기 (0) | 2020.08.06 |
---|---|
Conditional Attribute (0) | 2020.07.31 |