2021-09-09 20:42:29 -04:00

180 lines
7.6 KiB
C#

using System;
namespace UnityEngine.Rendering.HighDefinition
{
/// <summary>Settings to use when capturing a probe.</summary>
[Serializable]
public struct ProbeCapturePositionSettings
{
/// <summary>Default value.</summary>
[Obsolete("Since 2019.3, use ProbeCapturePositionSettings.NewDefault() instead.")]
public static readonly ProbeCapturePositionSettings @default = default;
/// <summary>Default value.</summary>
/// <returns>The default value.</returns>
public static ProbeCapturePositionSettings NewDefault() => new ProbeCapturePositionSettings(
Vector3.zero, Quaternion.identity,
Vector3.zero, Quaternion.identity,
Matrix4x4.identity
);
/// <summary>The proxy position.</summary>
public Vector3 proxyPosition;
/// <summary>The proxy rotation.</summary>
public Quaternion proxyRotation;
/// <summary>
/// The reference position.
///
/// This additional information is used to compute the actual capture position. (usually, the viewer position) (<see cref="ProbeSettings.ProbeType"/>)
/// </summary>
public Vector3 referencePosition;
/// <summary>
/// The reference rotation.
///
/// This additional information is used to compute the actual capture position. (usually, the viewer rotation) (<see cref="ProbeSettings.ProbeType"/>)
/// </summary>
public Quaternion referenceRotation;
/// <summary>
/// The matrix for influence to world.
/// </summary>
public Matrix4x4 influenceToWorld;
/// <summary>Create a new settings with only the probe transform.</summary>
/// <param name="proxyPosition">The proxy position.</param>
/// <param name="proxyRotation">The proxy rotation.</param>
/// <param name="influenceToWorld">Influence to world matrix</param>
public ProbeCapturePositionSettings(
Vector3 proxyPosition,
Quaternion proxyRotation,
Matrix4x4 influenceToWorld
)
{
this.proxyPosition = proxyPosition;
this.proxyRotation = proxyRotation;
referencePosition = Vector3.zero;
referenceRotation = Quaternion.identity;
this.influenceToWorld = influenceToWorld;
}
/// <summary>Create new settings.</summary>
/// <param name="proxyPosition">The proxy position.</param>
/// <param name="proxyRotation">The proxy rotation.</param>
/// <param name="referencePosition">The reference position.</param>
/// <param name="referenceRotation">The reference rotation.</param>
/// <param name="influenceToWorld">Influence to world matrix</param>
public ProbeCapturePositionSettings(
Vector3 proxyPosition,
Quaternion proxyRotation,
Vector3 referencePosition,
Quaternion referenceRotation,
Matrix4x4 influenceToWorld
)
{
this.proxyPosition = proxyPosition;
this.proxyRotation = proxyRotation;
this.referencePosition = referencePosition;
this.referenceRotation = referenceRotation;
this.influenceToWorld = influenceToWorld;
}
/// <summary>
/// Compute the probe capture settings from an HDProbe and a reference transform.
/// </summary>
/// <param name="probe">The probe to extract settings from.</param>
/// <param name="reference">The reference transform. Use <c>null</c> when no reference is available.</param>
/// <returns>The probe capture position settings.</returns>
public static ProbeCapturePositionSettings ComputeFrom(HDProbe probe, Transform reference)
{
var referencePosition = Vector3.zero;
var referenceRotation = Quaternion.identity;
if (reference != null)
{
referencePosition = reference.position;
referenceRotation = reference.rotation;
}
else
{
if (probe.type == ProbeSettings.ProbeType.PlanarProbe)
{
var planar = (PlanarReflectionProbe)probe;
return ComputeFromMirroredReference(planar, planar.referencePosition);
}
}
var result = ComputeFrom(probe, referencePosition, referenceRotation);
return result;
}
/// <summary>
/// Compute the probe capture settings from an HDProbe and a reference position.
/// The position will be mirrored based on the mirror position of the probe.
/// </summary>
/// <param name="probe">The probe to extract settings from.</param>
/// <param name="referencePosition">The reference position to use.</param>
/// <returns>The probe capture position setting.</returns>
public static ProbeCapturePositionSettings ComputeFromMirroredReference(
HDProbe probe, Vector3 referencePosition
)
{
var positionSettings = ComputeFrom(
probe,
referencePosition, Quaternion.identity
);
// Set proper orientation for the reference rotation
var proxyMatrix = Matrix4x4.TRS(
positionSettings.proxyPosition,
positionSettings.proxyRotation,
Vector3.one
);
var mirrorPosition = proxyMatrix.MultiplyPoint(probe.settings.proxySettings.mirrorPositionProxySpace);
positionSettings.referenceRotation = Quaternion.LookRotation(mirrorPosition - positionSettings.referencePosition);
return positionSettings;
}
/// <summary>
/// Compute a hash based on the settings' values
/// </summary>
/// <returns></returns>
public Hash128 ComputeHash()
{
var h = new Hash128();
var h2 = new Hash128();
HashUtilities.QuantisedVectorHash(ref proxyPosition, ref h);
HashUtilities.QuantisedVectorHash(ref referencePosition, ref h2);
HashUtilities.AppendHash(ref h2, ref h);
var euler = proxyRotation.eulerAngles;
HashUtilities.QuantisedVectorHash(ref euler, ref h2);
HashUtilities.AppendHash(ref h2, ref h);
euler = referenceRotation.eulerAngles;
HashUtilities.QuantisedVectorHash(ref euler, ref h2);
HashUtilities.AppendHash(ref h2, ref h);
return h;
}
static ProbeCapturePositionSettings ComputeFrom(
HDProbe probe,
Vector3 referencePosition, Quaternion referenceRotation
)
{
var result = new ProbeCapturePositionSettings();
var proxyToWorld = probe.proxyToWorld;
result.proxyPosition = proxyToWorld.GetColumn(3);
// If reference position and proxy position is exactly the same, we end up in some degeneracies triggered
// by engine code when computing culling parameters. This is an extremely rare case, but can happen
// in editor when focusing on the planar probe. So if that happens, we offset them 0.1 mm apart.
if (Vector3.Distance(result.proxyPosition, referencePosition) < 1e-4f)
{
referencePosition += new Vector3(1e-4f, 1e-4f, 1e-4f);
}
result.proxyRotation = proxyToWorld.rotation;
result.referencePosition = referencePosition;
result.referenceRotation = referenceRotation;
result.influenceToWorld = probe.influenceToWorld;
return result;
}
}
}