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.
362 lines
13 KiB
362 lines
13 KiB
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEditor.ShaderGraph.Internal;
|
|
using UnityEngine;
|
|
|
|
namespace UnityEditor.VFX
|
|
{
|
|
class VFXShaderGraphParticleOutput : VFXAbstractParticleOutput, IVFXShaderGraphOutput
|
|
{
|
|
//"protected" is only to be listed by VFXModel.GetSettings, we should always use GetOrRefreshShaderGraphObject
|
|
[SerializeField, VFXSetting]
|
|
protected ShaderGraphVfxAsset shaderGraph;
|
|
|
|
[SerializeField, VFXSetting]
|
|
internal VFXMaterialSerializedSettings materialSettings = new VFXMaterialSerializedSettings();
|
|
|
|
private bool m_IsShaderGraphMissing;
|
|
|
|
protected override IEnumerable<string> untransferableSettings
|
|
{
|
|
get
|
|
{
|
|
//In case of convert from VFXComposedParticleOutput, we won't retrieve shaderGraph anymore, this settings is now hidden
|
|
yield return nameof(shaderGraph);
|
|
}
|
|
}
|
|
|
|
public ShaderGraphVfxAsset GetOrRefreshShaderGraphObject(bool refreshErrors = true)
|
|
{
|
|
var wasShaderGraphMissing = m_IsShaderGraphMissing;
|
|
//This is the only place where shaderGraph property is updated or read
|
|
if (shaderGraph == null && !object.ReferenceEquals(shaderGraph, null))
|
|
{
|
|
var assetPath = AssetDatabase.GetAssetPath(shaderGraph.GetInstanceID());
|
|
|
|
var newShaderGraph = AssetDatabase.LoadAssetAtPath<ShaderGraphVfxAsset>(assetPath);
|
|
m_IsShaderGraphMissing = newShaderGraph == null;
|
|
|
|
if (!m_IsShaderGraphMissing)
|
|
{
|
|
shaderGraph = newShaderGraph;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_IsShaderGraphMissing = false;
|
|
}
|
|
|
|
if (refreshErrors && wasShaderGraphMissing != m_IsShaderGraphMissing)
|
|
{
|
|
RefreshErrors();
|
|
}
|
|
|
|
return shaderGraph;
|
|
}
|
|
|
|
public override void Sanitize(int version)
|
|
{
|
|
base.Sanitize(version);
|
|
if (version < 14)
|
|
{
|
|
var shaderGraph = GetOrRefreshShaderGraphObject();
|
|
if (shaderGraph && shaderGraph.generatesWithShaderGraph)
|
|
{
|
|
var path = AssetDatabase.GetAssetPath(shaderGraph);
|
|
var referenceMaterial = AssetDatabase.LoadAssetAtPath<Material>(path);
|
|
materialSettings.UpgradeToMaterialWorkflowVersion(referenceMaterial);
|
|
}
|
|
}
|
|
|
|
if (version < 15)
|
|
{
|
|
SanitizeHelper.MigrateSGOutputToComposed(this);
|
|
}
|
|
}
|
|
|
|
public override bool CanBeCompiled()
|
|
{
|
|
if (m_IsShaderGraphMissing)
|
|
return false;
|
|
|
|
var sg = GetOrRefreshShaderGraphObject();
|
|
if (sg != null && sg.generatesWithShaderGraph)
|
|
return false;
|
|
|
|
return base.CanBeCompiled();
|
|
}
|
|
|
|
public override void OnSettingModified(VFXSetting setting)
|
|
{
|
|
if (setting.name == nameof(shaderGraph))
|
|
{
|
|
VFXAnalytics.GetInstance().OnSpecificSettingChanged($"{GetType().Name}.{setting.name}");
|
|
}
|
|
}
|
|
|
|
public override void GetImportDependentAssets(HashSet<int> dependencies)
|
|
{
|
|
base.GetImportDependentAssets(dependencies);
|
|
if (!object.ReferenceEquals(shaderGraph, null))
|
|
{
|
|
dependencies.Add(shaderGraph.GetInstanceID());
|
|
}
|
|
}
|
|
|
|
protected VFXShaderGraphParticleOutput(bool strip = false) : base(strip) { }
|
|
|
|
// Here we maintain a list of settings that we do not need if we are using the ShaderGraph generation path (it will be in the material inspector).
|
|
static IEnumerable<string> FilterOutBuiltinSettings()
|
|
{
|
|
yield return "blendMode";
|
|
yield return "cullMode";
|
|
yield return "zWriteMode";
|
|
yield return "zTestMode";
|
|
yield return "excludeFromTUAndAA";
|
|
yield return "preserveSpecularLighting";
|
|
yield return "doubleSided";
|
|
yield return "onlyAmbientLighting";
|
|
yield return "useExposureWeight";
|
|
yield return "alphaThreshold";
|
|
yield return "normalBending";
|
|
}
|
|
|
|
protected override IEnumerable<string> filteredOutSettings
|
|
{
|
|
get
|
|
{
|
|
foreach (var setting in base.filteredOutSettings)
|
|
yield return setting;
|
|
|
|
var sg = GetOrRefreshShaderGraphObject();
|
|
if (sg != null || m_IsShaderGraphMissing)
|
|
{
|
|
yield return "colorMapping";
|
|
yield return "useAlphaClipping";
|
|
|
|
if (m_IsShaderGraphMissing)
|
|
{
|
|
yield return "useSoftParticle";
|
|
yield return "uvMode";
|
|
|
|
foreach (var builtinSetting in FilterOutBuiltinSettings())
|
|
yield return builtinSetting;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
yield return nameof(shaderGraph);
|
|
}
|
|
|
|
yield return nameof(materialSettings);
|
|
}
|
|
}
|
|
|
|
public override bool supportsUV => base.supportsUV && GetOrRefreshShaderGraphObject() == null;
|
|
public override bool exposeAlphaThreshold
|
|
{
|
|
get
|
|
{
|
|
var shaderGraph = GetOrRefreshShaderGraphObject();
|
|
if (shaderGraph == null)
|
|
{
|
|
if (base.exposeAlphaThreshold)
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (!shaderGraph.alphaClipping)
|
|
{
|
|
//alpha clipping isn't enabled in shaderGraph, we implicitly still allows clipping for shadow & motion vector passes.
|
|
if (!isBlendModeOpaque && (hasMotionVector || hasShadowCasting))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
public override bool supportSoftParticles => base.supportSoftParticles && GetOrRefreshShaderGraphObject() == null;
|
|
public override bool hasAlphaClipping
|
|
{
|
|
get
|
|
{
|
|
var shaderGraph = GetOrRefreshShaderGraphObject();
|
|
bool noShaderGraphAlphaThreshold = shaderGraph == null && useAlphaClipping;
|
|
bool ShaderGraphAlphaThreshold = shaderGraph != null && shaderGraph.alphaClipping;
|
|
return noShaderGraphAlphaThreshold || ShaderGraphAlphaThreshold;
|
|
}
|
|
}
|
|
|
|
// Do not resync slots when shader graph is missing to keep potential links to the shader properties
|
|
public override bool ResyncSlots(bool notify) => !m_IsShaderGraphMissing && base.ResyncSlots(notify);
|
|
|
|
public override void CheckGraphBeforeImport()
|
|
{
|
|
base.CheckGraphBeforeImport();
|
|
var currentShaderGraph = GetOrRefreshShaderGraphObject();
|
|
|
|
// If the graph is reimported it can be because one of its dependency such as the shadergraphs, has been changed.
|
|
if (!VFXGraph.explicitCompile)
|
|
{
|
|
ResyncSlots(true);
|
|
|
|
// Ensure that the output context name is in sync with the shader graph shader enum name.
|
|
if (currentShaderGraph != null && currentShaderGraph.generatesWithShaderGraph)
|
|
Invalidate(InvalidationCause.kUIChangedTransient);
|
|
|
|
else if (m_IsShaderGraphMissing)
|
|
{
|
|
var vfxName = GetGraph().visualEffectResource.name;
|
|
Debug.LogError($"The VFX Graph '{vfxName}'" + VFXShaderGraphHelpers.GetMissingShaderGraphErrorMessage(currentShaderGraph));
|
|
}
|
|
}
|
|
}
|
|
|
|
internal override void GenerateErrors(VFXErrorReporter report)
|
|
{
|
|
base.GenerateErrors(report);
|
|
|
|
var currentShaderGraph = GetOrRefreshShaderGraphObject(false);
|
|
if (m_IsShaderGraphMissing)
|
|
{
|
|
var message = VFXShaderGraphHelpers.GetMissingShaderGraphErrorMessage(currentShaderGraph);
|
|
report.RegisterError("ErrorMissingShaderGraph", VFXErrorType.Error, "The VFX Graph" + message, this);
|
|
}
|
|
|
|
if (currentShaderGraph != null)
|
|
{
|
|
if (!currentShaderGraph.generatesWithShaderGraph)
|
|
{
|
|
report.RegisterError("DeprecatedOldShaderGraph", VFXErrorType.Error, ParticleShadingShaderGraph.kErrorOldSG, this);
|
|
}
|
|
else
|
|
{
|
|
//There isn't automatic sanitize if the SG change its status from old to new SG integration
|
|
report.RegisterError("WrongOutputShaderGraph", VFXErrorType.Error, "Please convert this context to dedicated ShaderGraph Output.", this);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override IEnumerable<VFXPropertyWithValue> inputProperties
|
|
{
|
|
get
|
|
{
|
|
IEnumerable<VFXPropertyWithValue> properties = base.inputProperties;
|
|
var sg = GetOrRefreshShaderGraphObject();
|
|
if (sg != null)
|
|
{
|
|
//This path is only used with old shader graph integration. It doesn't support keyword.
|
|
var shaderGraphProperties = VFXShaderGraphHelpers.GetProperties(sg).Where(o => o.keywordsMapping == null).Select(o => o.property);
|
|
properties = properties.Concat(shaderGraphProperties);
|
|
}
|
|
return properties;
|
|
}
|
|
}
|
|
|
|
protected override IEnumerable<VFXNamedExpression> CollectGPUExpressions(IEnumerable<VFXNamedExpression> slotExpressions)
|
|
{
|
|
foreach (var exp in base.CollectGPUExpressions(slotExpressions))
|
|
yield return exp;
|
|
|
|
var shaderGraph = GetOrRefreshShaderGraphObject();
|
|
if (shaderGraph != null)
|
|
{
|
|
foreach (var sgProperty in shaderGraph.properties)
|
|
{
|
|
if (inputSlots.Any(t => t.property.name == sgProperty.referenceName))
|
|
yield return slotExpressions.First(o => o.name == sgProperty.referenceName);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual VFXOldShaderGraphHelpers.RPInfo currentRP
|
|
{
|
|
get { return VFXOldShaderGraphHelpers.hdrpInfo; }
|
|
}
|
|
|
|
public override IEnumerable<string> additionalDefines
|
|
{
|
|
get
|
|
{
|
|
foreach (var def in base.additionalDefines)
|
|
yield return def;
|
|
|
|
var shaderGraph = GetOrRefreshShaderGraphObject();
|
|
if (shaderGraph != null && !shaderGraph.generatesWithShaderGraph)
|
|
{
|
|
foreach (var def in VFXOldShaderGraphHelpers.GetAdditionalDefinesGetAdditionalReplacement(shaderGraph, currentRP, graphCodes))
|
|
yield return def;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override VFXExpressionMapper GetExpressionMapper(VFXDeviceTarget target)
|
|
{
|
|
var mapper = base.GetExpressionMapper(target);
|
|
var shaderGraph = GetOrRefreshShaderGraphObject();
|
|
|
|
switch (target)
|
|
{
|
|
case VFXDeviceTarget.CPU:
|
|
{
|
|
}
|
|
break;
|
|
case VFXDeviceTarget.GPU:
|
|
if (shaderGraph != null)
|
|
{
|
|
foreach (var texture in VFXShaderGraphHelpers.GetTextureConstant(shaderGraph))
|
|
mapper.AddExpression(texture, -1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return mapper;
|
|
}
|
|
|
|
public virtual bool isLitShader { get => false; }
|
|
|
|
Dictionary<string, GraphCode> graphCodes;
|
|
|
|
public override bool SetupCompilation()
|
|
{
|
|
if (!base.SetupCompilation())
|
|
return false;
|
|
|
|
var shaderGraph = GetOrRefreshShaderGraphObject();
|
|
if (shaderGraph != null && !shaderGraph.generatesWithShaderGraph)
|
|
{
|
|
graphCodes = VFXOldShaderGraphHelpers.BuildGraphCode(shaderGraph, currentRP, isLitShader);
|
|
return graphCodes != null;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override void EndCompilation()
|
|
{
|
|
graphCodes = null;
|
|
}
|
|
|
|
public override IEnumerable<KeyValuePair<string, VFXShaderWriter>> additionalReplacements
|
|
{
|
|
get
|
|
{
|
|
foreach (var rep in base.additionalReplacements)
|
|
yield return rep;
|
|
|
|
var shaderGraph = GetOrRefreshShaderGraphObject();
|
|
if (shaderGraph != null && !shaderGraph.generatesWithShaderGraph)
|
|
{
|
|
foreach (var def in VFXOldShaderGraphHelpers.GetAdditionalReplacement(shaderGraph, currentRP, graphCodes, taskType == VFXTaskType.ParticleMeshOutput))
|
|
yield return def;
|
|
}
|
|
}
|
|
}
|
|
|
|
public ShaderGraphVfxAsset GetShaderGraph()
|
|
{
|
|
var shaderGraph = GetOrRefreshShaderGraphObject();
|
|
return shaderGraph;
|
|
}
|
|
}
|
|
}
|