using System;
using System.Diagnostics;
using System.Collections.Generic;
namespace UnityEngine.Rendering.HighDefinition
{
///
/// This attribute is used to associate a unique ID to a sky class.
/// This is needed to be able to automatically register sky classes and avoid collisions and refactoring class names causing data compatibility issues.
///
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class SkyUniqueID : Attribute
{
internal readonly int uniqueID;
///
/// Attribute SkyUniqueID constructor.
///
/// Sky unique ID. Needs to be different from all other registered unique IDs.
public SkyUniqueID(int uniqueID)
{
this.uniqueID = uniqueID;
}
}
///
/// Environment Update volume parameter.
///
[Serializable, DebuggerDisplay(k_DebuggerDisplay)]
public sealed class EnvUpdateParameter : VolumeParameter
{
///
/// Environment Update parameter constructor.
///
/// Environment Update Mode parameter.
/// Initial override state.
public EnvUpdateParameter(EnvironmentUpdateMode value, bool overrideState = false)
: base(value, overrideState) { }
}
///
/// Sky Intensity Mode.
///
public enum SkyIntensityMode
{
/// Intensity is expressed as an exposure.
Exposure,
/// Intensity is expressed in lux.
Lux,
/// Intensity is expressed as a multiplier.
Multiplier,
}
///
/// Backplate Type for HDRISKy.
///
public enum BackplateType
{
/// Shape of backplate is a Disc.
Disc,
/// Shape of backplate is a Rectangle.
Rectangle,
/// Shape of backplate is a Ellispe.
Ellipse,
/// Shape of backplate is a Infinite Plane.
Infinite
}
///
/// Backplate Type volume parameter.
///
[Serializable, DebuggerDisplay(k_DebuggerDisplay)]
public sealed class BackplateTypeParameter : VolumeParameter
{
///
/// Backplate Type volume parameter constructor.
///
/// Backplate Type parameter.
/// Initial override state.
public BackplateTypeParameter(BackplateType value, bool overrideState = false)
: base(value, overrideState) { }
}
///
/// Sky Intensity volume parameter.
///
[Serializable, DebuggerDisplay(k_DebuggerDisplay)]
public sealed class SkyIntensityParameter : VolumeParameter
{
///
/// Sky Intensity volume parameter constructor.
///
/// Sky Intensity parameter.
/// Initial override state.
public SkyIntensityParameter(SkyIntensityMode value, bool overrideState = false)
: base(value, overrideState) { }
}
///
/// Base class for custom Sky Settings.
///
public abstract class SkySettings : VolumeComponent
{
/// Rotation of the sky.
[Tooltip("Sets the rotation of the sky.")]
public ClampedFloatParameter rotation = new ClampedFloatParameter(0.0f, 0.0f, 360.0f);
/// Intensity mode of the sky.
[Tooltip("Specifies the intensity mode HDRP uses for the sky.")]
public SkyIntensityParameter skyIntensityMode = new SkyIntensityParameter(SkyIntensityMode.Exposure);
/// Exposure of the sky.
[Tooltip("Sets the exposure of the sky in EV.")]
public FloatParameter exposure = new FloatParameter(0.0f);
/// Intensity Multipler of the sky.
[Tooltip("Sets the intensity multiplier for the sky.")]
public MinFloatParameter multiplier = new MinFloatParameter(1.0f, 0.0f);
/// Informative helper that displays the relative intensity (in Lux) for the current HDR texture set in HDRI Sky.
[Tooltip("Informative helper that displays the relative intensity (in Lux) for the current HDR texture set in HDRI Sky.")]
public MinFloatParameter upperHemisphereLuxValue = new MinFloatParameter(1.0f, 0.0f);
/// Informative helper that displays Show the color of Shadow.
[Tooltip("Informative helper that displays Show the color of Shadow.")]
public Vector3Parameter upperHemisphereLuxColor = new Vector3Parameter(new Vector3(0, 0, 0));
/// Absolute intensity (in lux) of the sky.
[Tooltip("Sets the absolute intensity (in Lux) of the current HDR texture set in HDRI Sky. Functions as a Lux intensity multiplier for the sky.")]
public FloatParameter desiredLuxValue = new FloatParameter(20000);
/// Update mode of the sky.
[Tooltip("Specifies when HDRP updates the environment lighting. When set to OnDemand, use HDRenderPipeline.RequestSkyEnvironmentUpdate() to request an update.")]
public EnvUpdateParameter updateMode = new EnvUpdateParameter(EnvironmentUpdateMode.OnChanged);
/// In case of real-time update mode, time between updates. 0 means every frame.
[Tooltip("Sets the period, in seconds, at which HDRP updates the environment ligting (0 means HDRP updates it every frame).")]
public MinFloatParameter updatePeriod = new MinFloatParameter(0.0f, 0.0f);
/// True if the sun disk should be included in the baking information (where available).
[Tooltip("When enabled, HDRP uses the Sun Disk in baked lighting.")]
public BoolParameter includeSunInBaking = new BoolParameter(false);
static Dictionary skyUniqueIDs = new Dictionary();
///
/// Returns the hash code of the sky parameters.
///
/// The camera we want to use to compute the hash of the sky.
/// The hash code of the sky parameters.
virtual public int GetHashCode(Camera camera)
{
// By default we don't need to consider the camera position.
return GetHashCode();
}
///
/// Returns the hash code of the sky parameters. When used with PBR Sky please use the GetHashCode variant that takes a camera as parameter.
///
/// The hash code of the sky parameters.
public override int GetHashCode()
{
unchecked
{
#if UNITY_2019_3 // In 2019.3, when we call GetHashCode on a VolumeParameter it generate garbage (due to the boxing of the generic parameter)
// UpdateMode and period should not be part of the hash as they do not influence rendering itself.
int hash = 13;
hash = hash * 23 + rotation.value.GetHashCode();
hash = hash * 23 + exposure.value.GetHashCode();
hash = hash * 23 + multiplier.value.GetHashCode();
hash = hash * 23 + desiredLuxValue.value.GetHashCode();
hash = hash * 23 + skyIntensityMode.value.GetHashCode();
hash = hash * 23 + includeSunInBaking.value.GetHashCode();
hash = hash * 23 + rotation.overrideState.GetHashCode();
hash = hash * 23 + exposure.overrideState.GetHashCode();
hash = hash * 23 + multiplier.overrideState.GetHashCode();
hash = hash * 23 + desiredLuxValue.overrideState.GetHashCode();
hash = hash * 23 + skyIntensityMode.overrideState.GetHashCode();
hash = hash * 23 + includeSunInBaking.overrideState.GetHashCode();
#else
// UpdateMode and period should not be part of the hash as they do not influence rendering itself.
int hash = 13;
hash = hash * 23 + rotation.GetHashCode();
hash = hash * 23 + exposure.GetHashCode();
hash = hash * 23 + multiplier.GetHashCode();
hash = hash * 23 + desiredLuxValue.GetHashCode();
hash = hash * 23 + skyIntensityMode.GetHashCode();
hash = hash * 23 + includeSunInBaking.GetHashCode();
#endif
return hash;
}
}
///
/// Returns the sky type unique ID.
/// Use this to override the skyType in the Visual Environment volume component.
///
/// Type of the sky.
/// The unique ID for the requested sky type.
public static int GetUniqueID()
{
return GetUniqueID(typeof(T));
}
///
/// Returns the sky type unique ID.
/// Use this to override the skyType in the Visual Environment volume component.
///
/// Type of the sky.
/// The unique ID for the requested sky type.
public static int GetUniqueID(Type type)
{
int uniqueID;
if (!skyUniqueIDs.TryGetValue(type, out uniqueID))
{
var uniqueIDs = type.GetCustomAttributes(typeof(SkyUniqueID), false);
uniqueID = (uniqueIDs.Length == 0) ? -1 : ((SkyUniqueID)uniqueIDs[0]).uniqueID;
skyUniqueIDs[type] = uniqueID;
}
return uniqueID;
}
///
/// Returns the sky intensity as determined by this SkySetting.
///
/// The sky intensity.
public float GetIntensityFromSettings()
{
float skyIntensity = 1.0f;
switch (skyIntensityMode.value)
{
case SkyIntensityMode.Exposure:
// Note: Here we use EV100 of sky as a multiplier, so it is the opposite of when use with a Camera
// because for sky/light, higher EV mean brighter, but for camera higher EV mean darker scene
skyIntensity *= ColorUtils.ConvertEV100ToExposure(-exposure.value);
break;
case SkyIntensityMode.Multiplier:
skyIntensity *= multiplier.value;
break;
case SkyIntensityMode.Lux:
skyIntensity *= desiredLuxValue.value / Mathf.Max(upperHemisphereLuxValue.value, 1e-5f);
break;
}
return skyIntensity;
}
///
/// Determines if the SkySettings is significantly divergent from another. This is going to be used to determine whether
/// to reset completely the ambient probe instead of using previous one when waiting for current data upon changes.
/// Override this to have a per-sky specific heuristic.
///
/// The settings to compare with.
/// Whether the settings are deemed very different.
public virtual bool SignificantlyDivergesFrom(SkySettings otherSettings)
{
if (otherSettings == null || otherSettings.GetSkyRendererType() != GetSkyRendererType())
return true;
float thisIntensity = GetIntensityFromSettings();
float otherIntensity = otherSettings.GetIntensityFromSettings();
// This is an arbitrary difference threshold. This needs to be re-evaluated in case it is proven problematic
float intensityRatio = thisIntensity > otherIntensity ? (thisIntensity / otherIntensity) : (otherIntensity / thisIntensity);
const float ratioThreshold = 3.0f;
return intensityRatio > ratioThreshold;
}
///
/// Returns the class type of the SkyRenderer associated with this Sky Settings.
///
/// The class type of the SkyRenderer associated with this Sky Settings.
public abstract Type GetSkyRendererType();
// Keeping this API internal for now.
// It's required for PBR sky to interact correctly with baking but we are not 100% set on the interface yet.
internal virtual Vector3 EvaluateAtmosphericAttenuation(Vector3 sunDirection, Vector3 cameraPosition)
{
return Vector3.one;
}
}
}