멀티프레임 렌더링 및 누적
패스트레이싱 같은 일부 렌더링 기술과 누적 모션 블러는 여러 중간 서브 프레임의 정보를 결합하여 최종적으로 "수렴된\” 프레임을 생성합니다. 각 중간 서브 프레임은 약간 다른 시점에 대응할 수 있으므로 오브젝트 회전이나 변형, 머티리얼, 조명의 변경 사항을 적절히 고려하는 물리 기반 누적 모션 블러를 효과적으로 계산할 수 있습니다.
고해상도 렌더 파이프라인(HDRP)은 서브 프레임 생성과 멀티프레임 렌더링 효과 수렴을 제어할 수 있도록 하는 스크립팅 API를 제공합니다. 특히 이 API로 중간 서브 프레임(샘플)의 개수와 각 프레임에 대응하는 시점을 제어할 수 있습니다. 또한 셔터 프로파일을 사용하여 각 서브 프레임의 가중치를 제어할 수 있습니다. 셔터 프로파일은 물리적 카메라가 셔터를 열고 닫는 속도를 설명합니다.
스크립팅 API는 경로 추적 동영상을 녹화할 때 특히 유용합니다. 일반적으로 씬을 편집하는 경우 패스트레이싱 수렴은 씬이 변경될 때마다 다시 시작하여 아티스트가 변경 사항을 빨리 시각화할 수 있게 해주는 대화형 편집 워크플로를 제공합니다. 하지만 그런 동작은 녹화 중에는 바람직하지 않습니다.
아래는 패스트레이싱과 누적 모션 블러가 있는 회전 중인 게임 오브젝트를 보여주는 이미지이며 이 오브젝트는 멀티프레임 녹화 API를 사용하여 녹화됩니다.
API 개요
녹화 API는 HDRP에서 사용할 수 있으며 여기엔 다음과 같이 세 가지 호출이 있습니다.
- BeginRecording: 멀티프레임 렌더를 시작하려는 경우 이 API를 호출합니다.
- PrepareNewSubFrame: 새로운 서브 프레임을 렌더링하기 전에 이 API를 호출합니다.
- EndRecording: 멀티 프레임 렌더를 멈추고자 하는 경우 이 API를 호출합니다.
유일하게 파라미터가 있는 호출은 BeginRecording입니다. 아래는 파라미터에 대한 설명입니다.
파라미터 | 설명 |
---|---|
Samples | 누적되는 서브 프레임의 개수입니다. 이 파라미터는 볼륨의 패스트레이싱 샘플의 개수를 오버라이드합니다. |
ShutterInterval | 두 개의 후속 프레임 간에 셔터가 열려있는 시간의 길이입니다. 값이 0이면 즉석 셔터(모션 블러 없음)가 생깁니다. 값이 1이면 두 후속 프레임 간에 시간적 차이가 없다는 의미입니다. |
ShutterProfile | 셔터 간격 동안 셔터 위치를 지정하는 애니메이션 커브입니다. 또는 셔터가 완전히 열려있는 시간과 셔터가 닫히기 시작하는 시간을 넣을 수도 있습니다. |
아래의 스크립트 예시는 이러한 API 호출을 사용하는 방법을 설명합니다.
스크립팅 API 예시
다음 예시는 스크립트의 멀티프레임 렌더링 API를 사용하여 패스트레이싱 그리고/또는 누적 모션 블러가 있는 수렴 애니메이션 시퀀스를 적절히 기록하는 방법을 설명합니다. 이를 사용하려면 씬의 카메라에 스크립트를 연결하고 컴포넌트의 컨텍스트 메뉴에서 “Start Recording”과 “Stop Recording” 동작을 클릭하면 됩니다.
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
public class FrameManager : MonoBehaviour
{
// The number of samples used for accumumation.
public int samples = 128;
[Range(0.0f, 1.0f)]
public float shutterInterval = 1.0f;
// The time during shutter interval when the shutter is fully open
[Range(0.0f, 1.0f)]
public float shutterFullyOpen = 0.25f;
// The time during shutter interval when the shutter begins closing.
[Range(0.0f, 1.0f)]
public float shutterBeginsClosing = 0.75f;
bool m_Recording = false;
int m_Iteration = 0;
int m_RecordedFrames = 0;
[ContextMenu("Start Recording")]
void BeginMultiframeRendering()
{
RenderPipelineManager.beginFrameRendering += PrepareSubFrameCallBack;
HDRenderPipeline renderPipeline = RenderPipelineManager.currentPipeline as HDRenderPipeline;
renderPipeline.BeginRecording(samples, shutterInterval, shutterFullyOpen, shutterBeginsClosing);
m_Recording = true;
m_Iteration = 0;
m_RecordedFrames = 0;
}
[ContextMenu("Stop Recording")]
void StopMultiframeRendering()
{
RenderPipelineManager.beginFrameRendering -= PrepareSubFrameCallBack;
HDRenderPipeline renderPipeline = RenderPipelineManager.currentPipeline as HDRenderPipeline;
renderPipeline?.EndRecording();
m_Recording = false;
}
void PrepareSubFrameCallBack(ScriptableRenderContext cntx, Camera[] cams)
{
HDRenderPipeline renderPipeline = RenderPipelineManager.currentPipeline as HDRenderPipeline;
if (renderPipeline != null && m_Recording)
{
renderPipeline.PrepareNewSubFrame();
m_Iteration++;
}
if (m_Recording && m_Iteration % samples == 0)
{
ScreenCapture.CaptureScreenshot($"frame_{m_RecordedFrames++}.png");
}
}
void OnDestroy()
{
if (m_Recording)
{
StopMultiframeRendering();
}
}
void OnValidate()
{
// Make sure the shutter will begin closing sometime after it is fully open (and not before)
shutterBeginsClosing = Mathf.Max(shutterFullyOpen, shutterBeginsClosing);
}
}
셔터 프로파일
BeginRecording 호출을 사용하여 카메라 셔터가 열리고 닫히는 속도를 지정할 수 있습니다. 카메라 셔터 속도는 보통 “셔터 프로파일”이라고 합니다. 다음은 여러 셔터 프로파일이 왼쪽에서 오른쪽으로 움직이는 파란색 구체의 모션 블러 형상에 미치는 영향을 보여주는 이미지입니다.
모든 경우에 구체의 속도는 동일합니다. 유일한 변경 사항은 셔터 프로파일뿐입니다. 프로파일 다이어그램의 가로 축은 시간을 나타내고 세로 축은 셔터 개방을 나타냅니다.
열기, 닫기 파라미터를 각각 (0,1), (1,1), (0.25, 0.75)로 설정하여 애니메이션 커브를 사용하지 않고도 처음 프로파일 세 개를 쉽게 정의할 수 있습니다. 마지막 프로파일은 애니메이션 커브를 사용해야 합니다.
이 예시에서 느리게 프로파일을 열어 모션 블러에 대한 모션 자취 형상을 만드는 것을 볼 수 있습니다. 이 방식은 아티스트에게 더 바람직할 수 있습니다. 반면 프로파일을 부드럽게 열고 닫으면 프로파일을 느리게 연 프로파일이나 균일한 프로파일보다 더 부드러운 애니메이션을 만듭니다.
제한 사항
멀티프레임 렌더링 API는 씬의 Time.timeScale
을 내부적으로 변경합니다. 이는 다음을 의미합니다.
- 카메라마다 다양한 누적 모션 블러 파라미터를 가질 수 없습니다.
- 프레임마다 이 파라미터를 이미 수정한 프로젝트는 이 기능과 호환되지 않습니다.