VFXShaderGraphParticleOutput.cs 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Text;
  7. using UnityEditor.ShaderGraph.Internal;
  8. using UnityEngine;
  9. using UnityEngine.Rendering;
  10. using UnityObject = UnityEngine.Object;
  11. namespace UnityEditor.VFX
  12. {
  13. [CustomEditor(typeof(VFXShaderGraphParticleOutput), true)]
  14. [CanEditMultipleObjects]
  15. class VFXShaderGraphParticleOutputEditor : VFXContextEditor
  16. {
  17. private MaterialEditor m_MaterialEditor = null;
  18. private bool m_RequireUpdateMaterialEditor = false;
  19. private void RequireUpdateMaterialEditor() => m_RequireUpdateMaterialEditor = true;
  20. protected new void OnEnable()
  21. {
  22. UpdateMaterialEditor();
  23. foreach (VFXShaderGraphParticleOutput output in targets)
  24. {
  25. if (output != null)
  26. output.OnMaterialChange += RequireUpdateMaterialEditor;
  27. }
  28. base.OnEnable();
  29. }
  30. protected new void OnDisable()
  31. {
  32. foreach (VFXShaderGraphParticleOutput output in targets)
  33. {
  34. if (output != null)
  35. output.OnMaterialChange -= RequireUpdateMaterialEditor;
  36. }
  37. DestroyImmediate(m_MaterialEditor);
  38. base.OnDisable();
  39. }
  40. void UpdateMaterialEditor()
  41. {
  42. var material = ((VFXShaderGraphParticleOutput)target).transientMaterial;
  43. if (material != null)
  44. {
  45. m_MaterialEditor = (MaterialEditor)CreateEditor(material);
  46. m_MaterialEditor.firstInspectedEditor = true;
  47. }
  48. }
  49. public override void DisplayWarnings()
  50. {
  51. base.DisplayWarnings();
  52. if (m_MaterialEditor != null && m_MaterialEditor.target != null && VFXLibrary.currentSRPBinder != null)
  53. {
  54. var shaderGraphParticleOutput = (VFXShaderGraphParticleOutput)target;
  55. var shaderGraph = shaderGraphParticleOutput.GetOrRefreshShaderGraphObject();
  56. var materialShadowOverride = VFXLibrary.currentSRPBinder.TryGetCastShadowFromMaterial(shaderGraph, shaderGraphParticleOutput.materialSettings, out var castShadow);
  57. var materialSortingPriorityOverride = VFXLibrary.currentSRPBinder.TryGetQueueOffset(shaderGraph, shaderGraphParticleOutput.materialSettings, out var queueOffset) && shaderGraphParticleOutput.subOutput.supportsSortingPriority;
  58. // Indicate material override from shaderGraph which is hiding output properties.
  59. if (materialShadowOverride || materialSortingPriorityOverride)
  60. {
  61. var msg = new StringBuilder("The ShaderGraph material is overriding some settings:");
  62. if (materialShadowOverride)
  63. msg.AppendFormat("\n - Cast Shadow = {0}", castShadow ? "true" : "false");
  64. if (materialSortingPriorityOverride)
  65. msg.AppendFormat("\n - Sorting Priority = {0}", queueOffset);
  66. EditorGUILayout.HelpBox(msg.ToString(), MessageType.Info);
  67. }
  68. // Indicate caution to the user if transparent motion vectors are disabled and motion vectors are enabled.
  69. if (shaderGraphParticleOutput.hasMotionVector &&
  70. (shaderGraphParticleOutput.GetMaterialBlendMode() != VFXAbstractRenderedOutput.BlendMode.Opaque &&
  71. !VFXLibrary.currentSRPBinder.TransparentMotionVectorEnabled(m_MaterialEditor.target as Material)))
  72. {
  73. EditorGUILayout.HelpBox("Transparent Motion Vectors pass is disabled. Consider disabling Generate Motion Vector to improve performance.", MessageType.Warning);
  74. }
  75. }
  76. }
  77. public override void OnInspectorGUI()
  78. {
  79. if (targets.OfType<VFXShaderGraphParticleOutput>().Any(context => context.GetOrRefreshShaderGraphObject() == null))
  80. {
  81. base.OnInspectorGUI();
  82. return;
  83. }
  84. serializedObject.Update();
  85. if (m_RequireUpdateMaterialEditor)
  86. {
  87. UpdateMaterialEditor();
  88. m_RequireUpdateMaterialEditor = false;
  89. }
  90. var materialChanged = false;
  91. var previousBlendMode = ((VFXShaderGraphParticleOutput)target).GetMaterialBlendMode();
  92. if (m_MaterialEditor != null)
  93. {
  94. if (m_MaterialEditor.target == null || (m_MaterialEditor.target as Material)?.shader == null)
  95. {
  96. EditorGUILayout.HelpBox("Material Destroyed.", MessageType.Warning);
  97. }
  98. else
  99. {
  100. using (new EditorGUI.DisabledScope(true))
  101. {
  102. // Required to draw the header to draw OnInspectorGUI.
  103. m_MaterialEditor.DrawHeader();
  104. }
  105. EditorGUI.BeginChangeCheck();
  106. // This will correctly handle the configuration of keyword and pass setup.
  107. m_MaterialEditor.OnInspectorGUI();
  108. materialChanged = EditorGUI.EndChangeCheck();
  109. }
  110. }
  111. base.OnInspectorGUI();
  112. if (serializedObject.ApplyModifiedProperties())
  113. {
  114. foreach (var context in targets.OfType<VFXShaderGraphParticleOutput>())
  115. context.Invalidate(VFXModel.InvalidationCause.kSettingChanged);
  116. }
  117. if (materialChanged)
  118. {
  119. foreach (var context in targets.OfType<VFXShaderGraphParticleOutput>())
  120. {
  121. context.UpdateMaterialSettings();
  122. var currentBlendMode = ((VFXShaderGraphParticleOutput)target).GetMaterialBlendMode();
  123. // If the blend mode is changed to one that may require sorting (Auto), we require a full recompilation.
  124. if (previousBlendMode != currentBlendMode)
  125. context.Invalidate(VFXModel.InvalidationCause.kSettingChanged);
  126. else
  127. context.Invalidate(VFXModel.InvalidationCause.kMaterialChanged);
  128. }
  129. }
  130. }
  131. }
  132. class VFXShaderGraphParticleOutput : VFXAbstractParticleOutput
  133. {
  134. //"protected" is only to be listed by VFXModel.GetSettings, we should always use GetOrRefreshShaderGraphObject
  135. [SerializeField, VFXSetting]
  136. protected ShaderGraphVfxAsset shaderGraph;
  137. [SerializeField]
  138. internal VFXMaterialSerializedSettings materialSettings = new VFXMaterialSerializedSettings();
  139. public event Action OnMaterialChange;
  140. internal Material transientMaterial;
  141. public ShaderGraphVfxAsset GetOrRefreshShaderGraphObject()
  142. {
  143. //This is the only place where shaderGraph property is updated or read
  144. if (shaderGraph == null && !object.ReferenceEquals(shaderGraph, null))
  145. {
  146. string assetPath = AssetDatabase.GetAssetPath(shaderGraph.GetInstanceID());
  147. var newShaderGraph = AssetDatabase.LoadAssetAtPath<ShaderGraphVfxAsset>(assetPath);
  148. if (newShaderGraph != null)
  149. {
  150. shaderGraph = newShaderGraph;
  151. }
  152. }
  153. return shaderGraph;
  154. }
  155. public override bool hasShadowCasting
  156. {
  157. get
  158. {
  159. var shaderGraph = GetOrRefreshShaderGraphObject();
  160. if (shaderGraph != null && shaderGraph.generatesWithShaderGraph && VFXLibrary.currentSRPBinder != null)
  161. {
  162. if (VFXLibrary.currentSRPBinder.TryGetCastShadowFromMaterial(shaderGraph, materialSettings, out var castShadows))
  163. {
  164. return castShadows;
  165. }
  166. }
  167. return base.hasShadowCasting;
  168. }
  169. }
  170. public override int GetMaterialSortingPriority()
  171. {
  172. var shaderGraph = GetOrRefreshShaderGraphObject();
  173. if (shaderGraph != null && shaderGraph.generatesWithShaderGraph && VFXLibrary.currentSRPBinder != null)
  174. {
  175. if (VFXLibrary.currentSRPBinder.TryGetQueueOffset(shaderGraph, materialSettings, out var queueOffset))
  176. {
  177. return queueOffset;
  178. }
  179. }
  180. return sortingPriority;
  181. }
  182. public override bool SupportsMotionVectorPerVertex(out uint vertsCount)
  183. {
  184. var support = base.SupportsMotionVectorPerVertex(out vertsCount);
  185. var shaderGraph = GetOrRefreshShaderGraphObject();
  186. if (shaderGraph != null && shaderGraph.generatesWithShaderGraph && VFXLibrary.currentSRPBinder != null)
  187. {
  188. support = support && VFXLibrary.currentSRPBinder.GetSupportsMotionVectorPerVertex(shaderGraph, materialSettings);
  189. }
  190. return support;
  191. }
  192. public BlendMode GetMaterialBlendMode()
  193. {
  194. var blendMode = BlendMode.Opaque;
  195. var shaderGraph = GetOrRefreshShaderGraphObject();
  196. if (shaderGraph != null && shaderGraph.generatesWithShaderGraph && VFXLibrary.currentSRPBinder != null)
  197. {
  198. // VFX Blend Mode state configures important systems like sorting and indirect buffer.
  199. // In the case of SG Generation path, we need to know the blend mode state of the SRP
  200. // Material to configure the VFX blend mode.
  201. blendMode = VFXLibrary.currentSRPBinder.GetBlendModeFromMaterial(shaderGraph, materialSettings);
  202. }
  203. return blendMode;
  204. }
  205. public override void SetupMaterial(Material material)
  206. {
  207. var shaderGraph = GetOrRefreshShaderGraphObject();
  208. if (shaderGraph != null && shaderGraph.generatesWithShaderGraph)
  209. {
  210. // In certain scenarios the context might not be configured with any serialized material information
  211. // when assigned a shader graph for the first time. In this case we sync the settings to the incoming material,
  212. // which will be pre-configured by shader graph with the render state & other properties (i.e. a SG with Transparent surface).
  213. if (materialSettings.NeedsSync())
  214. {
  215. materialSettings.SyncFromMaterial(material);
  216. Invalidate(InvalidationCause.kSettingChanged);
  217. return;
  218. }
  219. materialSettings.ApplyToMaterial(material);
  220. VFXLibrary.currentSRPBinder.SetupMaterial(material, hasMotionVector, hasShadowCasting, shaderGraph);
  221. transientMaterial = material;
  222. OnMaterialChange?.Invoke();
  223. }
  224. }
  225. public void UpdateMaterialSettings()
  226. {
  227. if (transientMaterial != null)
  228. {
  229. materialSettings.SyncFromMaterial(transientMaterial);
  230. }
  231. }
  232. public override void GetImportDependentAssets(HashSet<int> dependencies)
  233. {
  234. base.GetImportDependentAssets(dependencies);
  235. if (!object.ReferenceEquals(shaderGraph, null))
  236. dependencies.Add(shaderGraph.GetInstanceID());
  237. }
  238. protected VFXShaderGraphParticleOutput(bool strip = false) : base(strip) { }
  239. static Type GetSGPropertyType(AbstractShaderProperty property)
  240. {
  241. switch (property.propertyType)
  242. {
  243. case PropertyType.Color:
  244. return typeof(Color);
  245. case PropertyType.Texture2D:
  246. return typeof(Texture2D);
  247. case PropertyType.Texture2DArray:
  248. return typeof(Texture2DArray);
  249. case PropertyType.Texture3D:
  250. return typeof(Texture3D);
  251. case PropertyType.Cubemap:
  252. return typeof(Cubemap);
  253. case PropertyType.Gradient:
  254. return null;
  255. case PropertyType.Boolean:
  256. return typeof(bool);
  257. case PropertyType.Float:
  258. return typeof(float);
  259. case PropertyType.Vector2:
  260. return typeof(Vector2);
  261. case PropertyType.Vector3:
  262. return typeof(Vector3);
  263. case PropertyType.Vector4:
  264. return typeof(Vector4);
  265. case PropertyType.Matrix2:
  266. return null;
  267. case PropertyType.Matrix3:
  268. return null;
  269. case PropertyType.Matrix4:
  270. return typeof(Matrix4x4);
  271. case PropertyType.SamplerState:
  272. default:
  273. return null;
  274. }
  275. }
  276. public static object GetSGPropertyValue(AbstractShaderProperty property)
  277. {
  278. switch (property.propertyType)
  279. {
  280. case PropertyType.Texture2D:
  281. return ((Texture2DShaderProperty)property).value.texture;
  282. case PropertyType.Texture3D:
  283. return ((Texture3DShaderProperty)property).value.texture;
  284. case PropertyType.Cubemap:
  285. return ((CubemapShaderProperty)property).value.cubemap;
  286. case PropertyType.Texture2DArray:
  287. return ((Texture2DArrayShaderProperty)property).value.textureArray;
  288. default:
  289. {
  290. var type = GetSGPropertyType(property);
  291. PropertyInfo info = property.GetType().GetProperty("value", BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
  292. return VFXConverter.ConvertTo(info?.GetValue(property), type);
  293. }
  294. }
  295. }
  296. public override bool HasSorting()
  297. {
  298. var materialBlendMode = GetMaterialBlendMode();
  299. return base.HasSorting() || ((sort == SortMode.Auto && (materialBlendMode == BlendMode.Alpha || materialBlendMode == BlendMode.AlphaPremultiplied)) && !HasStrips(true));
  300. }
  301. public override bool isBlendModeOpaque
  302. {
  303. get
  304. {
  305. if (GetOrRefreshShaderGraphObject() != null &&
  306. GetOrRefreshShaderGraphObject().generatesWithShaderGraph)
  307. return GetMaterialBlendMode() == BlendMode.Opaque;
  308. return base.isBlendModeOpaque;
  309. }
  310. }
  311. protected string shaderName
  312. {
  313. get
  314. {
  315. var shaderGraph = GetOrRefreshShaderGraphObject();
  316. if (shaderGraph == null || !shaderGraph.generatesWithShaderGraph || VFXLibrary.currentSRPBinder == null)
  317. return string.Empty;
  318. return VFXLibrary.currentSRPBinder.GetShaderName(shaderGraph);
  319. }
  320. }
  321. // 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).
  322. static IEnumerable<string> FilterOutBuiltinSettings()
  323. {
  324. yield return "blendMode";
  325. yield return "cullMode";
  326. yield return "zWriteMode";
  327. yield return "zTestMode";
  328. yield return "excludeFromTAA";
  329. yield return "preserveSpecularLighting";
  330. yield return "doubleSided";
  331. yield return "onlyAmbientLighting";
  332. yield return "useExposureWeight";
  333. yield return "alphaThreshold";
  334. yield return "normalBending";
  335. }
  336. protected override IEnumerable<string> filteredOutSettings
  337. {
  338. get
  339. {
  340. foreach (var setting in base.filteredOutSettings)
  341. yield return setting;
  342. if (GetOrRefreshShaderGraphObject() != null)
  343. {
  344. yield return "colorMapping";
  345. yield return "useAlphaClipping";
  346. if (shaderGraph.generatesWithShaderGraph)
  347. {
  348. foreach (var builtinSetting in FilterOutBuiltinSettings())
  349. yield return builtinSetting;
  350. if (VFXLibrary.currentSRPBinder != null)
  351. {
  352. if (VFXLibrary.currentSRPBinder.TryGetCastShadowFromMaterial(shaderGraph, materialSettings, out var castShadow))
  353. yield return nameof(castShadows);
  354. if (VFXLibrary.currentSRPBinder.TryGetQueueOffset(shaderGraph, materialSettings, out var queueOffset))
  355. yield return nameof(sortingPriority);
  356. }
  357. }
  358. }
  359. if (!VFXViewPreference.displayExperimentalOperator)
  360. yield return "shaderGraph";
  361. }
  362. }
  363. public override bool supportsUV => base.supportsUV && GetOrRefreshShaderGraphObject() == null;
  364. public override bool exposeAlphaThreshold
  365. {
  366. get
  367. {
  368. var shaderGraph = GetOrRefreshShaderGraphObject();
  369. if (shaderGraph == null)
  370. {
  371. if (base.exposeAlphaThreshold)
  372. return true;
  373. }
  374. else
  375. {
  376. if (shaderGraph.generatesWithShaderGraph)
  377. return false;
  378. if (!shaderGraph.alphaClipping)
  379. {
  380. //alpha clipping isn't enabled in shaderGraph, we implicitly still allows clipping for shadow & motion vector passes.
  381. if (!isBlendModeOpaque && (hasMotionVector || hasShadowCasting))
  382. return true;
  383. }
  384. }
  385. return false;
  386. }
  387. }
  388. public override bool supportSoftParticles => base.supportSoftParticles && GetOrRefreshShaderGraphObject() == null;
  389. public override bool hasAlphaClipping
  390. {
  391. get
  392. {
  393. var shaderGraph = GetOrRefreshShaderGraphObject();
  394. bool noShaderGraphAlphaThreshold = shaderGraph == null && useAlphaClipping;
  395. bool ShaderGraphAlphaThreshold = shaderGraph != null && shaderGraph.alphaClipping;
  396. return noShaderGraphAlphaThreshold || ShaderGraphAlphaThreshold;
  397. }
  398. }
  399. public override void CheckGraphBeforeImport()
  400. {
  401. base.CheckGraphBeforeImport();
  402. // If the graph is reimported it can be because one of its depedency such as the shadergraphs, has been changed.
  403. if (!VFXGraph.explicitCompile)
  404. {
  405. ResyncSlots(true);
  406. // Ensure that the output context name is in sync with the shader graph shader enum name.
  407. if (GetOrRefreshShaderGraphObject() != null &&
  408. GetOrRefreshShaderGraphObject().generatesWithShaderGraph)
  409. Invalidate(InvalidationCause.kUIChangedTransient);
  410. }
  411. }
  412. protected override IEnumerable<VFXPropertyWithValue> inputProperties
  413. {
  414. get
  415. {
  416. IEnumerable<VFXPropertyWithValue> properties = base.inputProperties;
  417. var shaderGraph = GetOrRefreshShaderGraphObject();
  418. if (shaderGraph != null)
  419. {
  420. var shaderGraphProperties = new List<VFXPropertyWithValue>();
  421. foreach (var property in shaderGraph.properties
  422. .Where(t => !t.hidden)
  423. .Select(t => new { property = t, type = GetSGPropertyType(t) })
  424. .Where(t => t.type != null))
  425. {
  426. if (property.property.propertyType == PropertyType.Float)
  427. {
  428. var prop = property.property as Vector1ShaderProperty;
  429. if (prop != null)
  430. {
  431. if (prop.floatType == FloatType.Slider)
  432. shaderGraphProperties.Add(new VFXPropertyWithValue(new VFXProperty(property.type, property.property.referenceName, new RangeAttribute(prop.rangeValues.x, prop.rangeValues.y)), GetSGPropertyValue(property.property)));
  433. else if (prop.floatType == FloatType.Integer)
  434. shaderGraphProperties.Add(new VFXPropertyWithValue(new VFXProperty(typeof(int), property.property.referenceName), VFXConverter.ConvertTo(GetSGPropertyValue(property.property), typeof(int))));
  435. else
  436. shaderGraphProperties.Add(new VFXPropertyWithValue(new VFXProperty(property.type, property.property.referenceName), GetSGPropertyValue(property.property)));
  437. }
  438. }
  439. else
  440. shaderGraphProperties.Add(new VFXPropertyWithValue(new VFXProperty(property.type, property.property.referenceName), GetSGPropertyValue(property.property)));
  441. }
  442. properties = properties.Concat(shaderGraphProperties);
  443. }
  444. return properties;
  445. }
  446. }
  447. protected class PassInfo
  448. {
  449. public int[] vertexPorts;
  450. public int[] pixelPorts;
  451. }
  452. protected class RPInfo
  453. {
  454. public Dictionary<string, PassInfo> passInfos;
  455. HashSet<int> m_AllPorts;
  456. public IEnumerable<int> allPorts
  457. {
  458. get
  459. {
  460. if (m_AllPorts == null)
  461. {
  462. m_AllPorts = new HashSet<int>();
  463. foreach (var pass in passInfos.Values)
  464. {
  465. foreach (var port in pass.vertexPorts)
  466. m_AllPorts.Add(port);
  467. foreach (var port in pass.pixelPorts)
  468. m_AllPorts.Add(port);
  469. }
  470. }
  471. return m_AllPorts;
  472. }
  473. }
  474. }
  475. protected static readonly RPInfo hdrpInfo = new RPInfo
  476. {
  477. passInfos = new Dictionary<string, PassInfo>()
  478. {
  479. { "Forward", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.ColorSlotId, ShaderGraphVfxAsset.EmissiveSlotId, ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } },
  480. { "DepthOnly", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } }
  481. }
  482. };
  483. protected static readonly RPInfo hdrpLitInfo = new RPInfo
  484. {
  485. passInfos = new Dictionary<string, PassInfo>()
  486. {
  487. { "GBuffer", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.BaseColorSlotId, ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.MetallicSlotId, ShaderGraphVfxAsset.SmoothnessSlotId, ShaderGraphVfxAsset.EmissiveSlotId, ShaderGraphVfxAsset.NormalSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } },
  488. { "Forward", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.BaseColorSlotId, ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.MetallicSlotId, ShaderGraphVfxAsset.SmoothnessSlotId, ShaderGraphVfxAsset.EmissiveSlotId, ShaderGraphVfxAsset.NormalSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } },
  489. { "DepthOnly", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } }
  490. }
  491. };
  492. protected static readonly RPInfo urpLitInfo = new RPInfo
  493. {
  494. passInfos = new Dictionary<string, PassInfo>()
  495. {
  496. { "GBuffer", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.BaseColorSlotId, ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.MetallicSlotId, ShaderGraphVfxAsset.SmoothnessSlotId, ShaderGraphVfxAsset.EmissiveSlotId, ShaderGraphVfxAsset.NormalSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } },
  497. { "Forward", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.BaseColorSlotId, ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.MetallicSlotId, ShaderGraphVfxAsset.SmoothnessSlotId, ShaderGraphVfxAsset.EmissiveSlotId, ShaderGraphVfxAsset.NormalSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } },
  498. { "DepthOnly", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } },
  499. { "DepthNormals", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId, ShaderGraphVfxAsset.NormalSlotId } } }
  500. }
  501. };
  502. protected override IEnumerable<VFXNamedExpression> CollectGPUExpressions(IEnumerable<VFXNamedExpression> slotExpressions)
  503. {
  504. foreach (var exp in base.CollectGPUExpressions(slotExpressions))
  505. yield return exp;
  506. var shaderGraph = GetOrRefreshShaderGraphObject();
  507. if (shaderGraph != null)
  508. {
  509. foreach (var sgProperty in shaderGraph.properties)
  510. {
  511. if (inputSlots.Any(t => t.property.name == sgProperty.referenceName))
  512. yield return slotExpressions.First(o => o.name == sgProperty.referenceName);
  513. }
  514. }
  515. }
  516. public override IEnumerable<string> additionalDefines
  517. {
  518. get
  519. {
  520. foreach (var def in base.additionalDefines)
  521. yield return def;
  522. var shaderGraph = GetOrRefreshShaderGraphObject();
  523. if (shaderGraph != null)
  524. {
  525. yield return "VFX_SHADERGRAPH";
  526. RPInfo info = currentRP;
  527. foreach (var port in info.allPorts)
  528. {
  529. var portInfo = shaderGraph.GetOutput(port);
  530. if (!string.IsNullOrEmpty(portInfo.referenceName))
  531. yield return $"HAS_SHADERGRAPH_PARAM_{portInfo.referenceName.ToUpper(CultureInfo.InvariantCulture)}";
  532. }
  533. bool needsPosWS = false;
  534. // Per pass define
  535. foreach (var kvPass in graphCodes)
  536. {
  537. GraphCode graphCode = kvPass.Value;
  538. var pixelPorts = currentRP.passInfos[kvPass.Key].pixelPorts;
  539. bool readsNormal = (graphCode.requirements.requiresNormal & ~NeededCoordinateSpace.Tangent) != 0;
  540. bool readsTangent = (graphCode.requirements.requiresTangent & ~NeededCoordinateSpace.Tangent) != 0 ||
  541. (graphCode.requirements.requiresBitangent & ~NeededCoordinateSpace.Tangent) != 0 ||
  542. (graphCode.requirements.requiresViewDir & NeededCoordinateSpace.Tangent) != 0;
  543. bool hasNormalPort = pixelPorts.Any(t => t == ShaderGraphVfxAsset.NormalSlotId) && shaderGraph.HasOutput(ShaderGraphVfxAsset.NormalSlotId);
  544. if (readsNormal || readsTangent || hasNormalPort) // needs normal
  545. yield return $"SHADERGRAPH_NEEDS_NORMAL_{kvPass.Key.ToUpper(CultureInfo.InvariantCulture)}";
  546. if (readsTangent || hasNormalPort) // needs tangent
  547. yield return $"SHADERGRAPH_NEEDS_TANGENT_{kvPass.Key.ToUpper(CultureInfo.InvariantCulture)}";
  548. needsPosWS |= graphCode.requirements.requiresPosition != NeededCoordinateSpace.None ||
  549. graphCode.requirements.requiresScreenPosition ||
  550. graphCode.requirements.requiresViewDir != NeededCoordinateSpace.None;
  551. }
  552. // TODO Put that per pass ?
  553. if (needsPosWS)
  554. yield return "VFX_NEEDS_POSWS_INTERPOLATOR";
  555. }
  556. }
  557. }
  558. protected virtual RPInfo currentRP
  559. {
  560. get { return hdrpInfo; }
  561. }
  562. public override VFXExpressionMapper GetExpressionMapper(VFXDeviceTarget target)
  563. {
  564. var mapper = base.GetExpressionMapper(target);
  565. var shaderGraph = GetOrRefreshShaderGraphObject();
  566. switch (target)
  567. {
  568. case VFXDeviceTarget.CPU:
  569. {
  570. }
  571. break;
  572. case VFXDeviceTarget.GPU:
  573. if (shaderGraph != null)
  574. {
  575. foreach (var tex in shaderGraph.textureInfos)
  576. {
  577. switch (tex.dimension)
  578. {
  579. default:
  580. case TextureDimension.Tex2D:
  581. mapper.AddExpression(new VFXTexture2DValue(tex.instanceID, VFXValue.Mode.Variable), tex.name, -1);
  582. break;
  583. case TextureDimension.Tex3D:
  584. mapper.AddExpression(new VFXTexture3DValue(tex.instanceID, VFXValue.Mode.Variable), tex.name, -1);
  585. break;
  586. case TextureDimension.Cube:
  587. mapper.AddExpression(new VFXTextureCubeValue(tex.instanceID, VFXValue.Mode.Variable), tex.name, -1);
  588. break;
  589. case TextureDimension.Tex2DArray:
  590. mapper.AddExpression(new VFXTexture2DArrayValue(tex.instanceID, VFXValue.Mode.Variable), tex.name, -1);
  591. break;
  592. case TextureDimension.CubeArray:
  593. mapper.AddExpression(new VFXTextureCubeArrayValue(tex.instanceID, VFXValue.Mode.Variable), tex.name, -1);
  594. break;
  595. }
  596. }
  597. }
  598. break;
  599. }
  600. return mapper;
  601. }
  602. static bool IsTexture(PropertyType type)
  603. {
  604. switch (type)
  605. {
  606. case PropertyType.Texture2D:
  607. case PropertyType.Texture2DArray:
  608. case PropertyType.Texture3D:
  609. case PropertyType.Cubemap:
  610. return true;
  611. default:
  612. return false;
  613. }
  614. }
  615. public override IEnumerable<string> fragmentParameters
  616. {
  617. get
  618. {
  619. var shaderGraph = GetOrRefreshShaderGraphObject();
  620. if (shaderGraph != null)
  621. foreach (var param in shaderGraph.properties)
  622. if (!IsTexture(param.propertyType)) // Remove exposed textures from list of interpolants
  623. yield return param.referenceName;
  624. }
  625. }
  626. public override IEnumerable<string> vertexParameters
  627. {
  628. get
  629. {
  630. var shaderGraph = GetOrRefreshShaderGraphObject();
  631. if (shaderGraph != null)
  632. foreach (var param in shaderGraph.vertexProperties)
  633. if (!IsTexture(param.propertyType)) // Remove exposed textures from list of interpolants
  634. yield return param.referenceName;
  635. }
  636. }
  637. public virtual bool isLitShader { get => false; }
  638. Dictionary<string, GraphCode> graphCodes;
  639. public override bool SetupCompilation()
  640. {
  641. if (!base.SetupCompilation()) return false;
  642. var shaderGraph = GetOrRefreshShaderGraphObject();
  643. if (shaderGraph != null)
  644. {
  645. if (!isLitShader && shaderGraph.lit && !shaderGraph.generatesWithShaderGraph)
  646. {
  647. Debug.LogError("You must use an unlit vfx master node with an unlit output");
  648. return false;
  649. }
  650. if (isLitShader && !shaderGraph.lit && !shaderGraph.generatesWithShaderGraph)
  651. {
  652. Debug.LogError("You must use a lit vfx master node with a lit output");
  653. return false;
  654. }
  655. graphCodes = currentRP.passInfos.ToDictionary(t => t.Key, t => shaderGraph.GetCode(t.Value.pixelPorts.Select(u => shaderGraph.GetOutput(u)).Where(u => !string.IsNullOrEmpty(u.referenceName)).ToArray()));
  656. }
  657. return true;
  658. }
  659. public override void EndCompilation()
  660. {
  661. if (graphCodes != null)
  662. graphCodes.Clear();
  663. }
  664. public override IEnumerable<KeyValuePair<string, VFXShaderWriter>> additionalReplacements
  665. {
  666. get
  667. {
  668. foreach (var rep in base.additionalReplacements)
  669. yield return rep;
  670. var shaderGraph = GetOrRefreshShaderGraphObject();
  671. if (shaderGraph != null)
  672. {
  673. RPInfo info = currentRP;
  674. foreach (var port in info.allPorts)
  675. {
  676. var portInfo = shaderGraph.GetOutput(port);
  677. if (!string.IsNullOrEmpty(portInfo.referenceName))
  678. yield return new KeyValuePair<string, VFXShaderWriter>($"${{SHADERGRAPH_PARAM_{portInfo.referenceName.ToUpper(CultureInfo.InvariantCulture)}}}", new VFXShaderWriter($"{portInfo.referenceName}_{portInfo.id}"));
  679. }
  680. foreach (var kvPass in graphCodes)
  681. {
  682. GraphCode graphCode = kvPass.Value;
  683. var preProcess = new VFXShaderWriter();
  684. if (graphCode.requirements.requiresCameraOpaqueTexture)
  685. preProcess.WriteLine("#define REQUIRE_OPAQUE_TEXTURE");
  686. if (graphCode.requirements.requiresDepthTexture)
  687. preProcess.WriteLine("#define REQUIRE_DEPTH_TEXTURE");
  688. preProcess.WriteLine("${VFXShaderGraphFunctionsInclude}\n");
  689. yield return new KeyValuePair<string, VFXShaderWriter>("${SHADERGRAPH_PIXEL_CODE_" + kvPass.Key.ToUpper(CultureInfo.InvariantCulture) + "}", new VFXShaderWriter(preProcess.ToString() + graphCode.code));
  690. var callSG = new VFXShaderWriter("//Call Shader Graph\n");
  691. callSG.builder.AppendLine($"{shaderGraph.inputStructName} INSG = ({shaderGraph.inputStructName})0;");
  692. if (graphCode.requirements.requiresNormal != NeededCoordinateSpace.None)
  693. {
  694. callSG.builder.AppendLine("float3 WorldSpaceNormal = normalize(normalWS.xyz);");
  695. if ((graphCode.requirements.requiresNormal & NeededCoordinateSpace.World) != 0)
  696. callSG.builder.AppendLine("INSG.WorldSpaceNormal = WorldSpaceNormal;");
  697. if ((graphCode.requirements.requiresNormal & NeededCoordinateSpace.Object) != 0)
  698. callSG.builder.AppendLine("INSG.ObjectSpaceNormal = mul(WorldSpaceNormal, (float3x3)UNITY_MATRIX_M);");
  699. if ((graphCode.requirements.requiresNormal & NeededCoordinateSpace.View) != 0)
  700. callSG.builder.AppendLine("INSG.ViewSpaceNormal = mul(WorldSpaceNormal, (float3x3)UNITY_MATRIX_I_V);");
  701. if ((graphCode.requirements.requiresNormal & NeededCoordinateSpace.Tangent) != 0)
  702. callSG.builder.AppendLine("INSG.TangentSpaceNormal = float3(0.0f, 0.0f, 1.0f);");
  703. }
  704. if (graphCode.requirements.requiresTangent != NeededCoordinateSpace.None)
  705. {
  706. callSG.builder.AppendLine("float3 WorldSpaceTangent = normalize(tangentWS.xyz);");
  707. if ((graphCode.requirements.requiresTangent & NeededCoordinateSpace.World) != 0)
  708. callSG.builder.AppendLine("INSG.WorldSpaceTangent = WorldSpaceTangent;");
  709. if ((graphCode.requirements.requiresTangent & NeededCoordinateSpace.Object) != 0)
  710. callSG.builder.AppendLine("INSG.ObjectSpaceTangent = TransformWorldToObjectDir(WorldSpaceTangent);");
  711. if ((graphCode.requirements.requiresTangent & NeededCoordinateSpace.View) != 0)
  712. callSG.builder.AppendLine("INSG.ViewSpaceTangent = TransformWorldToViewDir(WorldSpaceTangent);");
  713. if ((graphCode.requirements.requiresTangent & NeededCoordinateSpace.Tangent) != 0)
  714. callSG.builder.AppendLine("INSG.TangentSpaceTangent = float3(1.0f, 0.0f, 0.0f);");
  715. }
  716. if (graphCode.requirements.requiresBitangent != NeededCoordinateSpace.None)
  717. {
  718. callSG.builder.AppendLine("float3 WorldSpaceBiTangent = normalize(bitangentWS.xyz);");
  719. if ((graphCode.requirements.requiresBitangent & NeededCoordinateSpace.World) != 0)
  720. callSG.builder.AppendLine("INSG.WorldSpaceBiTangent = WorldSpaceBiTangent;");
  721. if ((graphCode.requirements.requiresBitangent & NeededCoordinateSpace.Object) != 0)
  722. callSG.builder.AppendLine("INSG.ObjectSpaceBiTangent = TransformWorldToObjectDir(WorldSpaceBiTangent);");
  723. if ((graphCode.requirements.requiresBitangent & NeededCoordinateSpace.View) != 0)
  724. callSG.builder.AppendLine("INSG.ViewSpaceBiTangent = TransformWorldToViewDir(WorldSpaceBiTangent);");
  725. if ((graphCode.requirements.requiresBitangent & NeededCoordinateSpace.Tangent) != 0)
  726. callSG.builder.AppendLine("INSG.TangentSpaceBiTangent = float3(0.0f, 1.0f, 0.0f);");
  727. }
  728. if (graphCode.requirements.requiresPosition != NeededCoordinateSpace.None || graphCode.requirements.requiresScreenPosition || graphCode.requirements.requiresViewDir != NeededCoordinateSpace.None)
  729. {
  730. callSG.builder.AppendLine("float3 posRelativeWS = VFXGetPositionRWS(i.VFX_VARYING_POSWS);");
  731. callSG.builder.AppendLine("float3 posAbsoluteWS = VFXGetPositionAWS(i.VFX_VARYING_POSWS);");
  732. if ((graphCode.requirements.requiresPosition & NeededCoordinateSpace.World) != 0)
  733. callSG.builder.AppendLine("INSG.WorldSpacePosition = posRelativeWS;");
  734. if ((graphCode.requirements.requiresPosition & NeededCoordinateSpace.Object) != 0)
  735. callSG.builder.AppendLine("INSG.ObjectSpacePosition = TransformWorldToObject(posRelativeWS);");
  736. if ((graphCode.requirements.requiresPosition & NeededCoordinateSpace.View) != 0)
  737. callSG.builder.AppendLine("INSG.ViewSpacePosition = VFXTransformPositionWorldToView(posRelativeWS);");
  738. if ((graphCode.requirements.requiresPosition & NeededCoordinateSpace.Tangent) != 0)
  739. callSG.builder.AppendLine("INSG.TangentSpacePosition = float3(0.0f, 0.0f, 0.0f);");
  740. if ((graphCode.requirements.requiresPosition & NeededCoordinateSpace.AbsoluteWorld) != 0)
  741. callSG.builder.AppendLine("INSG.AbsoluteWorldSpacePosition = posAbsoluteWS;");
  742. if (graphCode.requirements.requiresPositionPredisplacement != NeededCoordinateSpace.None)
  743. {
  744. if ((graphCode.requirements.requiresPositionPredisplacement & NeededCoordinateSpace.World) != 0)
  745. callSG.builder.AppendLine("INSG.WorldSpacePositionPredisplacement = posRelativeWS;");
  746. if ((graphCode.requirements.requiresPositionPredisplacement & NeededCoordinateSpace.Object) != 0)
  747. callSG.builder.AppendLine("INSG.ObjectSpacePositionPredisplacement = TransformWorldToObject(posRelativeWS);");
  748. if ((graphCode.requirements.requiresPositionPredisplacement & NeededCoordinateSpace.View) != 0)
  749. callSG.builder.AppendLine("INSG.ViewSpacePositionPredisplacement = VFXTransformPositionWorldToView(posRelativeWS);");
  750. if ((graphCode.requirements.requiresPositionPredisplacement & NeededCoordinateSpace.Tangent) != 0)
  751. callSG.builder.AppendLine("INSG.TangentSpacePositionPredisplacement = float3(0.0f, 0.0f, 0.0f);");
  752. if ((graphCode.requirements.requiresPositionPredisplacement & NeededCoordinateSpace.AbsoluteWorld) != 0)
  753. callSG.builder.AppendLine("INSG.AbsoluteWorldSpacePositionPredisplacement = posAbsoluteWS;");
  754. }
  755. if (graphCode.requirements.requiresScreenPosition)
  756. callSG.builder.AppendLine("INSG.ScreenPosition = ComputeScreenPos(VFXTransformPositionWorldToClip(i.VFX_VARYING_POSWS), _ProjectionParams.x);");
  757. if (graphCode.requirements.requiresViewDir != NeededCoordinateSpace.None)
  758. {
  759. callSG.builder.AppendLine("float3 V = GetWorldSpaceNormalizeViewDir(VFXGetPositionRWS(i.VFX_VARYING_POSWS));");
  760. if ((graphCode.requirements.requiresViewDir & NeededCoordinateSpace.World) != 0)
  761. callSG.builder.AppendLine("INSG.WorldSpaceViewDirection = V;");
  762. if ((graphCode.requirements.requiresViewDir & NeededCoordinateSpace.Object) != 0)
  763. callSG.builder.AppendLine("INSG.ObjectSpaceViewDirection = TransformWorldToObjectDir(V);");
  764. if ((graphCode.requirements.requiresViewDir & NeededCoordinateSpace.View) != 0)
  765. callSG.builder.AppendLine("INSG.ViewSpaceViewDirection = TransformWorldToViewDir(V);");
  766. if ((graphCode.requirements.requiresViewDir & NeededCoordinateSpace.Tangent) != 0)
  767. callSG.builder.AppendLine("INSG.TangentSpaceViewDirection = mul(tbn, V);");
  768. }
  769. }
  770. if (graphCode.requirements.requiresMeshUVs.Contains(UVChannel.UV0))
  771. {
  772. callSG.builder.AppendLine("INSG.uv0.xy = i.uv;");
  773. }
  774. if (graphCode.requirements.requiresTime)
  775. {
  776. callSG.builder.AppendLine("INSG.TimeParameters = _TimeParameters.xyz;");
  777. }
  778. if (graphCode.requirements.requiresFaceSign)
  779. {
  780. callSG.builder.AppendLine("INSG.FaceSign = frontFace ? 1.0f : -1.0f;");
  781. }
  782. if (taskType == VFXTaskType.ParticleMeshOutput)
  783. {
  784. for (UVChannel uv = UVChannel.UV1; uv <= UVChannel.UV3; ++uv)
  785. {
  786. if (graphCode.requirements.requiresMeshUVs.Contains(uv))
  787. {
  788. int uvi = (int)uv;
  789. yield return new KeyValuePair<string, VFXShaderWriter>($"VFX_SHADERGRAPH_HAS_UV{uvi}", new VFXShaderWriter("1")); // TODO put that in additionalDefines
  790. callSG.builder.AppendLine($"INSG.uv{uvi} = i.uv{uvi};");
  791. }
  792. }
  793. if (graphCode.requirements.requiresVertexColor)
  794. {
  795. yield return new KeyValuePair<string, VFXShaderWriter>($"VFX_SHADERGRAPH_HAS_COLOR", new VFXShaderWriter("1")); // TODO put that in additionalDefines
  796. callSG.builder.AppendLine($"INSG.VertexColor = i.vertexColor;");
  797. }
  798. }
  799. callSG.builder.Append($"\n{shaderGraph.outputStructName} OUTSG = {shaderGraph.evaluationFunctionName}(INSG");
  800. if (graphCode.properties.Any())
  801. callSG.builder.Append("," + graphCode.properties.Select(t => t.GetHLSLVariableName(true, UnityEditor.ShaderGraph.GenerationMode.ForReals)).Aggregate((s, t) => s + ", " + t));
  802. callSG.builder.AppendLine(");");
  803. var pixelPorts = currentRP.passInfos[kvPass.Key].pixelPorts;
  804. if (pixelPorts.Any(t => t == ShaderGraphVfxAsset.AlphaThresholdSlotId) && shaderGraph.alphaClipping)
  805. {
  806. callSG.builder.AppendLine(
  807. @"#if (USE_ALPHA_TEST || VFX_FEATURE_MOTION_VECTORS_FORWARD) && defined(VFX_VARYING_ALPHATHRESHOLD)
  808. i.VFX_VARYING_ALPHATHRESHOLD = OUTSG.AlphaClipThreshold_7;
  809. #endif");
  810. }
  811. yield return new KeyValuePair<string, VFXShaderWriter>("${SHADERGRAPH_PIXEL_CALL_" + kvPass.Key.ToUpper(CultureInfo.InvariantCulture) + "}", callSG);
  812. }
  813. }
  814. }
  815. }
  816. }
  817. }