浏览代码

Light intensity now works with timeline and animators

/main
Antoine Lelievre 6 年前
当前提交
94299904
共有 4 个文件被更改,包括 211 次插入218 次删除
  1. 109
      com.unity.render-pipelines.high-definition/HDRP/Editor/Lighting/HDLightEditor.cs
  2. 45
      com.unity.render-pipelines.high-definition/HDRP/Editor/Upgraders/UpgradeMenuItem.cs
  3. 232
      com.unity.render-pipelines.high-definition/HDRP/Lighting/Light/HDAdditionalLightData.cs
  4. 43
      com.unity.render-pipelines.high-definition/HDRP/Lighting/LightUtils.cs

109
com.unity.render-pipelines.high-definition/HDRP/Editor/Lighting/HDLightEditor.cs


sealed class SerializedLightData
{
public SerializedProperty intensity;
public SerializedProperty directionalIntensity;
public SerializedProperty punctualIntensity;
public SerializedProperty areaIntensity;
public SerializedProperty enableSpotReflector;
public SerializedProperty spotInnerPercent;
public SerializedProperty lightDimmer;

using (var o = new PropertyFetcher<HDAdditionalLightData>(m_SerializedAdditionalLightData))
m_AdditionalLightData = new SerializedLightData
{
directionalIntensity = o.Find(x => x.directionalIntensity),
punctualIntensity = o.Find(x => x.punctualIntensity),
areaIntensity = o.Find(x => x.areaIntensity),
intensity = o.Find(x => x.editorLightIntensity),
intensity = o.Find(x => x.displayLightIntensity),
enableSpotReflector = o.Find(x => x.enableSpotReflector),
spotInnerPercent = o.Find(x => x.m_InnerSpotPercent),
lightDimmer = o.Find(x => x.lightDimmer),

if (EditorGUI.EndChangeCheck())
{
UpdateLightIntensity();
((Light)target).SetLightDirty(); // Should be apply only to parameter that's affect GI, but make the code cleaner
UpdateLightIntensityUnit();
// Caution: this function must match the one in HDAdditionalLightData.ConvertPhysicalLightIntensityToLightIntensity - any change need to be replicated
void UpdateLightIntensity()
void UpdateLightIntensityUnit()
//TOOD: TMP stuff, waiting for the emissive mesh to be merged
m_SerializedAdditionalLightData.ApplyModifiedProperties();
((Light)target).GetComponent<HDAdditionalLightData>().RefreshLightIntensity();
// Clamp negative values.
/*m_AdditionalLightData.directionalIntensity.floatValue = Mathf.Max(0, m_AdditionalLightData.directionalIntensity.floatValue);
m_AdditionalLightData.punctualIntensity.floatValue = Mathf.Max(0, m_AdditionalLightData.punctualIntensity.floatValue);
m_AdditionalLightData.areaIntensity.floatValue = Mathf.Max(0, m_AdditionalLightData.areaIntensity.floatValue);
switch (m_LightShape)
{
case LightShape.Directional:
settings.intensity.floatValue = m_AdditionalLightData.directionalIntensity.floatValue;
break;
case LightShape.Point:
settings.intensity.floatValue = LightUtils.ConvertPointLightIntensity(m_AdditionalLightData.punctualIntensity.floatValue);
break;
case LightShape.Spot:
// Spot should used conversion which take into account the angle, and thus the intensity vary with angle.
// This is not easy to manipulate for lighter, so we simply consider any spot light as just occluded point light. So reuse the same code.
var spotLightShape = (SpotLightShape)m_AdditionalLightData.spotLightShape.enumValueIndex;
if (m_AdditionalLightData.enableSpotReflector.boolValue)
{
if (spotLightShape == SpotLightShape.Cone)
{
settings.intensity.floatValue = LightUtils.ConvertSpotLightIntensity(m_AdditionalLightData.punctualIntensity.floatValue, settings.spotAngle.floatValue * Mathf.Deg2Rad, true);
}
else if (spotLightShape == SpotLightShape.Pyramid)
{
float angleA, angleB;
LightUtils.CalculateAnglesForPyramid(m_AdditionalLightData.aspectRatio.floatValue, settings.spotAngle.floatValue,
out angleA, out angleB);
settings.intensity.floatValue = LightUtils.ConvertFrustrumLightIntensity(m_AdditionalLightData.punctualIntensity.floatValue, angleA, angleB);
}
else // Box shape, fallback to punctual light.
{
settings.intensity.floatValue = LightUtils.ConvertPointLightIntensity(m_AdditionalLightData.punctualIntensity.floatValue);
}
}
else // Reflector disabled, fallback to punctual light.
{
settings.intensity.floatValue = LightUtils.ConvertPointLightIntensity(m_AdditionalLightData.punctualIntensity.floatValue);
}
break;
case LightShape.Rectangle:
settings.intensity.floatValue = LightUtils.ConvertRectLightIntensity(m_AdditionalLightData.areaIntensity.floatValue, m_AdditionalLightData.shapeWidth.floatValue, m_AdditionalLightData.shapeHeight.floatValue);
break;
case LightShape.Line:
settings.intensity.floatValue = LightUtils.CalculateLineLightIntensity(m_AdditionalLightData.areaIntensity.floatValue, m_AdditionalLightData.shapeWidth.floatValue);
break;
}*/
if (m_LightShape == LightShape.Directional)
m_AdditionalLightData.lightUnit.enumValueIndex = (int)DirectionalLightUnit.Lux;
else
m_AdditionalLightData.lightUnit.enumValueIndex = (int)LightUnit.Lumen;
}
LightUnit LightIntensityUnitPopup(LightShape shape)

void ConvertLightIntensity(LightUnit oldLightUnit, LightUnit newLightUnit)
{
float intensity = m_AdditionalLightData.intensity.floatValue;
// For punctual lights
if (oldLightUnit == LightUnit.Lumen && newLightUnit == LightUnit.Candela)
intensity = LightUtils.ConvertPointLightLumenToCandela(intensity);
if (oldLightUnit == LightUnit.Candela && newLightUnit == LightUnit.Lumen)
intensity = LightUtils.ConvertPointLightCandelaToLumen(intensity);
// For area lights
if (oldLightUnit == LightUnit.Lumen && newLightUnit == LightUnit.Luminance)
{
if (m_LightShape == LightShape.Rectangle)
intensity = LightUtils.ConvertRectLightLumenToLuminance(intensity, m_AdditionalLightData.shapeWidth.floatValue, m_AdditionalLightData.shapeHeight.floatValue);
else if (m_LightShape == LightShape.Line)
intensity = LightUtils.CalculateLineLightLumenToLuminance(intensity, m_AdditionalLightData.shapeWidth.floatValue);
}
if (oldLightUnit == LightUnit.Luminance && newLightUnit == LightUnit.Lumen)
{
if (m_LightShape == LightShape.Rectangle)
intensity = LightUtils.ConvertRectLightLuminanceToLumen(intensity, m_AdditionalLightData.shapeWidth.floatValue, m_AdditionalLightData.shapeHeight.floatValue);
else if (m_LightShape == LightShape.Line)
intensity = LightUtils.CalculateLineLightLuminanceToLumen(intensity, m_AdditionalLightData.shapeWidth.floatValue);
}
m_AdditionalLightData.intensity.floatValue = intensity;
}
void DrawLightSettings()

EditorGUI.BeginChangeCheck();
HDAdditionalLightData d = (target as Light).GetComponent<HDAdditionalLightData>();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(m_AdditionalLightData.intensity, s_Styles.lightIntensity);
m_AdditionalLightData.lightUnit.enumValueIndex = (int)LightIntensityUnitPopup(m_LightShape);

var spotLightShape = (SpotLightShape)m_AdditionalLightData.spotLightShape.enumValueIndex;
if (spotLightShape == SpotLightShape.Cone || spotLightShape == SpotLightShape.Pyramid)
EditorGUILayout.PropertyField(m_AdditionalLightData.enableSpotReflector, s_Styles.enableSpotReflector);
}
if (EditorGUI.EndChangeCheck())
{
UpdateLightIntensity();
}
settings.DrawBounceIntensity();

45
com.unity.render-pipelines.high-definition/HDRP/Editor/Upgraders/UpgradeMenuItem.cs


{
public class UpgradeMenuItems
{
//[MenuItem("Internal/HDRenderPipeline/Upgrade Scene Light Intensity to physical light unit", priority = CoreUtils.editMenuPriority2)]
static void UpgradeLightsPLU()
{
Light[] lights = Resources.FindObjectsOfTypeAll<Light>();
foreach (var l in lights)
{
var add = l.GetComponent<HDAdditionalLightData>();
if (add == null)
{
continue;
}
// We only need to update the new intensity parameters on additional data, no need to change intensity
if (add.lightTypeExtent == LightTypeExtent.Punctual)
{
switch (l.type)
{
case LightType.Point:
add.punctualIntensity = l.intensity / LightUtils.ConvertPointLightIntensity(1.0f);
break;
case LightType.Spot:
add.punctualIntensity = l.intensity / LightUtils.ConvertPointLightIntensity(1.0f);
break;
case LightType.Directional:
add.directionalIntensity = l.intensity;
break;
}
}
else if (add.lightTypeExtent == LightTypeExtent.Rectangle)
{
add.areaIntensity = l.intensity / LightUtils.ConvertRectLightIntensity(1.0f, add.shapeWidth, add.shapeHeight);
}
else if (add.lightTypeExtent == LightTypeExtent.Line)
{
add.areaIntensity = l.intensity / LightUtils.CalculateLineLightIntensity(1.0f, add.shapeWidth);
}
}
var scene = SceneManager.GetActiveScene();
EditorSceneManager.MarkSceneDirty(scene);
}
//[MenuItem("Internal/HDRenderPipeline/Update/Update material for subsurface")]
static void UpdateMaterialForSubsurface()

232
com.unity.render-pipelines.high-definition/HDRP/Lighting/Light/HDAdditionalLightData.cs


//@TODO: We should continuously move these values
// into the engine when we can see them being generally useful
[RequireComponent(typeof(Light))]
public class HDAdditionalLightData : MonoBehaviour
[ExecuteInEditMode]
public class HDAdditionalLightData : MonoBehaviour, ISerializationCallbackReceiver
public const float currentVersion = 1.1f;
public float version = 1.0f;
public float version = currentVersion;
[System.Obsolete("directionalIntensity is deprecated, use intensity and lightUnit instead")]
[System.Obsolete("punctualIntensity is deprecated, use intensity and lightUnit instead")]
[System.Obsolete("areaIntensity is deprecated, use intensity and lightUnit instead")]
public const float k_DefaultDirectionalLightIntensity = Mathf.PI; // In lux
public const float k_DefaultPunctualLightIntensity = 600.0f; // In lumens
public const float k_DefaultAreaLightIntensity = 200.0f; // In lumens
get { return editorLightIntensity; }
get { return displayLightIntensity; }
set { SetLightIntensity(value); }
}

public bool useOldInspector = false;
public bool featuresFoldout = true;
public bool showAdditionalSettings = false;
public float editorLightIntensity;
public float displayLightIntensity;
// We nee all those variables to make timeline and the animator record the intensity value
[System.NonSerialized]
float oldDisplayLightIntensity;
[System.NonSerialized]
float oldSpotAngle;
[System.NonSerialized]
bool oldEnableSpotReflector;
// Runtime datas used to compute light intensity
Light _light;

void SetLightIntensity(float intensity)
{
switch (lightTypeExtent)
displayLightIntensity = intensity;
if (lightUnit == LightUnit.Lumen)
case LightTypeExtent.Punctual:
SetLightIntensityPunctual(intensity);
break;
case LightTypeExtent.Line:
if (lightUnit == LightUnit.Lumen)
m_Light.intensity = LightUtils.CalculateLineLightIntensity(intensity, shapeWidth);
else
m_Light.intensity = intensity;
break;
case LightTypeExtent.Rectangle:
if (lightUnit == LightUnit.Lumen)
m_Light.intensity = LightUtils.ConvertRectLightIntensity(intensity, shapeWidth, shapeHeight);
else
m_Light.intensity = intensity;
break;
switch (lightTypeExtent)
{
case LightTypeExtent.Punctual:
SetLightIntensityPunctual(intensity);
break;
case LightTypeExtent.Line:
m_Light.intensity = LightUtils.CalculateLineLightLumenToLuminance(intensity, shapeWidth);
break;
case LightTypeExtent.Rectangle:
m_Light.intensity = LightUtils.ConvertRectLightLumenToLuminance(intensity, shapeWidth, shapeHeight);
break;
}
else
m_Light.intensity = intensity;
m_Light.SetLightDirty(); // Should be apply only to parameter that's affect GI, but make the code cleaner
}
void SetLightIntensityPunctual(float intensity)

if (lightUnit == LightUnit.Candela)
m_Light.intensity = intensity;
else
m_Light.intensity = LightUtils.ConvertPointLightIntensity(intensity);
m_Light.intensity = LightUtils.ConvertPointLightLumenToCandela(intensity);
break;
case LightType.Spot:
if (lightUnit == LightUnit.Candela)

if (spotLightShape == SpotLightShape.Cone)
{
m_Light.intensity = LightUtils.ConvertSpotLightIntensity(intensity, m_Light.spotAngle * Mathf.Deg2Rad, true);
m_Light.intensity = LightUtils.ConvertSpotLightLumenToCandela(intensity, m_Light.spotAngle * Mathf.Deg2Rad, true);
}
else if (spotLightShape == SpotLightShape.Pyramid)
{

m_Light.intensity = LightUtils.ConvertFrustrumLightIntensity(intensity, angleA, angleB);
m_Light.intensity = LightUtils.ConvertFrustrumLightLumenToCandela(intensity, angleA, angleB);
m_Light.intensity = LightUtils.ConvertPointLightIntensity(intensity);
m_Light.intensity = LightUtils.ConvertPointLightLumenToCandela(intensity);
m_Light.intensity = LightUtils.ConvertPointLightIntensity(intensity);
m_Light.intensity = LightUtils.ConvertPointLightLumenToCandela(intensity);
}
// Given a correlated color temperature (in Kelvin), estimate the RGB equivalent. Curve fit error is max 0.008.
Color CorrelatedColorTemperatureToRGB(float temperature)
{
float r, g, b;
// Temperature must fall between 1000 and 40000 degrees
// The fitting require to divide kelvin by 1000 (allow more precision)
float kelvin = Mathf.Clamp(temperature, 1000.0f, 40000.0f) / 1000.0f;
float kelvin2 = kelvin * kelvin;
// Using 6570 as a pivot is an approximation, pivot point for red is around 6580 and for blue and green around 6560.
// Calculate each color in turn (Note, clamp is not really necessary as all value belongs to [0..1] but can help for extremum).
// Red
r = kelvin < 6.570f ? 1.0f : Mathf.Clamp((1.35651f + 0.216422f * kelvin + 0.000633715f * kelvin2) / (-3.24223f + 0.918711f * kelvin), 0.0f, 1.0f);
// Green
g = kelvin < 6.570f ?
Mathf.Clamp((-399.809f + 414.271f * kelvin + 111.543f * kelvin2) / (2779.24f + 164.143f * kelvin + 84.7356f * kelvin2), 0.0f, 1.0f) :
Mathf.Clamp((1370.38f + 734.616f * kelvin + 0.689955f * kelvin2) / (-4625.69f + 1699.87f * kelvin), 0.0f, 1.0f);
//Blue
b = kelvin > 6.570f ? 1.0f : Mathf.Clamp((348.963f - 523.53f * kelvin + 183.62f * kelvin2) / (2848.82f - 214.52f * kelvin + 78.8614f * kelvin2), 0.0f, 1.0f);
return new Color(r, g, b, 1.0f);
}
#if UNITY_EDITOR

DrawGizmos(true);
}
public void RefreshLightIntensity()
{
// The editor can only access editorLightIntensity (because of SerializedProperties) so we update the intensity to get the real value
intensity = editorLightIntensity;
}
#endif
// Caution: this function must match the one in HDLightEditor.UpdateLightIntensity - any change need to be replicated
public void ConvertPhysicalLightIntensityToLightIntensity()
void LateUpdate()
var light = m_Light;
if (lightTypeExtent == LightTypeExtent.Punctual)
{
switch (light.type)
{
case LightType.Directional:
light.intensity = Mathf.Max(0, directionalIntensity);
break;
case LightType.Point:
light.intensity = LightUtils.ConvertPointLightIntensity(Mathf.Max(0, punctualIntensity));
break;
case LightType.Spot:
if (enableSpotReflector)
{
if (spotLightShape == SpotLightShape.Cone)
{
light.intensity = LightUtils.ConvertSpotLightIntensity(Mathf.Max(0, punctualIntensity), light.spotAngle * Mathf.Deg2Rad, true);
}
else if (spotLightShape == SpotLightShape.Pyramid)
{
float angleA, angleB;
LightUtils.CalculateAnglesForPyramid(aspectRatio, light.spotAngle,
out angleA, out angleB);
light.intensity = LightUtils.ConvertFrustrumLightIntensity(Mathf.Max(0, punctualIntensity), angleA, angleB);
}
else // Box shape, fallback to punctual light.
{
light.intensity = LightUtils.ConvertPointLightIntensity(Mathf.Max(0, punctualIntensity));
}
}
else
{
// Spot should used conversion which take into account the angle, and thus the intensity vary with angle.
// This is not easy to manipulate for lighter, so we simply consider any spot light as just occluded point light. So reuse the same code.
light.intensity = LightUtils.ConvertPointLightIntensity(Mathf.Max(0, punctualIntensity));
// TODO: What to do with box shape ?
// var spotLightShape = (SpotLightShape)m_AdditionalspotLightShape.enumValueIndex;
}
break;
}
}
else if (lightTypeExtent == LightTypeExtent.Rectangle)
// Check if the intensity have been changed by the inspector or an animator
if (oldDisplayLightIntensity != displayLightIntensity)
light.intensity = LightUtils.ConvertRectLightIntensity(Mathf.Max(0, areaIntensity), shapeWidth, shapeHeight);
RefreshLigthIntensity();
oldDisplayLightIntensity = displayLightIntensity;
else if (lightTypeExtent == LightTypeExtent.Line)
// Same check for light angle to update intensity using spot angle
if (m_Light.type == LightType.Spot && (oldSpotAngle != m_Light.spotAngle || oldEnableSpotReflector != enableSpotReflector))
light.intensity = LightUtils.CalculateLineLightIntensity(Mathf.Max(0, areaIntensity), shapeWidth);
RefreshLigthIntensity();
oldSpotAngle = m_Light.spotAngle;
oldEnableSpotReflector = enableSpotReflector;
// The editor can only access displayLightIntensity (because of SerializedProperties) so we update the intensity to get the real value
public void RefreshLigthIntensity()
{
intensity = displayLightIntensity;
}
#endif
// As we have our own default value, we need to initialize the light intensity correctly
public static void InitDefaultHDAdditionalLightData(HDAdditionalLightData lightData)

// Set light intensity and unit using its type
switch (light.type)
{
case LightType.Directional:
lightData.lightUnit = LightUnit.Lux;
lightData.intensity = k_DefaultDirectionalLightIntensity;
break;
case LightType.Area: // Rectangle by default when light is created
lightData.lightUnit = LightUnit.Lumen;
lightData.intensity = k_DefaultAreaLightIntensity;
break;
case LightType.Point:
case LightType.Spot:
lightData.lightUnit = LightUnit.Lumen;
lightData.intensity = k_DefaultPunctualLightIntensity;
break;
}
// Sanity check: lightData.lightTypeExtent is init to LightTypeExtent.Punctual (in case for unknow reasons we recreate additional data on an existing line)
if (light.type == LightType.Area && lightData.lightTypeExtent == LightTypeExtent.Punctual)
{

// We don't use the global settings of shadow mask by default
light.lightShadowCasterMode = LightShadowCasterMode.Everything;
}
// At first init we need to initialize correctly the default value
lightData.ConvertPhysicalLightIntensityToLightIntensity();
public void OnBeforeSerialize() {}
// TODO: Initialize the light intensity in function of the light type
public void OnAfterDeserialize()
{
// If we are deserializing an old version, convert the light intensity to the new system
if (version == 1.0f)
{
//TODO: convert dir, punc and area light intensities to intensity field
// Pragma to disable the warning got by using deprecated properties (areaIntensity, directionalIntensity, ...)
#pragma warning disable 0618
switch (lightTypeExtent)
{
case LightTypeExtent.Punctual:
switch (m_Light.type)
{
case LightType.Directional:
lightUnit = LightUnit.Lux;
intensity = directionalIntensity;
break;
case LightType.Spot:
case LightType.Point:
lightUnit = LightUnit.Lumen;
intensity = punctualIntensity;
break;
}
break;
case LightTypeExtent.Line:
case LightTypeExtent.Rectangle:
lightUnit = LightUnit.Lumen;
intensity = areaIntensity;
break;
}
#pragma warning restore 0618
version = currentVersion;
}
}
}
}

43
com.unity.render-pipelines.high-definition/HDRP/Lighting/LightUtils.cs


// Also good ref: https://www.radiance-online.org/community/workshops/2004-fribourg/presentations/Wandachowicz_paper.pdf
// convert intensity (lumen) to candela
public static float ConvertPointLightIntensity(float intensity)
public static float ConvertPointLightLumenToCandela(float intensity)
// convert intensity (candela) to lumen
public static float ConvertPointLightCandelaToLumen(float intensity)
{
return intensity * (4.0f * Mathf.PI);
}
public static float ConvertSpotLightIntensity(float intensity, float angle, bool exact)
public static float ConvertSpotLightLumenToCandela(float intensity, float angle, bool exact)
{
return exact ? intensity / (2.0f * (1.0f - Mathf.Cos(angle / 2.0f)) * Mathf.PI) : intensity / Mathf.PI;
}

public static float ConvertFrustrumLightIntensity(float intensity, float angleA, float angleB)
public static float ConvertFrustrumLightLumenToCandela(float intensity, float angleA, float angleB)
public static float ConvertSphereLightIntensity(float intensity, float sphereRadius)
public static float ConvertSphereLightLumenToLuminance(float intensity, float sphereRadius)
// convert intensity (nits) to lumen
public static float ConvertSphereLightLuminanceToLumen(float intensity, float sphereRadius)
{
return intensity * ((4.0f * Mathf.PI * sphereRadius * sphereRadius) * Mathf.PI);
}
public static float ConvertDiscLightIntensity(float intensity, float discRadius)
public static float ConvertDiscLightLumenToLuminance(float intensity, float discRadius)
// convert intensity (nits) to lumen
public static float ConvertDiscLightLuminanceToLumen(float intensity, float discRadius)
{
return intensity * ((discRadius * discRadius * Mathf.PI) * Mathf.PI);
}
public static float ConvertRectLightIntensity(float intensity, float width, float height)
public static float ConvertRectLightLumenToLuminance(float intensity, float width, float height)
// convert intensity (nits) to lumen
public static float ConvertRectLightLuminanceToLumen(float intensity, float width, float height)
{
return intensity * ((width * height) * Mathf.PI);
}
public static float CalculateLineLightIntensity(float intensity, float lineWidth)
public static float CalculateLineLightLumenToLuminance(float intensity, float lineWidth)
{
//Line lights expect radiance (W / (sr * m^2)) in the shader.
//In the UI, we specify luminous flux (power) in lumens.

//power = length * (4 * Pi) * radiance,
//radiance = power / (length * (4 * Pi)).
return intensity / (4.0f * Mathf.PI * lineWidth);
}
public static float CalculateLineLightLuminanceToLumen(float intensity, float lineWidth)
{
return intensity * (4.0f * Mathf.PI * lineWidth);
}
public static void CalculateAnglesForPyramid(float aspectRatio, float spotAngle, out float angleA, out float angleB)

正在加载...
取消
保存