using System;
using System.Collections.Generic;
using UnityEngine.Assertions;
using UnityEngine.Rendering;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{
///
/// Various utilities to perform rendering with HDRP
///
public static partial class HDRenderUtilities
{
/// Perform a rendering into .
///
/// How to perform standard rendering:
///
/// class StandardRenderingExample
/// {
/// public void Render()
/// {
/// // Copy default settings
/// var settings = CameraRenderSettings.Default;
/// // Adapt default settings to our custom usage
/// settings.position.position = new Vector3(0, 1, 0);
/// settings.camera.frustum.fieldOfView = 60.0f;
/// // Get our render target
/// var rt = new RenderTexture(128, 128, 1, GraphicsFormat.B8G8R8A8_SNorm);
/// HDRenderUtilities.Render(settings, rt);
/// // Do something with rt
/// rt.Release();
/// }
/// }
///
///
/// How to perform a cubemap rendering:
///
/// class CubemapRenderExample
/// {
/// public void Render()
/// {
/// // Copy default settings
/// var settings = CameraRenderSettings.Default;
/// // Adapt default settings to our custom usage
/// settings.position.position = new Vector3(0, 1, 0);
/// settings.camera.physical.iso = 800.0f;
/// // Frustum settings are ignored and driven by the cubemap rendering
/// // Get our render target
/// var rt = new RenderTexture(128, 128, 1, GraphicsFormat.B8G8R8A8_SNorm)
/// {
/// dimension = TextureDimension.Cube
/// };
/// // The TextureDimension is detected and the renderer will perform a cubemap rendering.
/// HDRenderUtilities.Render(settings, rt);
/// // Do something with rt
/// rt.Release();
/// }
/// }
///
///
/// Settings for the camera.
/// Position for the camera.
/// Target to render to.
/// Only used in the Editor fo cubemaps.
/// This is bitmask of only objects with these flags will be rendered
///
public static void Render(
CameraSettings settings,
CameraPositionSettings position,
Texture target,
uint staticFlags = 0
)
{
// Argument checking
if (target == null)
throw new ArgumentNullException(nameof(target));
var rtTarget = target as RenderTexture;
var cubeTarget = target as Cubemap;
switch (target.dimension)
{
case TextureDimension.Tex2D:
if (rtTarget == null)
throw new ArgumentException("'target' must be a RenderTexture when rendering into a 2D texture");
break;
case TextureDimension.Cube:
break;
default:
throw new ArgumentException("Rendering into a target of dimension "
+ $"{target.dimension} is not supported");
}
var camera = NewRenderingCamera();
try
{
camera.ApplySettings(settings);
camera.ApplySettings(position);
switch (target.dimension)
{
case TextureDimension.Tex2D:
{
#if DEBUG
Debug.LogWarning(
"A static flags bitmask was provided but this is ignored when rendering into a Tex2D"
);
#endif
Assert.IsNotNull(rtTarget);
camera.targetTexture = rtTarget;
camera.Render();
camera.targetTexture = null;
target.IncrementUpdateCount();
break;
}
case TextureDimension.Cube:
{
Assert.IsTrue(rtTarget != null || cubeTarget != null);
var canHandleStaticFlags = false;
#if UNITY_EDITOR
canHandleStaticFlags = true;
#endif
// ReSharper disable ConditionIsAlwaysTrueOrFalse
if (canHandleStaticFlags && staticFlags != 0)
// ReSharper restore ConditionIsAlwaysTrueOrFalse
{
#if UNITY_EDITOR
UnityEditor.Rendering.EditorCameraUtils.RenderToCubemap(
camera,
rtTarget,
-1,
(UnityEditor.StaticEditorFlags)staticFlags
);
#endif
}
else
{
// ReSharper disable ConditionIsAlwaysTrueOrFalse
if (!canHandleStaticFlags && staticFlags != 0)
// ReSharper restore ConditionIsAlwaysTrueOrFalse
{
Debug.LogWarning(
"A static flags bitmask was provided but this is ignored in player builds"
);
}
if (rtTarget != null)
camera.RenderToCubemap(rtTarget);
if (cubeTarget != null)
camera.RenderToCubemap(cubeTarget);
}
target.IncrementUpdateCount();
break;
}
}
}
finally
{
CoreUtils.Destroy(camera.gameObject);
}
}
public static void Render(
ProbeSettings settings,
ProbeCapturePositionSettings position,
Texture target,
bool forceFlipY = false,
bool forceInvertBackfaceCulling = false,
uint staticFlags = 0,
float referenceFieldOfView = 90
)
{
Render(
settings, position, target,
out _, out _,
forceFlipY,
forceInvertBackfaceCulling,
staticFlags,
referenceFieldOfView
);
}
static readonly Vector3[] s_GenerateRenderingSettingsFor_Rotations =
{
new Vector3(0, 90, 0),
new Vector3(0, 270, 0),
new Vector3(270, 0, 0),
new Vector3(90, 0, 0),
new Vector3(0, 0, 0),
new Vector3(0, 180, 0),
};
public static void GenerateRenderingSettingsFor(
ProbeSettings settings, ProbeCapturePositionSettings position,
List cameras, List cameraPositions,
bool forceFlipY = false, float referenceFieldOfView = 90
)
{
// Copy settings
ComputeCameraSettingsFromProbeSettings(
settings, position,
out var cameraSettings, out var cameraPositionSettings,
referenceFieldOfView
);
if (forceFlipY)
cameraSettings.flipYMode = HDAdditionalCameraData.FlipYMode.ForceFlipY;
switch (settings.type)
{
case ProbeSettings.ProbeType.PlanarProbe:
{
cameras.Add(cameraSettings);
cameraPositions.Add(cameraPositionSettings);
break;
}
case ProbeSettings.ProbeType.ReflectionProbe:
{
for (int i = 0; i < 6; ++i)
{
var cameraPositionCopy = cameraPositionSettings;
cameraPositionCopy.rotation = cameraPositionCopy.rotation * Quaternion.Euler(
s_GenerateRenderingSettingsFor_Rotations[i]
);
cameras.Add(cameraSettings);
cameraPositions.Add(cameraPositionCopy);
}
break;
}
}
}
public static void ComputeCameraSettingsFromProbeSettings(
ProbeSettings settings,
ProbeCapturePositionSettings position,
out CameraSettings cameraSettings,
out CameraPositionSettings cameraPositionSettings,
float referenceFieldOfView = 90
)
{
// Copy settings
cameraSettings = settings.camera;
cameraPositionSettings = CameraPositionSettings.@default;
// Update settings
ProbeSettingsUtilities.ApplySettings(
ref settings, ref position,
ref cameraSettings, ref cameraPositionSettings,
referenceFieldOfView
);
}
public static void Render(
ProbeSettings settings,
ProbeCapturePositionSettings position,
Texture target,
out CameraSettings cameraSettings,
out CameraPositionSettings cameraPositionSettings,
bool forceFlipY = false,
bool forceInvertBackfaceCulling = false,
uint staticFlags = 0,
float referenceFieldOfView = 90
)
{
// Copy settings
ComputeCameraSettingsFromProbeSettings(
settings, position,
out cameraSettings, out cameraPositionSettings
);
if (forceFlipY)
cameraSettings.flipYMode = HDAdditionalCameraData.FlipYMode.ForceFlipY;
if (forceInvertBackfaceCulling)
cameraSettings.invertFaceCulling = true;
// Perform rendering
Render(cameraSettings, cameraPositionSettings, target, staticFlags);
}
public static RenderTexture CreateReflectionProbeRenderTarget(int cubemapSize)
{
return new RenderTexture(cubemapSize, cubemapSize, 1, GraphicsFormat.R16G16B16A16_SFloat)
{
dimension = TextureDimension.Cube,
enableRandomWrite = true,
useMipMap = true,
autoGenerateMips = false
};
}
public static RenderTexture CreatePlanarProbeRenderTarget(int planarSize)
{
return new RenderTexture(planarSize, planarSize, 1, GraphicsFormat.R16G16B16A16_SFloat)
{
dimension = TextureDimension.Tex2D,
enableRandomWrite = true,
useMipMap = true,
autoGenerateMips = false
};
}
public static Cubemap CreateReflectionProbeTarget(int cubemapSize)
{
return new Cubemap(cubemapSize, GraphicsFormat.R16G16B16A16_SFloat, TextureCreationFlags.None);
}
static Camera NewRenderingCamera()
{
var go = new GameObject("__Render Camera");
var camera = go.AddComponent();
camera.cameraType = CameraType.Reflection;
go.AddComponent();
return camera;
}
static void FixSettings(
Texture target,
ref ProbeSettings settings, ref ProbeCapturePositionSettings position,
ref CameraSettings cameraSettings, ref CameraPositionSettings cameraPositionSettings
)
{
// Fix a specific case
// When rendering into a cubemap with Camera.RenderToCubemap
// Unity will flip the image during the read back before writing into the cubemap
// But in the end, the cubemap is flipped
// So we force in the HDRP to flip the last blit so we have the proper flipping.
RenderTexture rt = null;
if ((rt = target as RenderTexture) != null
&& rt.dimension == TextureDimension.Cube
&& settings.type == ProbeSettings.ProbeType.ReflectionProbe
&& SystemInfo.graphicsUVStartsAtTop)
cameraSettings.flipYMode = HDAdditionalCameraData.FlipYMode.ForceFlipY;
}
}
}