浏览代码

Merge pull request #987 from Unity-Technologies/Add-physical-Light-unit-2

Add physical light unit
/main
GitHub 7 年前
当前提交
29fc3c6e
共有 7 个文件被更改,包括 209 次插入8 次删除
  1. 46
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDRenderPipelineMenuItems.cs
  2. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/HDLightEditor.Styles.cs
  3. 78
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/HDLightEditor.cs
  4. 6
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Light/HDAdditionalLightData.cs
  5. 6
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl
  6. 67
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightUtils.cs
  7. 11
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightUtils.cs.meta

46
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDRenderPipelineMenuItems.cs


public class HDRenderPipelineMenuItems
{
[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.calculateLineLightArea(1.0f, add.shapeWidth);
}
}
var scene = SceneManager.GetActiveScene();
EditorSceneManager.MarkSceneDirty(scene);
}
[MenuItem("Internal/HDRenderPipeline/Add \"Additional Light-shadow Data\" (if not present)")]
static void AddAdditionalLightData()
{

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/HDLightEditor.Styles.cs


public readonly GUIContent indirectBounceShadowWarning = new GUIContent("Realtime indirect bounce shadowing is not supported for Spot and Point lights.");
// Additional light data
public readonly GUIContent directionalIntensity = new GUIContent("Intensity (Lux)", "");
public readonly GUIContent punctualIntensity = new GUIContent("Intensity (Lumen)", "");
public readonly GUIContent areaIntensity = new GUIContent("Intensity (Lumen)", "");
public readonly GUIContent maxSmoothness = new GUIContent("Max Smoothness", "Very low cost way of faking spherical area lighting. This will modify the roughness of the material lit. This is useful when the specular highlight is too small or too sharp.");
public readonly GUIContent affectDiffuse = new GUIContent("Affect Diffuse", "This will disable diffuse lighting for this light. Doesn't save performance, diffuse lighting is still computed.");

78
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/HDLightEditor.cs


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

//Disc,
}
const float k_MinAreaWidth = 0.01f; // Provide a small size of 1cm for line light
// Used for UI only; the processing code must use LightTypeExtent and LightType
LightShape m_LightShape;

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),
spotInnerPercent = o.Find(x => x.m_InnerSpotPercent),
lightDimmer = o.Find(x => x.lightDimmer),
fadeDistance = o.Find(x => x.fadeDistance),

void DrawShape()
{
EditorGUI.BeginChangeCheck(); // For GI we need to detect any change on additional data and call SetLightDirty + For intensity we need to detect light shape change
EditorGUI.BeginChangeCheck(); // For GI we need to detect any change on additional data and call SetLightDirty
// LightShape is HD specific, it need to drive LightType from the original LightType
// when it make sense, so the GI is still in sync with the light shape
switch (m_LightShape)

m_AdditionalLightData.lightTypeExtent.enumValueIndex = (int)LightTypeExtent.Rectangle;
EditorGUILayout.PropertyField(m_AdditionalLightData.shapeWidth, s_Styles.shapeWidthRect);
EditorGUILayout.PropertyField(m_AdditionalLightData.shapeHeight, s_Styles.shapeHeightRect);
m_AdditionalLightData.shapeWidth.floatValue = Mathf.Max(m_AdditionalLightData.shapeWidth.floatValue, k_MinAreaWidth);
m_AdditionalLightData.shapeHeight.floatValue = Mathf.Max(m_AdditionalLightData.shapeHeight.floatValue, k_MinAreaWidth);
settings.areaSizeX.floatValue = m_AdditionalLightData.shapeWidth.floatValue;
settings.areaSizeY.floatValue = m_AdditionalLightData.shapeHeight.floatValue;
settings.shadowsType.enumValueIndex = (int)LightShadows.None;

settings.lightType.enumValueIndex = (int)LightType.Point;
m_AdditionalLightData.lightTypeExtent.enumValueIndex = (int)LightTypeExtent.Line;
EditorGUILayout.PropertyField(m_AdditionalLightData.shapeWidth, s_Styles.shapeWidthLine);
m_AdditionalLightData.shapeWidth.floatValue = Mathf.Max(m_AdditionalLightData.shapeWidth.floatValue, k_MinAreaWidth);
m_AdditionalLightData.shapeHeight.floatValue = Mathf.Max(m_AdditionalLightData.shapeHeight.floatValue, k_MinAreaWidth);
settings.areaSizeY.floatValue = 0.01f;
settings.areaSizeY.floatValue = k_MinAreaWidth;
settings.shadowsType.enumValueIndex = (int)LightShadows.None;
break;

if (EditorGUI.EndChangeCheck())
{
UpdateLightIntensity();
void UpdateLightIntensity()
{
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.
settings.intensity.floatValue = LightUtils.ConvertPointLightIntensity(m_AdditionalLightData.punctualIntensity.floatValue);
// TODO: What to do with box shape ?
// var spotLightShape = (SpotLightShape)m_AdditionalLightData.spotLightShape.enumValueIndex;
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.calculateLineLightArea(m_AdditionalLightData.areaIntensity.floatValue, m_AdditionalLightData.shapeWidth.floatValue);
break;
}
}
settings.DrawIntensity();
settings.DrawBounceIntensity();
EditorGUI.BeginChangeCheck();
switch (m_LightShape)
{
case LightShape.Directional:
EditorGUILayout.PropertyField(m_AdditionalLightData.directionalIntensity, s_Styles.directionalIntensity);
break;
case LightShape.Point:
case LightShape.Spot:
EditorGUILayout.PropertyField(m_AdditionalLightData.punctualIntensity, s_Styles.punctualIntensity);
break;
case LightShape.Rectangle:
case LightShape.Line:
EditorGUILayout.PropertyField(m_AdditionalLightData.areaIntensity, s_Styles.areaIntensity);
break;
}
if (EditorGUI.EndChangeCheck())
{
UpdateLightIntensity();
}
settings.DrawLightmapping();
EditorGUI.BeginChangeCheck(); // For GI we need to detect any change on additional data and call SetLightDirty

EditorGUILayout.Slider(m_AdditionalShadowData.normalBiasMin, 0.0f, 5.0f, s_Styles.normalBiasMin);
if (EditorGUI.EndChangeCheck())
{
// Link min to max and don't expose normalBiasScale (useless when min == max)
// Link min to max and don't expose normalBiasScale (useless when min == max)
m_AdditionalShadowData.normalBiasMax = m_AdditionalShadowData.normalBiasMin;
}
//EditorGUILayout.PropertyField(m_AdditionalShadowData.normalBiasMax, s_Styles.normalBiasMax);

6
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Light/HDAdditionalLightData.cs


float m_Version = 1.0f;
#pragma warning restore 414
// To be able to have correct default values for our lights and to also control the conversion of intensity from the light editor (so it is compatible with GI)
// we add intensity (for each type of light we want to manage).
public float directionalIntensity = Mathf.PI; // In Lux
public float punctualIntensity = 600.0f; // Light default to 600 lumen, i.e ~48 candela
public float areaIntensity = 200.0f; // Light default to 200 lumen to better match point light
[Range(0.0f, 100.0f)]
public float m_InnerSpotPercent = 0.0f; // To display this field in the UI this need to be public

6
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl


// Save ALU by applying 'lightData.color' only once.
lighting.diffuse *= lightData.color;
lighting.specular *= lightData.color;
#endif // LIT_DISPLAY_REFERENCE_AREA
#ifdef DEBUG_DISPLAY
if (_DebugLightingMode == DEBUGLIGHTINGMODE_LUX_METER)

lighting.diffuse *= PI * lightData.diffuseScale;
}
#endif
#endif // LIT_DISPLAY_REFERENCE_AREA
return lighting;
}

// Save ALU by applying 'lightData.color' only once.
lighting.diffuse *= lightData.color;
lighting.specular *= lightData.color;
#endif // LIT_DISPLAY_REFERENCE_AREA
#ifdef DEBUG_DISPLAY
if (_DebugLightingMode == DEBUGLIGHTINGMODE_LUX_METER)

lighting.diffuse *= PI * lightData.diffuseScale;
}
#endif
#endif // LIT_DISPLAY_REFERENCE_AREA
return lighting;
}

67
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightUtils.cs


using System;
using System.Collections.Generic;
using System.Linq;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{
public class LightUtils
{
// Physical light unit helper
// All light unit are in lumen (Luminous power)
// Punctual light (point, spot) are convert to candela (cd = lumens / steradian)
// Area light are convert to luminance (cd/(m^2*steradian)) with the following formulation: Luminous Power / (Area * PI * steradian)
// Ref: Moving Frostbite to PBR
// 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)
{
return intensity / (4.0f * Mathf.PI);
}
// angle is the full angle, not the half angle in radiant
// convert intensity (lumen) to candela
public static float ConvertSpotLightIntensity(float intensity, float angle, bool exact)
{
return exact ? intensity / (2.0f * (1.0f - Mathf.Cos(angle / 2.0f)) * Mathf.PI) : intensity / Mathf.PI;
}
// angleA and angleB are the full opening angle, not half angle
// convert intensity (lumen) to candela
public static float ConvertFrustrumLightIntensity(float intensity, float angleA, float angleB)
{
return intensity / (4.0f * Mathf.Asin(Mathf.Sin(angleA / 2.0f) * Mathf.Sin(angleB / 2.0f)));
}
// convert intensity (lumen) to nits
public static float ConvertSphereLightIntensity(float intensity, float sphereRadius)
{
return intensity / ((4.0f * Mathf.PI * sphereRadius * sphereRadius) * Mathf.PI);
}
// convert intensity (lumen) to nits
public static float ConvertDiscLightIntensity(float intensity, float discRadius)
{
return intensity / ((discRadius * discRadius * Mathf.PI) * Mathf.PI);
}
// convert intensity (lumen) to nits
public static float ConvertRectLightIntensity(float intensity, float width, float height)
{
return intensity / ((width * height) * Mathf.PI);
}
// convert intensity (lumen) to nits
public static float calculateLineLightArea(float intensity, float lineWidth)
{
// The area of a cylinder is this:
// float lineRadius = 0.01f; // 1cm
//return intensity / (2.0f * Mathf.PI * lineRadius * lineWidth * Mathf.PI);
// But with our current line light algorithm we get an insane gap in intensity
// following formula (fully empirical) give a better match to a rect light of 1cm of width.
// It is basically point light intensity / line width.
return intensity / (4.0f * Mathf.PI * lineWidth);
}
}
}

11
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightUtils.cs.meta


fileFormatVersion: 2
guid: 04acc467a6eef0b45b027f43ed25662b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存