임의 출력 변수
임의 출력 변수(AOV)는 HDRP 카메라가 생성할 수 있는 추가 이미지입니다. AOV는 픽셀마다 추가 정보를 출력할 수 있으며 추후에 합성이나 추가 이미지 프로세싱(예: 노이즈 감소)에 사용할 수 있습니다.
다음은 세 가지 AOV에 대한 예시이며 왼쪽부터 오른쪽으로 각 픽셀의 알베도, 노멀, 오브젝트 ID입니다.
HDRP에서는 다음의 방식으로 AOV에 접근하고 설정할 수 있습니다.
- HDRP 컴포지터 툴 사용
- Unity 레코더 패키지와 AOV 레코더 패키지 사용
- 스크립팅 API를 사용하여 씬의 모든 HDRP 카메라에서 커스텀 AOV 요청 설정
처음 두 옵션이 사용자 인터페이스에 제공하는 AOV는 선택이 제한적이지만 세 번째 옵션은 HDRP 카메라가 출력할 수 있는 데이터에 유연성을 훨씬 더 많이 허용합니다.
머티리얼 프로퍼티 AOV
다음은 AOV API를 사용하여 액세스할 수 있는 머티리얼 프로퍼티 리스트입니다.
머티리얼 프로퍼티 | 설명 |
---|---|
Normal | 표면 알베도를 출력합니다. |
Albedo | 표면 노멀을 출력합니다. |
Smoothness | 표면 평활도를 출력합니다. |
Ambient Occlusion | 앰비언트 오클루전을 출력합니다(AxF의 경우 해당 없음). 참고: 여기서 출력하는 앰비언트 오클루전에는 앰비언트 오클루전 오버라이드에서 레이트레이싱된/스크린 공간 앰비언트 오클루전이 포함되어 있지 않습니다. 여기에는 씬에 있는 머티리얼의 앰비언트 오클루전만 포함됩니다. |
Specular | 표면 스페큘러를 출력합니다. |
Alpha | 표면 알파(픽셀 커버리지)를 출력합니다. |
AOV가 있는 조명 선택
AOV를 사용하여 선택된 광원 리스트에서 기여도를 출력하거나 AOV를 사용하여 조명의 특정 컴포넌트만 출력할 수 있습니다.
조명 프로퍼티 | 설명 |
---|---|
DiffuseOnly | 산란광만 렌더링합니다(직접과 간접 모두). |
SpecularOnly | 스페큘러 조명만 렌더링합니다(직접과 간접 모두). |
DirectDiffuseOnly | 직접 산란광만 렌더링합니다. |
DirectSpecularOnly | 직접 스페큘러 조명만 렌더링합니다. |
IndirectDiffuseOnly | 간접 산란광만 렌더링합니다. |
ReflectionOnly | 리플렉션만 렌더링합니다. |
RefractionOnly | 굴절만 렌더링합니다. |
EmissiveOnly | 이미시브 조명만 렌더링합니다. |
커스텀 패스 AOV
마지막으로 AOV를 사용하여 커스텀 패스 결과를 출력할 수 있습니다. 특히 모든 커스텀 패스 주입 지점에서 활성화되어 있는 모든 커스텀 패스의 누적 결과를 출력할 수 있습니다. 이는 씬 게임 오브젝트의 오브젝트 ID 같이 커스텀 패스가 계산하는 임의 정보를 출력하는 데 유용할 수 있습니다.
스크립팅 API 예시
다음의 예시 스크립트는 HDRP 카메라의 알베도 AOV를 출력하고 .png 이미지 시퀀스로 디스크에 결과 프레임을 저장합니다. 예시 스크립트를 사용하려면 HDRP 카메라에 연결하고 플레이 모드로 진입합니다.
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.Rendering.HighDefinition.Attributes;
public class AovRecorder : MonoBehaviour
{
RTHandle m_TmpRT; // The RTHandle used to render the AOV
Texture2D m_ReadBackTexture;
int m_Frames = 0;
// Start is called before the first frame update
void Start()
{
var camera = gameObject.GetComponent<Camera>();
if (camera != null)
{
var hdAdditionalCameraData = gameObject.GetComponent<HDAdditionalCameraData>();
if (hdAdditionalCameraData != null)
{
// initialize a new AOV request
var aovRequest = AOVRequest.NewDefault();
AOVBuffers[] aovBuffers = null;
CustomPassAOVBuffers[] customPassAovBuffers = null;
// Request an AOV with the surface albedo
aovRequest.SetFullscreenOutput(MaterialSharedProperty.Albedo);
aovBuffers = new[] { AOVBuffers.Color };
// Allocate the RTHandle that will store the intermediate results
m_TmpRT = RTHandles.Alloc(camera.pixelWidth, camera.pixelHeight);
// Add the request to a new AOVRequestBuilder
var aovRequestBuilder = new AOVRequestBuilder();
aovRequestBuilder.Add(aovRequest,
bufferId => m_TmpRT,
null,
aovBuffers,
customPassAovBuffers,
bufferId => m_TmpRT,
(cmd, textures, customPassTextures, properties) =>
{
// callback to read back the AOV data and write them to disk
if (textures.Count > 0)
{
m_ReadBackTexture = m_ReadBackTexture ?? new Texture2D(camera.pixelWidth, camera.pixelHeight, TextureFormat.RGBAFloat, false);
RenderTexture.active = textures[0].rt;
m_ReadBackTexture.ReadPixels(new Rect(0, 0, camera.pixelWidth, camera.pixelHeight), 0, 0, false);
m_ReadBackTexture.Apply();
RenderTexture.active = null;
byte[] bytes = m_ReadBackTexture.EncodeToPNG();
System.IO.File.WriteAllBytes($"output_{m_Frames++}.png", bytes);
}
});
// Now build the AOV request
var aovRequestDataCollection = aovRequestBuilder.Build();
// And finally set the request to the camera
hdAdditionalCameraData.SetAOVRequests(aovRequestDataCollection);
}
}
}
}