319 lines
15 KiB
C#
319 lines
15 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering.HighDefinition;
|
|
using UnityEngine.Rendering;
|
|
using System.Reflection;
|
|
using System.Linq.Expressions;
|
|
using System.Linq;
|
|
|
|
namespace UnityEditor.Rendering.HighDefinition
|
|
{
|
|
/// <summary>
|
|
/// The UI block that displays emission properties for materials.
|
|
/// </summary>
|
|
public class EmissionUIBlock : MaterialUIBlock
|
|
{
|
|
/// <summary>Options for emission block features. Use this to control which fields are visible.</summary>
|
|
[Flags]
|
|
public enum Features
|
|
{
|
|
/// <summary>Shows the minimal emission fields.</summary>
|
|
None = 0,
|
|
/// <summary>Shows the enable emission for GI field.</summary>
|
|
EnableEmissionForGI = 1 << 0,
|
|
/// <summary>Shows the multiply with base field.</summary>
|
|
MultiplyWithBase = 1 << 1,
|
|
/// <summary>Shows all the fields.</summary>
|
|
All = ~0
|
|
}
|
|
|
|
static Func<LightingSettings> GetLightingSettingsOrDefaultsFallback;
|
|
|
|
static EmissionUIBlock()
|
|
{
|
|
Type lightMappingType = typeof(Lightmapping);
|
|
var getLightingSettingsOrDefaultsFallbackInfo = lightMappingType.GetMethod("GetLightingSettingsOrDefaultsFallback", BindingFlags.Static | BindingFlags.NonPublic);
|
|
var getLightingSettingsOrDefaultsFallbackLambda = Expression.Lambda<Func<LightingSettings>>(Expression.Call(null, getLightingSettingsOrDefaultsFallbackInfo));
|
|
GetLightingSettingsOrDefaultsFallback = getLightingSettingsOrDefaultsFallbackLambda.Compile();
|
|
}
|
|
|
|
internal class Styles
|
|
{
|
|
public const string header = "Emission Inputs";
|
|
|
|
public static GUIContent emissiveText = new GUIContent("Emissive Color", "Emissive Color (RGB).");
|
|
|
|
public static GUIContent albedoAffectEmissiveText = new GUIContent("Emission multiply with Base", "Specifies whether or not the emission color is multiplied by the albedo.");
|
|
public static GUIContent useEmissiveIntensityText = new GUIContent("Use Emission Intensity", "Specifies whether to use to a HDR color or a LDR color with a separate multiplier.");
|
|
public static GUIContent emissiveIntensityText = new GUIContent("Emission Intensity", "");
|
|
public static GUIContent emissiveIntensityFromHDRColorText = new GUIContent("The emission intensity is from the HDR color picker in luminance", "");
|
|
public static GUIContent emissiveExposureWeightText = new GUIContent("Exposure weight", "Controls how the camera exposure influences the perceived intensity of the emissivity. A weight of 0 means that the emissive intensity is calculated ignoring the exposure; increasing this weight progressively increases the influence of exposure on the final emissive value.");
|
|
|
|
public static GUIContent UVEmissiveMappingText = new GUIContent("Emission UV mapping", "");
|
|
public static GUIContent texWorldScaleText = new GUIContent("World Scale", "Sets the tiling factor HDRP applies to Planar/Trilinear mapping.");
|
|
public static GUIContent bakedEmission = new GUIContent("Baked Emission", "");
|
|
}
|
|
|
|
MaterialProperty emissiveColorLDR = null;
|
|
const string kEmissiveColorLDR = "_EmissiveColorLDR";
|
|
MaterialProperty emissiveExposureWeight = null;
|
|
const string kEmissiveExposureWeight = "_EmissiveExposureWeight";
|
|
MaterialProperty useEmissiveIntensity = null;
|
|
const string kUseEmissiveIntensity = "_UseEmissiveIntensity";
|
|
MaterialProperty emissiveIntensityUnit = null;
|
|
const string kEmissiveIntensityUnit = "_EmissiveIntensityUnit";
|
|
MaterialProperty emissiveIntensity = null;
|
|
const string kEmissiveIntensity = "_EmissiveIntensity";
|
|
MaterialProperty emissiveColor = null;
|
|
const string kEmissiveColor = "_EmissiveColor";
|
|
MaterialProperty emissiveColorMap = null;
|
|
const string kEmissiveColorMap = "_EmissiveColorMap";
|
|
MaterialProperty UVEmissive = null;
|
|
const string kUVEmissive = "_UVEmissive";
|
|
MaterialProperty TexWorldScaleEmissive = null;
|
|
const string kTexWorldScaleEmissive = "_TexWorldScaleEmissive";
|
|
MaterialProperty UVMappingMaskEmissive = null;
|
|
const string kUVMappingMaskEmissive = "_UVMappingMaskEmissive";
|
|
MaterialProperty albedoAffectEmissive = null;
|
|
const string kAlbedoAffectEmissive = "_AlbedoAffectEmissive";
|
|
|
|
ExpandableBit m_ExpandableBit;
|
|
Features m_Features;
|
|
|
|
/// <summary>
|
|
/// Constructs an EmissionUIBlock based on the parameters.
|
|
/// </summary>
|
|
/// <param name="expandableBit">Bit index used to store the foldout state.</param>
|
|
/// <param name="features">Features of the block.</param>
|
|
public EmissionUIBlock(ExpandableBit expandableBit, Features features = Features.All)
|
|
{
|
|
m_ExpandableBit = expandableBit;
|
|
m_Features = features;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads the material properties for the block.
|
|
/// </summary>
|
|
public override void LoadMaterialProperties()
|
|
{
|
|
emissiveColor = FindProperty(kEmissiveColor);
|
|
emissiveColorMap = FindProperty(kEmissiveColorMap);
|
|
emissiveIntensityUnit = FindProperty(kEmissiveIntensityUnit);
|
|
emissiveIntensity = FindProperty(kEmissiveIntensity);
|
|
emissiveExposureWeight = FindProperty(kEmissiveExposureWeight);
|
|
emissiveColorLDR = FindProperty(kEmissiveColorLDR);
|
|
useEmissiveIntensity = FindProperty(kUseEmissiveIntensity);
|
|
albedoAffectEmissive = FindProperty(kAlbedoAffectEmissive);
|
|
UVEmissive = FindProperty(kUVEmissive);
|
|
TexWorldScaleEmissive = FindProperty(kTexWorldScaleEmissive);
|
|
UVMappingMaskEmissive = FindProperty(kUVMappingMaskEmissive);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Renders the properties in the block.
|
|
/// </summary>
|
|
public override void OnGUI()
|
|
{
|
|
using (var header = new MaterialHeaderScope(Styles.header, (uint)m_ExpandableBit, materialEditor))
|
|
{
|
|
if (header.expanded)
|
|
DrawEmissionGUI();
|
|
}
|
|
}
|
|
|
|
void UpdateEmissiveColorFromIntensityAndEmissiveColorLDR()
|
|
{
|
|
materialEditor.serializedObject.ApplyModifiedProperties();
|
|
foreach (Material target in materials)
|
|
{
|
|
target.UpdateEmissiveColorFromIntensityAndEmissiveColorLDR();
|
|
}
|
|
materialEditor.serializedObject.Update();
|
|
}
|
|
|
|
internal static void UpdateEmissiveColorFromIntensityAndEmissiveColorLDR(MaterialProperty emissiveColorLDR, MaterialProperty emissiveIntensity, MaterialProperty emissiveColor)
|
|
=> emissiveColor.colorValue = emissiveColorLDR.colorValue.linear * emissiveIntensity.floatValue;
|
|
|
|
internal static void UpdateEmissiveColorLDRFromIntensityAndEmissiveColor(MaterialProperty emissiveColorLDR, MaterialProperty emissiveIntensity, MaterialProperty emissiveColor)
|
|
{
|
|
Color emissiveColorLDRLinear = emissiveColorLDR.colorValue / emissiveIntensity.floatValue;
|
|
emissiveColorLDR.colorValue = emissiveColorLDRLinear.gamma;
|
|
}
|
|
|
|
void UpdateEmissionUnit(float newUnitFloat)
|
|
{
|
|
foreach (Material target in materials)
|
|
{
|
|
if (target.HasProperty(kEmissiveIntensityUnit) && target.HasProperty(kEmissiveIntensity))
|
|
{
|
|
target.SetFloat(kEmissiveIntensityUnit, newUnitFloat);
|
|
}
|
|
}
|
|
materialEditor.serializedObject.Update();
|
|
}
|
|
|
|
void DrawEmissionGUI()
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
materialEditor.ShaderProperty(useEmissiveIntensity, Styles.useEmissiveIntensityText);
|
|
bool updateEmissiveColor = EditorGUI.EndChangeCheck();
|
|
|
|
if (useEmissiveIntensity.floatValue == 0)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
DoEmissiveTextureProperty(emissiveColor);
|
|
if (EditorGUI.EndChangeCheck() || updateEmissiveColor)
|
|
emissiveColor.colorValue = emissiveColor.colorValue;
|
|
EditorGUILayout.HelpBox(Styles.emissiveIntensityFromHDRColorText.text, MessageType.Info, true);
|
|
}
|
|
else
|
|
{
|
|
float newUnitFloat;
|
|
float newIntensity = emissiveIntensity.floatValue;
|
|
bool unitIsMixed = emissiveIntensityUnit.hasMixedValue;
|
|
bool intensityIsMixed = unitIsMixed || emissiveIntensity.hasMixedValue;
|
|
bool intensityChanged = false;
|
|
bool unitChanged = false;
|
|
EditorGUI.BeginChangeCheck();
|
|
{
|
|
DoEmissiveTextureProperty(emissiveColorLDR);
|
|
|
|
using (new EditorGUILayout.HorizontalScope())
|
|
{
|
|
EmissiveIntensityUnit unit = (EmissiveIntensityUnit)emissiveIntensityUnit.floatValue;
|
|
EditorGUI.showMixedValue = intensityIsMixed;
|
|
|
|
if (unit == EmissiveIntensityUnit.Nits)
|
|
{
|
|
using (var change = new EditorGUI.ChangeCheckScope())
|
|
{
|
|
materialEditor.ShaderProperty(emissiveIntensity, Styles.emissiveIntensityText);
|
|
intensityChanged = change.changed;
|
|
if (intensityChanged)
|
|
newIntensity = Mathf.Clamp(emissiveIntensity.floatValue, 0, float.MaxValue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
float value = emissiveIntensity.floatValue;
|
|
if (!intensityIsMixed)
|
|
{
|
|
float evValue = LightUtils.ConvertLuminanceToEv(emissiveIntensity.floatValue);
|
|
evValue = EditorGUILayout.FloatField(Styles.emissiveIntensityText, evValue);
|
|
newIntensity = Mathf.Clamp(evValue, 0, float.MaxValue);
|
|
emissiveIntensity.floatValue = LightUtils.ConvertEvToLuminance(evValue);
|
|
}
|
|
else
|
|
{
|
|
using (var change = new EditorGUI.ChangeCheckScope())
|
|
{
|
|
newIntensity = EditorGUILayout.FloatField(Styles.emissiveIntensityText, value);
|
|
intensityChanged = change.changed;
|
|
}
|
|
}
|
|
}
|
|
EditorGUI.showMixedValue = false;
|
|
|
|
EditorGUI.showMixedValue = emissiveIntensityUnit.hasMixedValue;
|
|
using (var change = new EditorGUI.ChangeCheckScope())
|
|
{
|
|
newUnitFloat = (float)(EmissiveIntensityUnit)EditorGUILayout.EnumPopup(unit);
|
|
unitChanged = change.changed;
|
|
}
|
|
EditorGUI.showMixedValue = false;
|
|
}
|
|
}
|
|
if (EditorGUI.EndChangeCheck() || updateEmissiveColor)
|
|
{
|
|
if (unitChanged)
|
|
{
|
|
if (unitIsMixed)
|
|
UpdateEmissionUnit(newUnitFloat);
|
|
else
|
|
emissiveIntensityUnit.floatValue = newUnitFloat;
|
|
}
|
|
|
|
// We don't allow changes on intensity if units are mixed
|
|
if (intensityChanged && !unitIsMixed)
|
|
emissiveIntensity.floatValue = newIntensity;
|
|
|
|
UpdateEmissiveColorFromIntensityAndEmissiveColorLDR(emissiveColorLDR, emissiveIntensity, emissiveColor);
|
|
}
|
|
}
|
|
|
|
materialEditor.ShaderProperty(emissiveExposureWeight, Styles.emissiveExposureWeightText);
|
|
|
|
if ((m_Features & Features.MultiplyWithBase) != 0)
|
|
materialEditor.ShaderProperty(albedoAffectEmissive, Styles.albedoAffectEmissiveText);
|
|
|
|
// Emission for GI?
|
|
if ((m_Features & Features.EnableEmissionForGI) != 0)
|
|
{
|
|
BakedEmissionEnabledProperty(materialEditor);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draw the Baked Emission Enabled field
|
|
/// </summary>
|
|
/// <param name="materialEditor">The current material editor in use.</param>
|
|
/// <returns>True if the property is enabled on all selected materials.</returns>
|
|
public static bool BakedEmissionEnabledProperty(MaterialEditor materialEditor)
|
|
{
|
|
Material[] materials = Array.ConvertAll(materialEditor.targets, (UnityEngine.Object o) => { return (Material)o; });
|
|
|
|
// Calculate isMixed
|
|
bool enabled = materials[0].globalIlluminationFlags == MaterialGlobalIlluminationFlags.BakedEmissive;
|
|
bool isMixed = materials.Any(m => m.globalIlluminationFlags != materials[0].globalIlluminationFlags);
|
|
|
|
// initial checkbox for enabling/disabling emission
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUI.showMixedValue = isMixed;
|
|
enabled = EditorGUILayout.Toggle(Styles.bakedEmission, enabled);
|
|
EditorGUI.showMixedValue = false;
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
foreach (Material mat in materials)
|
|
{
|
|
mat.globalIlluminationFlags = enabled ? MaterialGlobalIlluminationFlags.BakedEmissive : MaterialGlobalIlluminationFlags.EmissiveIsBlack;
|
|
}
|
|
return enabled;
|
|
}
|
|
return !isMixed && enabled;
|
|
}
|
|
|
|
void DoEmissiveTextureProperty(MaterialProperty color)
|
|
{
|
|
materialEditor.TexturePropertySingleLine(Styles.emissiveText, emissiveColorMap, color);
|
|
|
|
if (materials.All(m => m.GetTexture(kEmissiveColorMap)))
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
if (UVEmissive != null) // Unlit does not have UVEmissive
|
|
{
|
|
materialEditor.ShaderProperty(UVEmissive, Styles.UVEmissiveMappingText);
|
|
UVEmissiveMapping uvEmissiveMapping = (UVEmissiveMapping)UVEmissive.floatValue;
|
|
|
|
float X, Y, Z, W;
|
|
X = (uvEmissiveMapping == UVEmissiveMapping.UV0) ? 1.0f : 0.0f;
|
|
Y = (uvEmissiveMapping == UVEmissiveMapping.UV1) ? 1.0f : 0.0f;
|
|
Z = (uvEmissiveMapping == UVEmissiveMapping.UV2) ? 1.0f : 0.0f;
|
|
W = (uvEmissiveMapping == UVEmissiveMapping.UV3) ? 1.0f : 0.0f;
|
|
|
|
UVMappingMaskEmissive.colorValue = new Color(X, Y, Z, W);
|
|
|
|
if ((uvEmissiveMapping == UVEmissiveMapping.Planar) || (uvEmissiveMapping == UVEmissiveMapping.Triplanar))
|
|
{
|
|
materialEditor.ShaderProperty(TexWorldScaleEmissive, Styles.texWorldScaleText);
|
|
}
|
|
}
|
|
|
|
if (UVEmissive == null || (UVEmissiveMapping)UVEmissive.floatValue != UVEmissiveMapping.SameAsBase)
|
|
materialEditor.TextureScaleOffsetProperty(emissiveColorMap);
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
}
|
|
}
|
|
}
|