You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

405 lines
16 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using RenderingLayerMask = UnityEngine.Rendering.HighDefinition.RenderingLayerMask;
namespace UnityEditor.VFX.HDRP
{
[VFXInfo(name = "Output Particle HDRP Lit Decal", category = "Output")]
class VFXDecalHDRPOutput : VFXAbstractParticleHDRPOutput
{
public override string name
{
get { return "Output Particle HDRP Lit Decal"; }
}
public override string codeGeneratorTemplate
{
get { return RenderPipeTemplate("VFXParticleHDRPDecal"); }
}
public override VFXTaskType taskType
{
get { return VFXTaskType.ParticleHexahedronOutput; }
}
public override void OnEnable()
{
base.OnEnable();
blendMode = BlendMode.Opaque;
cullMode = CullMode.Back;
}
public enum BlendSource
{
BaseColorMapAlpha,
MaskMapBlue,
}
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), Header("Opacity Channels"), SerializeField,
Tooltip("Specifies the source this Material uses as opacity for its Normal Map.")]
BlendSource normalOpacityChannel = BlendSource.BaseColorMapAlpha;
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), SerializeField,
Tooltip("Specifies the source this Material uses as opacity for its Mask Map.")]
BlendSource maskOpacityChannel = BlendSource.BaseColorMapAlpha;
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), Header("Surface options"), SerializeField,
Tooltip("When enabled, modifies the base color of the surface it projects onto.")]
private bool affectBaseColor = true;
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), SerializeField,
Tooltip(
"When enabled, modifies the metallic look of the surface it projects onto using the (R) channel of the Mask Map if one is provided.")]
private bool affectMetal = true;
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), SerializeField,
Tooltip(
"When enabled, modifies the ambient occlusion (AO) of the surface it projects onto using the (G) channel of the Mask Map if one is provided.")]
private bool affectAmbientOcclusion = true;
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), SerializeField,
Tooltip(
"When enabled, modifies the smoothness of the surface it projects onto using the (A) channel of the Mask Map if one is provided.")]
private bool affectSmoothness = true;
private void GetDecalSupport(out bool supportDecals, out bool enableDecalLayers, out bool metalAndAODecals)
{
var renderingPathFrameSettings = GraphicsSettings
.GetRenderPipelineSettings<RenderingPathFrameSettings>()?
.GetDefaultFrameSettings(FrameSettingsRenderType.Camera);
var pipelineSettings = HDRenderPipeline.currentAsset.currentPlatformRenderPipelineSettings;
supportDecals = pipelineSettings.supportDecals &&
renderingPathFrameSettings?.IsEnabled(FrameSettingsField.Decals) == true;
enableDecalLayers = supportDecals && pipelineSettings.supportDecalLayers &&
renderingPathFrameSettings?.IsEnabled(FrameSettingsField.DecalLayers) == true;
metalAndAODecals = supportDecals && pipelineSettings.decalSettings.perChannelMask;
}
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), SerializeField,
Tooltip("Specify the layer mask for the decals. Unity renders decals on all meshes where at least one Rendering Layer value matches.")]
private RenderingLayerMask decalLayer = (RenderingLayerMask) (uint) UnityEngine.RenderingLayerMask.defaultRenderingLayerMask;
private bool affectsAOAndHasMaskMap => affectAmbientOcclusion && useMaskMap;
public override bool HasSorting() => (sort == SortActivationMode.On) || (sort == SortActivationMode.Auto);
public override bool supportsUV { get { return GetOrRefreshShaderGraphObject() == null; } }
protected override bool useNormalScale => false;
public class FadeFactorProperty
{
[Range(0, 1), Tooltip("Controls the transparency of the decal.")]
public float fadeFactor = 1.0f;
}
public class AngleFadeProperty
{
[Tooltip("Use the min-max slider to control the fade out range of the decal based on the angle between the Decal backward direction and the vertex normal of the receiving surface." +
" Works only if Decal Layers is enabled both in the HDRP Asset and in the HDRP Global Settings."), MinMax(0.0f, 180.0f)]
public Vector2 angleFade = new Vector2(0.0f, 180.0f);
}
public class NormalAlphaProperty
{
[Tooltip("Controls the blending factor of the normal map."), Range(0, 1)]
public float normalAlpha = 1.0f;
}
protected IEnumerable<VFXPropertyWithValue> materialProperties
{
get
{
if (affectMetal)
yield return new VFXPropertyWithValue(new VFXProperty(typeof(float),
"metallic",
new TooltipAttribute(useMaskMap
? "Controls the scale factor for the particle’s metallic."
: "Controls the metallic of the decal."),
new RangeAttribute(0, 1)), 0.0f);
if (affectsAOAndHasMaskMap)
yield return new VFXPropertyWithValue(new VFXProperty(typeof(float),
"ambientOcclusion",
new TooltipAttribute("Controls the scale factor for the particle’s ambient occlusion."),
new RangeAttribute(0, 1)), 1.0f);
if (affectSmoothness)
yield return new VFXPropertyWithValue(new VFXProperty(typeof(float),
"smoothness",
new TooltipAttribute(useMaskMap
? "Controls the scale factor for the particle’s smoothness."
: "Controls the smoothness of the decal."),
new RangeAttribute(0, 1)), 0.5f);
}
}
protected override IEnumerable<VFXPropertyWithValue> inputProperties
{
get
{
var properties = Enumerable.Empty<VFXPropertyWithValue>();
properties = properties.Concat(PropertiesFromType(nameof(FadeFactorProperty)));
properties = properties.Concat(PropertiesFromType(nameof(AngleFadeProperty)));
foreach (var prop in base.inputProperties)
{
properties = properties.Append(prop);
if(prop.property.name == "normalMap")
properties = properties.Concat(PropertiesFromType(nameof(NormalAlphaProperty)));
}
properties = properties.Concat(materialProperties);
return properties;
}
}
protected override IEnumerable<VFXNamedExpression> CollectGPUExpressions(
IEnumerable<VFXNamedExpression> slotExpressions)
{
foreach (var exp in base.CollectGPUExpressions(slotExpressions))
yield return exp;
if (GetOrRefreshShaderGraphObject() == null)
{
yield return slotExpressions.First(o => o.name == nameof(FadeFactorProperty.fadeFactor));
if (affectMetal)
yield return slotExpressions.First(o => o.name == "metallic");
if (affectsAOAndHasMaskMap)
yield return slotExpressions.First(o => o.name == "ambientOcclusion");
if (affectSmoothness)
yield return slotExpressions.First(o => o.name == "smoothness");
var angleFadeExp = slotExpressions.First(o => o.name == nameof(AngleFadeProperty.angleFade));
yield return new VFXNamedExpression(AngleFadeSimplification(angleFadeExp.exp), nameof(AngleFadeProperty.angleFade));
if (useNormalMap)
yield return slotExpressions.First(o => o.name == nameof(NormalAlphaProperty.normalAlpha));
yield return new VFXNamedExpression(VFXValue.Constant((uint)decalLayer), "decalLayerMask");
}
}
VFXExpression AngleFadeSimplification(VFXExpression angleFadeExp)
{
// See DecalSystem.cs
angleFadeExp = angleFadeExp / VFXValue.Constant(new Vector2(180.0f, 180.0f));
var angleStart = new VFXExpressionExtractComponent(angleFadeExp, 0);
var angleEnd = new VFXExpressionExtractComponent(angleFadeExp, 1);
var range = new VFXExpressionMax(VFXValue.Constant(0.0001f), angleEnd - angleStart);
var simplifiedAngleFade = new VFXExpressionCombine(
VFXValue.Constant(0.222222222f) / range,
(angleEnd - VFXValue.Constant(0.5f)) / range);
return simplifiedAngleFade;
}
public override void OnSettingModified(VFXSetting setting)
{
base.OnSettingModified(setting);
if (setting.name == "affectBaseColor")
{
if (!affectBaseColor)
{
useBaseColorMap = BaseColorMapMode.Alpha;
}
else
{
useBaseColorMap = BaseColorMapMode.ColorAndAlpha;
}
}
}
protected override IEnumerable<string> filteredOutSettings
{
get
{
foreach (var setting in base.filteredOutSettings)
yield return setting;
yield return "cullMode";
yield return "blendMode";
yield return "doubleSided";
yield return "shaderGraph";
yield return "zTestMode";
yield return "zWriteMode";
yield return "castShadows";
yield return "materialType";
GetDecalSupport(out var _, out var enableDecalLayers, out var __);
if (!enableDecalLayers)
yield return "decalLayer";
if (!affectBaseColor)
yield return "useBaseColorMap";
}
}
public override IEnumerable<string> additionalDefines
{
get
{
foreach (var def in base.additionalDefines)
yield return def;
if (maskOpacityChannel == BlendSource.BaseColorMapAlpha)
yield return "VFX_MASK_BLEND_BASE_COLOR_ALPHA";
else
yield return "VFX_MASK_BLEND_MASK_BLUE";
if (normalOpacityChannel == BlendSource.BaseColorMapAlpha)
yield return "VFX_NORMAL_BLEND_BASE_COLOR_ALPHA";
else
yield return "VFX_NORMAL_BLEND_MASK_BLUE";
if (affectMetal)
yield return "AFFECT_METALLIC";
if (affectsAOAndHasMaskMap)
yield return "AFFECT_AMBIENT_OCCLUSION";
if (affectSmoothness)
yield return "AFFECT_SMOOTHNESS";
if (useEmissiveColor || useEmissiveMap)
yield return "NEEDS_FORWARD_EMISSIVE_PASS";
}
}
protected VFXShaderWriter GetDecalMaskColor(int maskIndex)
{
var rs = new VFXShaderWriter();
var maskString = "";
switch (maskIndex)
{
case 0:
rs.Write(affectBaseColor ? "RBGA" : "0");
break;
case 1:
rs.Write(useNormalMap ? "RGBA" : "0");
break;
case 2:
{
if (affectMetal)
{
maskString += "R";
}
if (affectsAOAndHasMaskMap)
{
maskString += "G";
}
if (affectSmoothness)
{
maskString += "BA";
}
if (String.IsNullOrEmpty(maskString))
maskString = "0";
rs.Write(maskString);
break;
}
case 3:
if (affectMetal)
{
maskString += "R";
}
if (affectsAOAndHasMaskMap)
{
maskString += "G";
}
if (String.IsNullOrEmpty(maskString))
maskString = "0";
rs.Write(maskString);
break;
}
return rs;
}
public override IEnumerable<KeyValuePair<string, VFXShaderWriter>> additionalReplacements
{
get
{
foreach (var rep in base.additionalReplacements)
yield return rep;
for (int i = 0; i < 4; i++)
{
yield return new KeyValuePair<string, VFXShaderWriter>("${VFXDecalColorMask" + i + "}",
GetDecalMaskColor(i));
}
}
}
public override void Sanitize(int version)
{
base.Sanitize(version);
VFXSlot oldNormalScaleSlot = null;
VFXSlot newNormalAlphaSlot = null;
foreach (var slot in inputSlots)
{
if (slot.name == "normalScale")
{
oldNormalScaleSlot = slot;
}
if (slot.name == "normalAlpha")
newNormalAlphaSlot = slot;
}
if (oldNormalScaleSlot != null && newNormalAlphaSlot != null)
{
VFXSlot.CopyLinksAndValue(newNormalAlphaSlot, oldNormalScaleSlot, true);
oldNormalScaleSlot.UnlinkAll(true, true);
}
}
internal override void GenerateErrors(VFXErrorReporter report)
{
base.GenerateErrors(report);
GetDecalSupport(out var supportDecals, out var enableDecalLayers, out var metalAndAODecals);
if (!supportDecals)
{
report.RegisterError("DecalsDisabled", VFXErrorType.Warning,
$"Decals will not be rendered because the 'Decals' is disabled in your HDRP Asset. Enable 'Decals' in your HDRP Asset to make this output work.", this);
}
if (!enableDecalLayers)
{
report.RegisterError("DecalLayersDisabled", VFXErrorType.Warning,
$"The Angle Fade parameter won't have any effect, because the 'Decal Layers' setting is disabled." +
$" Enable 'Decal Layers' in your HDRP Asset if you want to control the Angle Fade." +
$" There is a performance cost of enabling this option.", this);
}
if (!metalAndAODecals)
{
report.RegisterError("DecalMetalAODisabled", VFXErrorType.Warning,
$"The Metallic and Ambient Occlusion parameters won't have any effect, because the 'Metal and AO properties' setting is disabled." +
$" Enable 'Metal and AO properties' in your HDRP Asset if you want to control the Metal and AO properties of decals. There is a performance cost of enabling this option.", this);
}
}
protected override IEnumerable<string> untransferableSettings
{
get
{
foreach (var setting in base.untransferableSettings)
{
yield return setting;
}
yield return "blendMode";
yield return "sort";
yield return "cullMode";
}
}
}
}