using System.Collections.Generic; using System; using UnityEngine; using UnityEditor.Graphing; using UnityEditor.ShaderGraph; using UnityEditor.ShaderGraph.Drawing.Controls; using UnityEditor.ShaderGraph.Internal; using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; namespace UnityEditor.Rendering.HighDefinition { [SRPFilter(typeof(HDRenderPipeline))] [FormerName("UnityEditor.Experimental.Rendering.HDPipeline.EmissionNode")] [Title("Utility", "High Definition Render Pipeline", "Emission Node")] class EmissionNode : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction { public EmissionNode() { name = "Emission Node"; UpdateNodeAfterDeserialization(); } public override string documentationURL => Documentation.GetPageLink("SGNode-Emission"); [SerializeField] EmissiveIntensityUnit _intensityUnit; [EnumControl] EmissiveIntensityUnit intensityUnit { get { return _intensityUnit; } set { _intensityUnit = value; Dirty(ModificationScope.Node); } } [SerializeField] bool m_NormalizeColor; [ToggleControl("Normalize Color")] ToggleData normalizeColor { get { return new ToggleData(m_NormalizeColor); } set { m_NormalizeColor = value.isOn; Dirty(ModificationScope.Node); } } const int kEmissionOutputSlotId = 0; const int kEmissionColorInputSlotId = 1; const int kEmissionIntensityInputSlotId = 2; const int kEmissionExposureWeightInputSlotId = 3; const string kEmissionOutputSlotName = "Output"; const string kEmissionColorInputSlotName = "Color"; const string kEmissionExpositionWeightInputSlotName = "Exposure Weight"; const string kEmissionIntensityInputSlotName = "Intensity"; public override bool hasPreview { get { return false; } } ColorRGBMaterialSlot ldrColorSlot; Vector1MaterialSlot intensitySlot; public sealed override void UpdateNodeAfterDeserialization() { // Input slots: ldrColorSlot = new ColorRGBMaterialSlot(kEmissionColorInputSlotId, kEmissionColorInputSlotName, kEmissionColorInputSlotName, SlotType.Input, Color.black, ColorMode.Default); intensitySlot = new Vector1MaterialSlot(kEmissionIntensityInputSlotId, kEmissionIntensityInputSlotName, kEmissionIntensityInputSlotName, SlotType.Input, 1); AddSlot(ldrColorSlot); AddSlot(intensitySlot); AddSlot(new Vector1MaterialSlot(kEmissionExposureWeightInputSlotId, kEmissionExpositionWeightInputSlotName, kEmissionExpositionWeightInputSlotName, SlotType.Input, 1)); // Output slot:kEmissionOutputSlotName AddSlot(new ColorRGBMaterialSlot(kEmissionOutputSlotId, kEmissionOutputSlotName, kEmissionOutputSlotName, SlotType.Output, Color.black, ColorMode.HDR)); RemoveSlotsNameNotMatching(new[] { kEmissionOutputSlotId, kEmissionColorInputSlotId, kEmissionIntensityInputSlotId, kEmissionExposureWeightInputSlotId }); } public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) { var colorValue = GetSlotValue(kEmissionColorInputSlotId, generationMode); var intensityValue = GetSlotValue(kEmissionIntensityInputSlotId, generationMode); var exposureWeightValue = GetSlotValue(kEmissionExposureWeightInputSlotId, generationMode); var outputValue = GetSlotValue(kEmissionOutputSlotId, generationMode); if (intensityUnit == EmissiveIntensityUnit.EV100) intensityValue = "ConvertEvToLuminance(" + intensityValue + ")"; sb.AppendLine(@"$precision3 {0} = {1}({2}.xyz, {3}, {4});", outputValue, GetFunctionName(), colorValue, intensityValue, exposureWeightValue ); } string GetFunctionName() { return "Unity_HDRP_GetEmissionHDRColor_$precision"; } public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode) { // We may need ConvertEvToLuminance() so we include CommonLighting.hlsl registry.RequiresIncludePath("Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonLighting.hlsl"); registry.ProvideFunction(GetFunctionName(), s => { s.AppendLine("$precision3 {0}($precision3 ldrColor, {1} luminanceIntensity, {1} exposureWeight)", GetFunctionName(), intensitySlot.concreteValueType.ToShaderString()); using (s.BlockScope()) { if (normalizeColor.isOn) { s.AppendLine("ldrColor = ldrColor * rcp(max(Luminance(ldrColor), 1e-6));"); } s.AppendLine("$precision3 hdrColor = ldrColor * luminanceIntensity;"); s.AppendNewLine(); s.AppendLine("#ifdef SHADERGRAPH_PREVIEW"); s.AppendLine($"$precision inverseExposureMultiplier = 1.0;"); s.AppendLine("#else"); s.AppendLine($"$precision inverseExposureMultiplier = GetInverseCurrentExposureMultiplier();"); s.AppendLine("#endif"); s.AppendNewLine(); s.AppendLine("// Inverse pre-expose using _EmissiveExposureWeight weight"); s.AppendLine("hdrColor = lerp(hdrColor * inverseExposureMultiplier, hdrColor, exposureWeight);"); s.AppendLine("return hdrColor;"); } }); } Vector3 GetHDREmissionColor(Vector3 ldrColor, float intensity) { float multiplier = intensity; if (intensityUnit == EmissiveIntensityUnit.EV100) multiplier = LightUnitUtils.Ev100ToNits(intensity); return ldrColor * intensity; } public override void CollectPreviewMaterialProperties(List properties) { Vector3 outputColor = GetHDREmissionColor(ldrColorSlot.value, intensitySlot.value); properties.Add(new PreviewProperty(PropertyType.Vector3) { name = GetVariableNameForSlot(kEmissionColorInputSlotId), vector4Value = outputColor }); } } }