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.

1317 lines
43 KiB

  1. // Amplify Shader Editor - Visual Shader Editing Tool
  2. // Copyright (c) Amplify Creations, Lda <info@amplify.pt>
  3. using UnityEngine;
  4. using UnityEditor;
  5. using System;
  6. using System.Collections.Generic;
  7. #if !UNITY_2018_1_OR_NEWER
  8. namespace AmplifyShaderEditor
  9. {
  10. // Disabling Substance Deprecated warning
  11. #pragma warning disable 0618
  12. [Serializable]
  13. [NodeAttributes( "Substance Sample", "Textures", "Samples a procedural material", KeyCode.None, true, 0, int.MaxValue, typeof( SubstanceArchive ), typeof( ProceduralMaterial ) )]
  14. public sealed class SubstanceSamplerNode : PropertyNode
  15. {
  16. private const string GlobalVarDecStr = "uniform sampler2D {0};";
  17. private const string PropertyDecStr = "{0}(\"{0}\", 2D) = \"white\"";
  18. private const string AutoNormalStr = "Auto-Normal";
  19. private const string SubstanceStr = "Substance";
  20. private float TexturePreviewSizeX = 128;
  21. private float TexturePreviewSizeY = 128;
  22. private float PickerPreviewWidthAdjust = 18;
  23. private bool m_editing;
  24. private CacheNodeConnections m_cacheNodeConnections;
  25. [SerializeField]
  26. private int m_firstOutputConnected = 0;
  27. [SerializeField]
  28. private ProceduralMaterial m_proceduralMaterial;
  29. [SerializeField]
  30. private int m_textureCoordSet = 0;
  31. [SerializeField]
  32. private ProceduralOutputType[] m_textureTypes;
  33. [SerializeField]
  34. private bool m_autoNormal = true;
  35. private System.Type m_type;
  36. private Texture[] m_textures = new Texture[] { };
  37. private List<int> m_outputConns = new List<int>();
  38. private Rect m_previewArea;
  39. private Rect m_pickerArea;
  40. protected override void CommonInit( int uniqueId )
  41. {
  42. base.CommonInit( uniqueId );
  43. AddInputPort( WirePortDataType.FLOAT2, false, "UV" );
  44. AddOutputPort( WirePortDataType.COLOR, Constants.EmptyPortValue );
  45. m_insideSize.Set( TexturePreviewSizeX + PickerPreviewWidthAdjust, TexturePreviewSizeY + 10 );
  46. m_type = typeof( ProceduralMaterial );
  47. m_currentParameterType = PropertyType.Property;
  48. m_freeType = false;
  49. m_freeName = false;
  50. m_autoWrapProperties = true;
  51. m_customPrefix = "Substance Sample ";
  52. m_drawPrecisionUI = false;
  53. m_showPreview = true;
  54. m_drawPreviewExpander = false;
  55. m_selectedLocation = PreviewLocation.TopCenter;
  56. m_cacheNodeConnections = new CacheNodeConnections();
  57. m_previewShaderGUID = "6f322c1da33f1e744941aafcb0ad1a2d";
  58. m_showAutoRegisterUI = false;
  59. }
  60. public override void RenderNodePreview()
  61. {
  62. if( !m_initialized )
  63. return;
  64. SetPreviewInputs();
  65. PreviewMaterial.SetInt( "_CustomUVs", m_inputPorts[ 0 ].IsConnected ? 1 : 0 );
  66. if( m_proceduralMaterial == null )
  67. return;
  68. Texture[] texs = m_proceduralMaterial.GetGeneratedTextures();
  69. int count = m_outputPorts.Count;
  70. for( int i = 0; i < count; i++ )
  71. {
  72. RenderTexture temp = RenderTexture.active;
  73. RenderTexture.active = m_outputPorts[ i ].OutputPreviewTexture;
  74. PreviewMaterial.SetTexture( "_GenTex", texs[ i ] );
  75. if( m_autoNormal && m_textureTypes[ i ] == ProceduralOutputType.Normal )
  76. Graphics.Blit( null, m_outputPorts[ i ].OutputPreviewTexture, PreviewMaterial, 1 );
  77. else
  78. Graphics.Blit( null, m_outputPorts[ i ].OutputPreviewTexture, PreviewMaterial, 0 );
  79. RenderTexture.active = temp;
  80. }
  81. }
  82. public override void OnOutputPortConnected( int portId, int otherNodeId, int otherPortId )
  83. {
  84. base.OnOutputPortConnected( portId, otherNodeId, otherPortId );
  85. m_firstOutputConnected = -1;
  86. }
  87. public override void OnOutputPortDisconnected( int portId )
  88. {
  89. base.OnOutputPortDisconnected( portId );
  90. m_firstOutputConnected = -1;
  91. }
  92. void CalculateFirstOutputConnected()
  93. {
  94. m_outputConns.Clear();
  95. int count = m_outputPorts.Count;
  96. bool connectionsAvailable = false;
  97. for( int i = 0; i < count; i++ )
  98. {
  99. if( m_outputPorts[ i ].IsConnected )
  100. {
  101. connectionsAvailable = true;
  102. }
  103. }
  104. for( int i = 0; i < count; i++ )
  105. {
  106. if( connectionsAvailable )
  107. {
  108. if( m_outputPorts[ i ].IsConnected )
  109. {
  110. if( m_firstOutputConnected < 0 )
  111. m_firstOutputConnected = i;
  112. m_outputConns.Add( i );
  113. }
  114. }
  115. else
  116. {
  117. m_outputConns.Add( i );
  118. }
  119. }
  120. if( m_firstOutputConnected < 0 )
  121. m_firstOutputConnected = 0;
  122. }
  123. public override void OnNodeLayout( DrawInfo drawInfo )
  124. {
  125. base.OnNodeLayout( drawInfo );
  126. m_previewArea = m_remainingBox;
  127. m_previewArea.width = TexturePreviewSizeX * drawInfo.InvertedZoom;
  128. m_previewArea.height = TexturePreviewSizeY * drawInfo.InvertedZoom;
  129. m_previewArea.x += 0.5f * m_remainingBox.width - 0.5f * m_previewArea.width;
  130. m_pickerArea = m_previewArea;
  131. m_pickerArea.width = 40 * drawInfo.InvertedZoom;
  132. m_pickerArea.x = m_previewArea.xMax - m_pickerArea.width - 2;
  133. m_pickerArea.height = 14 * drawInfo.InvertedZoom;
  134. m_pickerArea.y = m_previewArea.yMax - m_pickerArea.height - 2;
  135. }
  136. public override void DrawGUIControls( DrawInfo drawInfo )
  137. {
  138. base.DrawGUIControls( drawInfo );
  139. if( !( drawInfo.CurrentEventType == EventType.MouseDown || drawInfo.CurrentEventType == EventType.MouseUp || drawInfo.CurrentEventType == EventType.ExecuteCommand || drawInfo.CurrentEventType == EventType.DragPerform ) )
  140. return;
  141. bool insideBox = m_previewArea.Contains( drawInfo.MousePosition );
  142. if( insideBox )
  143. {
  144. m_editing = true;
  145. }
  146. else if( m_editing && !insideBox && drawInfo.CurrentEventType != EventType.ExecuteCommand )
  147. {
  148. GUI.FocusControl( null );
  149. m_editing = false;
  150. }
  151. }
  152. public override void Draw( DrawInfo drawInfo )
  153. {
  154. base.Draw( drawInfo );
  155. if( m_editing )
  156. {
  157. m_textures = m_proceduralMaterial != null ? m_proceduralMaterial.GetGeneratedTextures() : null;
  158. if( GUI.Button( m_pickerArea, string.Empty, GUIStyle.none ) )
  159. {
  160. int controlID = EditorGUIUtility.GetControlID( FocusType.Passive );
  161. EditorGUIUtility.ShowObjectPicker<ProceduralMaterial>( m_proceduralMaterial, false, "", controlID );
  162. }
  163. string commandName = Event.current.commandName;
  164. UnityEngine.Object newValue = null;
  165. if( commandName == "ObjectSelectorUpdated" )
  166. {
  167. newValue = EditorGUIUtility.GetObjectPickerObject();
  168. if( newValue != (UnityEngine.Object)m_proceduralMaterial )
  169. {
  170. UndoRecordObject( "Changing value EditorGUIObjectField on node Substance Sample" );
  171. m_proceduralMaterial = newValue != null ? (ProceduralMaterial)newValue : null;
  172. m_textures = m_proceduralMaterial != null ? m_proceduralMaterial.GetGeneratedTextures() : null;
  173. OnNewSubstanceSelected( m_textures );
  174. }
  175. }
  176. else if( commandName == "ObjectSelectorClosed" )
  177. {
  178. newValue = EditorGUIUtility.GetObjectPickerObject();
  179. if( newValue != (UnityEngine.Object)m_proceduralMaterial )
  180. {
  181. UndoRecordObject( "Changing value EditorGUIObjectField on node Substance Sample" );
  182. m_proceduralMaterial = newValue != null ? (ProceduralMaterial)newValue : null;
  183. m_textures = m_proceduralMaterial != null ? m_proceduralMaterial.GetGeneratedTextures() : null;
  184. OnNewSubstanceSelected( m_textures );
  185. }
  186. m_editing = false;
  187. }
  188. if( GUI.Button( m_previewArea, string.Empty, GUIStyle.none ) )
  189. {
  190. if( m_proceduralMaterial != null )
  191. {
  192. Selection.activeObject = m_proceduralMaterial;
  193. EditorGUIUtility.PingObject( Selection.activeObject );
  194. }
  195. m_editing = false;
  196. }
  197. }
  198. if( drawInfo.CurrentEventType == EventType.Repaint )
  199. {
  200. if( !m_editing )
  201. m_textures = m_proceduralMaterial != null ? m_proceduralMaterial.GetGeneratedTextures() : null;
  202. if( m_textures != null )
  203. {
  204. if( m_firstOutputConnected < 0 )
  205. {
  206. CalculateFirstOutputConnected();
  207. }
  208. else if( m_textures.Length != m_textureTypes.Length )
  209. {
  210. OnNewSubstanceSelected( m_textures );
  211. }
  212. int texCount = m_outputConns.Count;
  213. Rect individuals = m_previewArea;
  214. individuals.height /= texCount;
  215. for( int i = 0; i < texCount; i++ )
  216. {
  217. EditorGUI.DrawPreviewTexture( individuals, m_textures[ m_outputConns[ i ] ], null, ScaleMode.ScaleAndCrop );
  218. individuals.y += individuals.height;
  219. }
  220. }
  221. else
  222. {
  223. GUI.Label( m_previewArea, string.Empty, UIUtils.ObjectFieldThumb );
  224. }
  225. if( ContainerGraph.LodLevel <= ParentGraph.NodeLOD.LOD2 )
  226. {
  227. Rect smallButton = m_previewArea;
  228. smallButton.height = 14 * drawInfo.InvertedZoom;
  229. smallButton.y = m_previewArea.yMax - smallButton.height - 2;
  230. smallButton.width = 40 * drawInfo.InvertedZoom;
  231. smallButton.x = m_previewArea.xMax - smallButton.width - 2;
  232. if( m_textures == null )
  233. {
  234. GUI.Label( m_previewArea, "None (Procedural Material)", UIUtils.ObjectFieldThumbOverlay );
  235. }
  236. GUI.Label( m_pickerArea, "Select", UIUtils.GetCustomStyle( CustomStyle.SamplerButton ) );
  237. }
  238. GUI.Label( m_previewArea, string.Empty, UIUtils.GetCustomStyle( CustomStyle.SamplerFrame ) );
  239. }
  240. }
  241. void OnNewSubstanceSelected( Texture[] textures )
  242. {
  243. CacheCurrentSettings();
  244. ConfigPortsFromMaterial( true, textures );
  245. ConnectFromCache();
  246. m_requireMaterialUpdate = true;
  247. CalculateFirstOutputConnected();
  248. ContainerGraph.ParentWindow.RequestRepaint();
  249. }
  250. public override void DrawProperties()
  251. {
  252. base.DrawProperties();
  253. EditorGUI.BeginChangeCheck();
  254. m_proceduralMaterial = EditorGUILayoutObjectField( SubstanceStr, m_proceduralMaterial, m_type, false ) as ProceduralMaterial;
  255. if( EditorGUI.EndChangeCheck() )
  256. {
  257. Texture[] textures = m_proceduralMaterial != null ? m_proceduralMaterial.GetGeneratedTextures() : null;
  258. if( textures != null )
  259. {
  260. OnNewSubstanceSelected( textures );
  261. }
  262. }
  263. m_textureCoordSet = EditorGUILayoutIntPopup( Constants.AvailableUVSetsLabel, m_textureCoordSet, Constants.AvailableUVSetsStr, Constants.AvailableUVSets );
  264. EditorGUI.BeginChangeCheck();
  265. m_autoNormal = EditorGUILayoutToggle( AutoNormalStr, m_autoNormal );
  266. if( EditorGUI.EndChangeCheck() )
  267. {
  268. for( int i = 0; i < m_textureTypes.Length; i++ )
  269. {
  270. WirePortDataType portType = ( m_autoNormal && m_textureTypes[ i ] == ProceduralOutputType.Normal ) ? WirePortDataType.FLOAT3 : WirePortDataType.COLOR;
  271. if( m_outputPorts[ i ].DataType != portType )
  272. {
  273. m_outputPorts[ i ].ChangeType( portType, false );
  274. }
  275. }
  276. }
  277. }
  278. private void CacheCurrentSettings()
  279. {
  280. m_cacheNodeConnections.Clear();
  281. for( int portId = 0; portId < m_outputPorts.Count; portId++ )
  282. {
  283. if( m_outputPorts[ portId ].IsConnected )
  284. {
  285. int connCount = m_outputPorts[ portId ].ConnectionCount;
  286. for( int connIdx = 0; connIdx < connCount; connIdx++ )
  287. {
  288. WireReference connection = m_outputPorts[ portId ].GetConnection( connIdx );
  289. m_cacheNodeConnections.Add( m_outputPorts[ portId ].Name, new NodeCache( connection.NodeId, connection.PortId ) );
  290. }
  291. }
  292. }
  293. }
  294. private void ConnectFromCache()
  295. {
  296. for( int i = 0; i < m_outputPorts.Count; i++ )
  297. {
  298. List<NodeCache> connections = m_cacheNodeConnections.GetList( m_outputPorts[ i ].Name );
  299. if( connections != null )
  300. {
  301. int count = connections.Count;
  302. for( int connIdx = 0; connIdx < count; connIdx++ )
  303. {
  304. UIUtils.SetConnection( connections[ connIdx ].TargetNodeId, connections[ connIdx ].TargetPortId, UniqueId, i );
  305. }
  306. }
  307. }
  308. }
  309. private void ConfigPortsFromMaterial( bool invalidateConnections = false, Texture[] newTextures = null )
  310. {
  311. SetAdditonalTitleText( ( m_proceduralMaterial != null ) ? string.Format( Constants.PropertyValueLabel, m_proceduralMaterial.name ) : "Value( <None> )" );
  312. Texture[] textures = newTextures != null ? newTextures : ( ( m_proceduralMaterial != null ) ? m_proceduralMaterial.GetGeneratedTextures() : null );
  313. if( textures != null )
  314. {
  315. m_firstOutputConnected = -1;
  316. string nameToRemove = m_proceduralMaterial.name + "_";
  317. m_textureTypes = new ProceduralOutputType[ textures.Length ];
  318. for( int i = 0; i < textures.Length; i++ )
  319. {
  320. ProceduralTexture procTex = textures[ i ] as ProceduralTexture;
  321. m_textureTypes[ i ] = procTex.GetProceduralOutputType();
  322. WirePortDataType portType = ( m_autoNormal && m_textureTypes[ i ] == ProceduralOutputType.Normal ) ? WirePortDataType.FLOAT3 : WirePortDataType.COLOR;
  323. string newName = textures[ i ].name.Replace( nameToRemove, string.Empty );
  324. char firstLetter = Char.ToUpper( newName[ 0 ] );
  325. newName = firstLetter.ToString() + newName.Substring( 1 );
  326. if( i < m_outputPorts.Count )
  327. {
  328. m_outputPorts[ i ].ChangeProperties( newName, portType, false );
  329. if( invalidateConnections )
  330. {
  331. m_outputPorts[ i ].FullDeleteConnections();
  332. }
  333. }
  334. else
  335. {
  336. AddOutputPort( portType, newName );
  337. }
  338. }
  339. if( textures.Length < m_outputPorts.Count )
  340. {
  341. int itemsToRemove = m_outputPorts.Count - textures.Length;
  342. for( int i = 0; i < itemsToRemove; i++ )
  343. {
  344. int idx = m_outputPorts.Count - 1;
  345. if( m_outputPorts[ idx ].IsConnected )
  346. {
  347. m_outputPorts[ idx ].ForceClearConnection();
  348. }
  349. RemoveOutputPort( idx );
  350. }
  351. }
  352. }
  353. else
  354. {
  355. int itemsToRemove = m_outputPorts.Count - 1;
  356. m_outputPorts[ 0 ].ChangeProperties( Constants.EmptyPortValue, WirePortDataType.COLOR, false );
  357. m_outputPorts[ 0 ].ForceClearConnection();
  358. for( int i = 0; i < itemsToRemove; i++ )
  359. {
  360. int idx = m_outputPorts.Count - 1;
  361. if( m_outputPorts[ idx ].IsConnected )
  362. {
  363. m_outputPorts[ idx ].ForceClearConnection();
  364. }
  365. RemoveOutputPort( idx );
  366. }
  367. }
  368. m_sizeIsDirty = true;
  369. m_isDirty = true;
  370. }
  371. private void ConfigFromObject( UnityEngine.Object obj )
  372. {
  373. ProceduralMaterial newMat = AssetDatabase.LoadAssetAtPath<ProceduralMaterial>( AssetDatabase.GetAssetPath( obj ) );
  374. if( newMat != null )
  375. {
  376. m_proceduralMaterial = newMat;
  377. ConfigPortsFromMaterial();
  378. }
  379. }
  380. public override void OnObjectDropped( UnityEngine.Object obj )
  381. {
  382. ConfigFromObject( obj );
  383. }
  384. public override void SetupFromCastObject( UnityEngine.Object obj )
  385. {
  386. ConfigFromObject( obj );
  387. }
  388. public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar )
  389. {
  390. if( m_proceduralMaterial == null )
  391. {
  392. return "(0).xxxx";
  393. }
  394. if( m_outputPorts[ outputId ].IsLocalValue( dataCollector.PortCategory ) )
  395. {
  396. return m_outputPorts[ outputId ].LocalValue( dataCollector.PortCategory );
  397. }
  398. Texture[] textures = m_proceduralMaterial.GetGeneratedTextures();
  399. string uvPropertyName = string.Empty;
  400. for( int i = 0; i < m_outputPorts.Count; i++ )
  401. {
  402. if( m_outputPorts[ i ].HasConnectedNode )
  403. {
  404. uvPropertyName = textures[ i ].name;
  405. break;
  406. }
  407. }
  408. string name = textures[ outputId ].name + OutputId;
  409. dataCollector.AddToUniforms( UniqueId, string.Format( GlobalVarDecStr, textures[ outputId ].name ) );
  410. dataCollector.AddToProperties( UniqueId, string.Format( PropertyDecStr, textures[ outputId ].name ) + "{}", -1 );
  411. bool isVertex = ( dataCollector.PortCategory == MasterNodePortCategory.Vertex || dataCollector.PortCategory == MasterNodePortCategory.Tessellation );
  412. string value = string.Format( "tex2D{0}({1}, {2})", ( isVertex ? "lod" : string.Empty ), textures[ outputId ].name, GetUVCoords( ref dataCollector, ignoreLocalvar, uvPropertyName ) );
  413. if( m_autoNormal && m_textureTypes[ outputId ] == ProceduralOutputType.Normal )
  414. {
  415. value = string.Format( TemplateHelperFunctions.CreateUnpackNormalStr( dataCollector,false,"1.0"), value );
  416. }
  417. dataCollector.AddPropertyNode( this );
  418. RegisterLocalVariable( outputId, value, ref dataCollector, name );
  419. return m_outputPorts[ outputId ].LocalValue( dataCollector.PortCategory );
  420. }
  421. public string GetUVCoords( ref MasterNodeDataCollector dataCollector, bool ignoreLocalVar, string propertyName )
  422. {
  423. bool isVertex = ( dataCollector.PortCategory == MasterNodePortCategory.Vertex || dataCollector.PortCategory == MasterNodePortCategory.Tessellation );
  424. if( m_inputPorts[ 0 ].IsConnected )
  425. {
  426. return m_inputPorts[ 0 ].GenerateShaderForOutput( ref dataCollector, isVertex ? WirePortDataType.FLOAT4 : WirePortDataType.FLOAT2, ignoreLocalVar, true );
  427. }
  428. else
  429. {
  430. string uvChannelName = IOUtils.GetUVChannelName( propertyName, m_textureCoordSet );
  431. if( dataCollector.IsTemplate )
  432. {
  433. string propertyHelperVar = propertyName + "_ST";
  434. dataCollector.AddToUniforms( UniqueId, "float4", propertyHelperVar );
  435. string uvName = string.Empty;
  436. if( dataCollector.TemplateDataCollectorInstance.HasUV( m_textureCoordSet ) )
  437. {
  438. uvName = dataCollector.TemplateDataCollectorInstance.GetUVName( m_textureCoordSet );
  439. }
  440. else
  441. {
  442. uvName = dataCollector.TemplateDataCollectorInstance.RegisterUV( m_textureCoordSet );
  443. }
  444. uvChannelName = "uv" + propertyName;
  445. if( isVertex )
  446. {
  447. string value = string.Format( Constants.TilingOffsetFormat, uvName, propertyHelperVar + ".xy", propertyHelperVar + ".zw" );
  448. string lodLevel = "0";
  449. value = "float4( " + value + ", 0 , " + lodLevel + " )";
  450. dataCollector.AddLocalVariable( UniqueId, m_currentPrecisionType, WirePortDataType.FLOAT4, uvChannelName, value );
  451. }
  452. else
  453. {
  454. dataCollector.AddLocalVariable( UniqueId, m_currentPrecisionType, WirePortDataType.FLOAT2, uvChannelName, string.Format( Constants.TilingOffsetFormat, uvName, propertyHelperVar + ".xy", propertyHelperVar + ".zw" ) );
  455. }
  456. }
  457. else
  458. {
  459. string vertexCoords = Constants.VertexShaderInputStr + ".texcoord";
  460. if( m_textureCoordSet > 0 )
  461. {
  462. vertexCoords += m_textureCoordSet.ToString();
  463. }
  464. string dummyPropUV = "_texcoord" + ( m_textureCoordSet > 0 ? ( m_textureCoordSet + 1 ).ToString() : "" );
  465. string dummyUV = "uv" + ( m_textureCoordSet > 0 ? ( m_textureCoordSet + 1 ).ToString() : "" ) + dummyPropUV;
  466. dataCollector.AddToUniforms( UniqueId, "uniform float4 " + propertyName + "_ST;" );
  467. dataCollector.AddToProperties( UniqueId, "[HideInInspector] " + dummyPropUV + "( \"\", 2D ) = \"white\" {}", 100 );
  468. dataCollector.AddToInput( UniqueId, dummyUV, WirePortDataType.FLOAT2 );
  469. if( isVertex )
  470. {
  471. dataCollector.AddToVertexLocalVariables( UniqueId, "float4 " + uvChannelName + " = float4(" + vertexCoords + " * " + propertyName + "_ST.xy + " + propertyName + "_ST.zw, 0 ,0);" );
  472. return uvChannelName;
  473. }
  474. else
  475. dataCollector.AddToLocalVariables( UniqueId, PrecisionType.Float, WirePortDataType.FLOAT2, uvChannelName, Constants.InputVarStr + "." + dummyUV + " * " + propertyName + "_ST.xy + " + propertyName + "_ST.zw" );
  476. }
  477. return uvChannelName;
  478. }
  479. }
  480. public override void UpdateMaterial( Material mat )
  481. {
  482. base.UpdateMaterial( mat );
  483. if( m_proceduralMaterial != null )
  484. {
  485. Texture[] textures = m_proceduralMaterial.GetGeneratedTextures();
  486. for( int i = 0; i < textures.Length; i++ )
  487. {
  488. if( mat.HasProperty( textures[ i ].name ) && !InsideShaderFunction )
  489. {
  490. mat.SetTexture( textures[ i ].name, textures[ i ] );
  491. }
  492. }
  493. }
  494. }
  495. public override bool UpdateShaderDefaults( ref Shader shader, ref TextureDefaultsDataColector defaultCol )
  496. {
  497. if( m_proceduralMaterial != null )
  498. {
  499. Texture[] textures = m_proceduralMaterial.GetGeneratedTextures();
  500. for( int i = 0; i < textures.Length; i++ )
  501. {
  502. defaultCol.AddValue( textures[ i ].name, textures[ i ] );
  503. }
  504. }
  505. return true;
  506. }
  507. public override void Destroy()
  508. {
  509. base.Destroy();
  510. m_textures = null;
  511. m_proceduralMaterial = null;
  512. m_cacheNodeConnections.Clear();
  513. m_cacheNodeConnections = null;
  514. m_outputConns.Clear();
  515. m_outputConns = null;
  516. }
  517. public override string GetPropertyValStr()
  518. {
  519. return m_proceduralMaterial ? m_proceduralMaterial.name : string.Empty;
  520. }
  521. public override void ReadFromString( ref string[] nodeParams )
  522. {
  523. base.ReadFromString( ref nodeParams );
  524. string guid = GetCurrentParam( ref nodeParams );
  525. m_textureCoordSet = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  526. m_autoNormal = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  527. if( guid.Length > 1 )
  528. {
  529. m_proceduralMaterial = AssetDatabase.LoadAssetAtPath<ProceduralMaterial>( AssetDatabase.GUIDToAssetPath( guid ) );
  530. if( m_proceduralMaterial != null )
  531. {
  532. ConfigPortsFromMaterial();
  533. }
  534. else
  535. {
  536. UIUtils.ShowMessage( "Substance not found ", MessageSeverity.Error );
  537. }
  538. }
  539. }
  540. public override void WriteToString( ref string nodeInfo, ref string connectionsInfo )
  541. {
  542. base.WriteToString( ref nodeInfo, ref connectionsInfo );
  543. string guid = ( m_proceduralMaterial != null ) ? AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath( m_proceduralMaterial ) ) : "0";
  544. IOUtils.AddFieldValueToString( ref nodeInfo, guid );
  545. IOUtils.AddFieldValueToString( ref nodeInfo, m_textureCoordSet );
  546. IOUtils.AddFieldValueToString( ref nodeInfo, m_autoNormal );
  547. }
  548. }
  549. #pragma warning restore 0618
  550. }
  551. #elif SUBSTANCE_PLUGIN_ENABLED
  552. using Substance.Game;
  553. namespace AmplifyShaderEditor
  554. {
  555. public enum ASEProceduralOutputType
  556. {
  557. Color,
  558. Normal,
  559. }
  560. // Disabling Substance Deprecated warning
  561. #pragma warning disable 0618
  562. [Serializable]
  563. [NodeAttributes( "Substance Sample", "Textures", "Samples a procedural material", KeyCode.None, true, 0, int.MaxValue, typeof( SubstanceGraph ), typeof( Substance.Game.Substance ) )]
  564. public sealed class SubstanceSamplerNode : PropertyNode
  565. {
  566. private const string NormalMapCheck = "_normal";
  567. private const string GlobalVarDecStr = "uniform sampler2D {0};";
  568. private const string PropertyDecStr = "{0}(\"{1}\", 2D) = \"white\"";
  569. private const string AutoNormalStr = "Auto-Normal";
  570. private const string SubstanceStr = "Substance";
  571. private float TexturePreviewSizeX = 128;
  572. private float TexturePreviewSizeY = 128;
  573. private float PickerPreviewWidthAdjust = 18;
  574. private bool m_editing;
  575. private CacheNodeConnections m_cacheNodeConnections;
  576. [SerializeField]
  577. private int m_firstOutputConnected = 0;
  578. [SerializeField]
  579. private Substance.Game.SubstanceGraph m_substanceGraph;
  580. [SerializeField]
  581. private string m_substanceGUID = string.Empty;
  582. [SerializeField]
  583. private int m_textureCoordSet = 0;
  584. [SerializeField]
  585. private ASEProceduralOutputType[] m_textureTypes;
  586. [SerializeField]
  587. private bool m_autoNormal = true;
  588. private System.Type m_type;
  589. private List<Texture2D> m_textures = new List<Texture2D>();
  590. private List<int> m_outputConns = new List<int>();
  591. private Rect m_previewArea;
  592. private Rect m_pickerArea;
  593. protected override void CommonInit( int uniqueId )
  594. {
  595. base.CommonInit( uniqueId );
  596. AddInputPort( WirePortDataType.FLOAT2, false, "UV" );
  597. AddOutputPort( WirePortDataType.COLOR, Constants.EmptyPortValue );
  598. m_insideSize.Set( TexturePreviewSizeX + PickerPreviewWidthAdjust, TexturePreviewSizeY + 10 );
  599. m_type = typeof( Substance.Game.Substance );
  600. m_currentParameterType = PropertyType.Property;
  601. m_freeType = false;
  602. m_freeName = false;
  603. m_autoWrapProperties = true;
  604. m_customPrefix = "Substance Sample ";
  605. m_drawPrecisionUI = false;
  606. m_showPreview = true;
  607. m_drawPreviewExpander = false;
  608. m_selectedLocation = PreviewLocation.TopCenter;
  609. m_cacheNodeConnections = new CacheNodeConnections();
  610. m_previewShaderGUID = "6f322c1da33f1e744941aafcb0ad1a2d";
  611. m_showAutoRegisterUI = false;
  612. }
  613. public override void RenderNodePreview()
  614. {
  615. if( !m_initialized )
  616. return;
  617. SetPreviewInputs();
  618. PreviewMaterial.SetInt( "_CustomUVs", m_inputPorts[ 0 ].IsConnected ? 1 : 0 );
  619. if( m_substanceGraph == null )
  620. return;
  621. List<Texture2D> texs = m_substanceGraph.generatedTextures;
  622. int count = m_outputPorts.Count;
  623. for( int i = 0; i < count; i++ )
  624. {
  625. RenderTexture temp = RenderTexture.active;
  626. RenderTexture.active = m_outputPorts[ i ].OutputPreviewTexture;
  627. PreviewMaterial.SetTexture( "_GenTex", texs[ i ] );
  628. if( m_autoNormal && m_textureTypes[ i ] == ASEProceduralOutputType.Normal )
  629. Graphics.Blit( null, m_outputPorts[ i ].OutputPreviewTexture, PreviewMaterial, 1 );
  630. else
  631. Graphics.Blit( null, m_outputPorts[ i ].OutputPreviewTexture, PreviewMaterial, 0 );
  632. RenderTexture.active = temp;
  633. }
  634. }
  635. public override void OnOutputPortConnected( int portId, int otherNodeId, int otherPortId )
  636. {
  637. base.OnOutputPortConnected( portId, otherNodeId, otherPortId );
  638. m_firstOutputConnected = -1;
  639. }
  640. public override void OnOutputPortDisconnected( int portId )
  641. {
  642. base.OnOutputPortDisconnected( portId );
  643. m_firstOutputConnected = -1;
  644. }
  645. void CalculateFirstOutputConnected()
  646. {
  647. m_outputConns.Clear();
  648. int count = m_outputPorts.Count;
  649. bool connectionsAvailable = false;
  650. for( int i = 0; i < count; i++ )
  651. {
  652. if( m_outputPorts[ i ].IsConnected )
  653. {
  654. connectionsAvailable = true;
  655. }
  656. }
  657. for( int i = 0; i < count; i++ )
  658. {
  659. if( connectionsAvailable )
  660. {
  661. if( m_outputPorts[ i ].IsConnected )
  662. {
  663. if( m_firstOutputConnected < 0 )
  664. m_firstOutputConnected = i;
  665. m_outputConns.Add( i );
  666. }
  667. }
  668. else
  669. {
  670. m_outputConns.Add( i );
  671. }
  672. }
  673. if( m_firstOutputConnected < 0 )
  674. m_firstOutputConnected = 0;
  675. }
  676. public override void OnNodeLayout( DrawInfo drawInfo )
  677. {
  678. base.OnNodeLayout( drawInfo );
  679. m_previewArea = m_remainingBox;
  680. m_previewArea.width = TexturePreviewSizeX * drawInfo.InvertedZoom;
  681. m_previewArea.height = TexturePreviewSizeY * drawInfo.InvertedZoom;
  682. m_previewArea.x += 0.5f * m_remainingBox.width - 0.5f * m_previewArea.width;
  683. m_pickerArea = m_previewArea;
  684. m_pickerArea.width = 40 * drawInfo.InvertedZoom;
  685. m_pickerArea.x = m_previewArea.xMax - m_pickerArea.width - 2;
  686. m_pickerArea.height = 14 * drawInfo.InvertedZoom;
  687. m_pickerArea.y = m_previewArea.yMax - m_pickerArea.height - 2;
  688. }
  689. public override void DrawGUIControls( DrawInfo drawInfo )
  690. {
  691. base.DrawGUIControls( drawInfo );
  692. if( !( drawInfo.CurrentEventType == EventType.MouseDown || drawInfo.CurrentEventType == EventType.MouseUp || drawInfo.CurrentEventType == EventType.ExecuteCommand || drawInfo.CurrentEventType == EventType.DragPerform ) )
  693. return;
  694. bool insideBox = m_previewArea.Contains( drawInfo.MousePosition );
  695. if( insideBox )
  696. {
  697. m_editing = true;
  698. }
  699. else if( m_editing && !insideBox && drawInfo.CurrentEventType != EventType.ExecuteCommand )
  700. {
  701. GUI.FocusControl( null );
  702. m_editing = false;
  703. }
  704. }
  705. public override void Draw( DrawInfo drawInfo )
  706. {
  707. base.Draw( drawInfo );
  708. if( m_editing )
  709. {
  710. m_textures = m_substanceGraph != null ? m_substanceGraph.generatedTextures : null;
  711. if( GUI.Button( m_pickerArea, string.Empty, GUIStyle.none ) )
  712. {
  713. int controlID = EditorGUIUtility.GetControlID( FocusType.Passive );
  714. EditorGUIUtility.ShowObjectPicker<SubstanceGraph>( m_substanceGraph, false, "", controlID );
  715. }
  716. string commandName = Event.current.commandName;
  717. UnityEngine.Object newValue = null;
  718. if( commandName == "ObjectSelectorUpdated" )
  719. {
  720. newValue = EditorGUIUtility.GetObjectPickerObject();
  721. if( newValue != (UnityEngine.Object)m_substanceGraph )
  722. {
  723. UndoRecordObject( "Changing value EditorGUIObjectField on node Substance Sample" );
  724. SubstanceGraph = newValue != null ? (SubstanceGraph)newValue : null;
  725. m_textures = m_substanceGraph != null ? m_substanceGraph.generatedTextures : null;
  726. OnNewSubstanceSelected( m_textures );
  727. }
  728. }
  729. else if( commandName == "ObjectSelectorClosed" )
  730. {
  731. newValue = EditorGUIUtility.GetObjectPickerObject();
  732. if( newValue != (UnityEngine.Object)m_substanceGraph )
  733. {
  734. UndoRecordObject( "Changing value EditorGUIObjectField on node Substance Sample" );
  735. SubstanceGraph = newValue != null ? (SubstanceGraph)newValue : null;
  736. m_textures = m_substanceGraph != null ? m_substanceGraph.generatedTextures : null;
  737. OnNewSubstanceSelected( m_textures );
  738. }
  739. m_editing = false;
  740. }
  741. if( GUI.Button( m_previewArea, string.Empty, GUIStyle.none ) )
  742. {
  743. if( m_substanceGraph != null )
  744. {
  745. Selection.activeObject = m_substanceGraph;
  746. EditorGUIUtility.PingObject( Selection.activeObject );
  747. }
  748. m_editing = false;
  749. }
  750. }
  751. if( drawInfo.CurrentEventType == EventType.Repaint )
  752. {
  753. if( !m_editing )
  754. m_textures = m_substanceGraph != null ? m_substanceGraph.generatedTextures : null;
  755. if( m_textures != null )
  756. {
  757. if( m_firstOutputConnected < 0 )
  758. {
  759. CalculateFirstOutputConnected();
  760. }
  761. else if( m_textures.Count != m_textureTypes.Length )
  762. {
  763. OnNewSubstanceSelected( m_textures );
  764. }
  765. int texCount = m_outputConns.Count;
  766. Rect individuals = m_previewArea;
  767. individuals.height /= texCount;
  768. for( int i = 0; i < texCount; i++ )
  769. {
  770. EditorGUI.DrawPreviewTexture( individuals, m_textures[ m_outputConns[ i ] ], null, ScaleMode.ScaleAndCrop );
  771. individuals.y += individuals.height;
  772. }
  773. }
  774. else
  775. {
  776. GUI.Label( m_previewArea, string.Empty, UIUtils.ObjectFieldThumb );
  777. }
  778. if( ContainerGraph.LodLevel <= ParentGraph.NodeLOD.LOD2 )
  779. {
  780. Rect smallButton = m_previewArea;
  781. smallButton.height = 14 * drawInfo.InvertedZoom;
  782. smallButton.y = m_previewArea.yMax - smallButton.height - 2;
  783. smallButton.width = 40 * drawInfo.InvertedZoom;
  784. smallButton.x = m_previewArea.xMax - smallButton.width - 2;
  785. if( m_textures == null )
  786. {
  787. GUI.Label( m_previewArea, "None (Procedural Material)", UIUtils.ObjectFieldThumbOverlay );
  788. }
  789. GUI.Label( m_pickerArea, "Select", UIUtils.GetCustomStyle( CustomStyle.SamplerButton ) );
  790. }
  791. GUI.Label( m_previewArea, string.Empty, UIUtils.GetCustomStyle( CustomStyle.SamplerFrame ) );
  792. }
  793. }
  794. void OnNewSubstanceSelected( List<Texture2D> textures )
  795. {
  796. CacheCurrentSettings();
  797. ConfigPortsFromMaterial( true, textures );
  798. ConnectFromCache();
  799. m_requireMaterialUpdate = true;
  800. CalculateFirstOutputConnected();
  801. ContainerGraph.ParentWindow.RequestRepaint();
  802. }
  803. public override void DrawProperties()
  804. {
  805. base.DrawProperties();
  806. EditorGUI.BeginChangeCheck();
  807. SubstanceGraph = EditorGUILayoutObjectField( SubstanceStr, m_substanceGraph, m_type, false ) as SubstanceGraph;
  808. if( EditorGUI.EndChangeCheck() )
  809. {
  810. List<Texture2D> textures = m_substanceGraph != null ? m_substanceGraph.generatedTextures : null;
  811. if( textures != null )
  812. {
  813. OnNewSubstanceSelected( textures );
  814. }
  815. }
  816. m_textureCoordSet = EditorGUILayoutIntPopup( Constants.AvailableUVSetsLabel, m_textureCoordSet, Constants.AvailableUVSetsStr, Constants.AvailableUVSets );
  817. EditorGUI.BeginChangeCheck();
  818. m_autoNormal = EditorGUILayoutToggle( AutoNormalStr, m_autoNormal );
  819. if( EditorGUI.EndChangeCheck() )
  820. {
  821. for( int i = 0; i < m_textureTypes.Length; i++ )
  822. {
  823. WirePortDataType portType = ( m_autoNormal && m_textureTypes[ i ] == ASEProceduralOutputType.Normal ) ? WirePortDataType.FLOAT3 : WirePortDataType.COLOR;
  824. if( m_outputPorts[ i ].DataType != portType )
  825. {
  826. m_outputPorts[ i ].ChangeType( portType, false );
  827. }
  828. }
  829. }
  830. }
  831. private void CacheCurrentSettings()
  832. {
  833. m_cacheNodeConnections.Clear();
  834. for( int portId = 0; portId < m_outputPorts.Count; portId++ )
  835. {
  836. if( m_outputPorts[ portId ].IsConnected )
  837. {
  838. int connCount = m_outputPorts[ portId ].ConnectionCount;
  839. for( int connIdx = 0; connIdx < connCount; connIdx++ )
  840. {
  841. WireReference connection = m_outputPorts[ portId ].GetConnection( connIdx );
  842. m_cacheNodeConnections.Add( m_outputPorts[ portId ].Name, new NodeCache( connection.NodeId, connection.PortId ) );
  843. }
  844. }
  845. }
  846. }
  847. private void ConnectFromCache()
  848. {
  849. for( int i = 0; i < m_outputPorts.Count; i++ )
  850. {
  851. List<NodeCache> connections = m_cacheNodeConnections.GetList( m_outputPorts[ i ].Name );
  852. if( connections != null )
  853. {
  854. int count = connections.Count;
  855. for( int connIdx = 0; connIdx < count; connIdx++ )
  856. {
  857. UIUtils.SetConnection( connections[ connIdx ].TargetNodeId, connections[ connIdx ].TargetPortId, UniqueId, i );
  858. }
  859. }
  860. }
  861. }
  862. private void ConfigPortsFromMaterial( bool invalidateConnections = false, List<Texture2D> newTextures = null )
  863. {
  864. SetAdditonalTitleText( ( m_substanceGraph != null ) ? string.Format( Constants.PropertyValueLabel, m_substanceGraph.name ) : "Value( <None> )" );
  865. List<Texture2D> textures = newTextures != null ? newTextures : ( ( m_substanceGraph != null ) ? m_substanceGraph.generatedTextures : null );
  866. if( textures != null )
  867. {
  868. m_firstOutputConnected = -1;
  869. string nameToRemove = m_substanceGraph.graphLabel + "_";
  870. m_textureTypes = new ASEProceduralOutputType[ textures.Count ];
  871. for( int i = 0; i < textures.Count; i++ )
  872. {
  873. //TODO: Replace for a more efficient test as soon as Laurent gives more infos
  874. m_textureTypes[ i ] = textures[ i ].name.EndsWith( NormalMapCheck )?ASEProceduralOutputType.Normal:ASEProceduralOutputType.Color;
  875. WirePortDataType portType = ( m_autoNormal && m_textureTypes[ i ] == ASEProceduralOutputType.Normal ) ? WirePortDataType.FLOAT3 : WirePortDataType.COLOR;
  876. string newName = textures[ i ].name.Replace( nameToRemove, string.Empty );
  877. char firstLetter = Char.ToUpper( newName[ 0 ] );
  878. newName = firstLetter.ToString() + newName.Substring( 1 );
  879. if( i < m_outputPorts.Count )
  880. {
  881. m_outputPorts[ i ].ChangeProperties( newName, portType, false );
  882. if( invalidateConnections )
  883. {
  884. m_outputPorts[ i ].FullDeleteConnections();
  885. }
  886. }
  887. else
  888. {
  889. AddOutputPort( portType, newName );
  890. }
  891. }
  892. if( textures.Count < m_outputPorts.Count )
  893. {
  894. int itemsToRemove = m_outputPorts.Count - textures.Count;
  895. for( int i = 0; i < itemsToRemove; i++ )
  896. {
  897. int idx = m_outputPorts.Count - 1;
  898. if( m_outputPorts[ idx ].IsConnected )
  899. {
  900. m_outputPorts[ idx ].ForceClearConnection();
  901. }
  902. RemoveOutputPort( idx );
  903. }
  904. }
  905. }
  906. else
  907. {
  908. int itemsToRemove = m_outputPorts.Count - 1;
  909. m_outputPorts[ 0 ].ChangeProperties( Constants.EmptyPortValue, WirePortDataType.COLOR, false );
  910. m_outputPorts[ 0 ].ForceClearConnection();
  911. for( int i = 0; i < itemsToRemove; i++ )
  912. {
  913. int idx = m_outputPorts.Count - 1;
  914. if( m_outputPorts[ idx ].IsConnected )
  915. {
  916. m_outputPorts[ idx ].ForceClearConnection();
  917. }
  918. RemoveOutputPort( idx );
  919. }
  920. }
  921. m_sizeIsDirty = true;
  922. m_isDirty = true;
  923. }
  924. private void ConfigFromObject( UnityEngine.Object obj )
  925. {
  926. SubstanceGraph newGraph = obj as SubstanceGraph;// AssetDatabase.LoadAssetAtPath<SubstanceGraph>( AssetDatabase.GetAssetPath( obj ) );
  927. if( newGraph != null )
  928. {
  929. SubstanceGraph = newGraph;
  930. ConfigPortsFromMaterial();
  931. }
  932. Substance.Game.Substance newSubstance = obj as Substance.Game.Substance;// AssetDatabase.LoadAssetAtPath<SubstanceGraph>( AssetDatabase.GetAssetPath( obj ) );
  933. if( newSubstance != null && newSubstance.graphs.Count > 0 )
  934. {
  935. SubstanceGraph = newSubstance.graphs[0];
  936. ConfigPortsFromMaterial();
  937. }
  938. }
  939. public override void OnObjectDropped( UnityEngine.Object obj )
  940. {
  941. ConfigFromObject( obj );
  942. }
  943. public override void SetupFromCastObject( UnityEngine.Object obj )
  944. {
  945. ConfigFromObject( obj );
  946. }
  947. public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar )
  948. {
  949. if( m_substanceGraph == null )
  950. {
  951. return "(0).xxxx";
  952. }
  953. if( m_outputPorts[ outputId ].IsLocalValue( dataCollector.PortCategory ) )
  954. {
  955. return m_outputPorts[ outputId ].LocalValue( dataCollector.PortCategory );
  956. }
  957. List<Texture2D> textures = m_substanceGraph.generatedTextures;
  958. string uvPropertyName = string.Empty;
  959. for( int i = 0; i < m_outputPorts.Count; i++ )
  960. {
  961. if( m_outputPorts[ i ].HasConnectedNode )
  962. {
  963. uvPropertyName = UIUtils.GeneratePropertyName( textures[ i ].name , PropertyType.Property );
  964. break;
  965. }
  966. }
  967. string propertyName = UIUtils.GeneratePropertyName( textures[ outputId ].name, PropertyType.Property );
  968. string name = propertyName + OutputId;
  969. dataCollector.AddToUniforms( UniqueId, string.Format( GlobalVarDecStr, propertyName ) );
  970. dataCollector.AddToProperties( UniqueId, string.Format( PropertyDecStr, propertyName, textures[ outputId ].name ) + "{}", -1 );
  971. bool isVertex = ( dataCollector.PortCategory == MasterNodePortCategory.Vertex || dataCollector.PortCategory == MasterNodePortCategory.Tessellation );
  972. string value = string.Format( "tex2D{0}({1}, {2})", ( isVertex ? "lod" : string.Empty ), propertyName, GetUVCoords( ref dataCollector, ignoreLocalvar, uvPropertyName ) );
  973. if( m_autoNormal && m_textureTypes[ outputId ] == ASEProceduralOutputType.Normal )
  974. {
  975. value = string.Format( TemplateHelperFunctions.CreateUnpackNormalStr( dataCollector, false, "1.0" ), value );
  976. }
  977. dataCollector.AddPropertyNode( this );
  978. RegisterLocalVariable( outputId, value, ref dataCollector, name );
  979. return m_outputPorts[ outputId ].LocalValue( dataCollector.PortCategory );
  980. }
  981. public string GetUVCoords( ref MasterNodeDataCollector dataCollector, bool ignoreLocalVar, string propertyName )
  982. {
  983. bool isVertex = ( dataCollector.PortCategory == MasterNodePortCategory.Vertex || dataCollector.PortCategory == MasterNodePortCategory.Tessellation );
  984. if( m_inputPorts[ 0 ].IsConnected )
  985. {
  986. return m_inputPorts[ 0 ].GenerateShaderForOutput( ref dataCollector, isVertex ? WirePortDataType.FLOAT4 : WirePortDataType.FLOAT2, ignoreLocalVar, true );
  987. }
  988. else
  989. {
  990. string uvChannelName = IOUtils.GetUVChannelName( propertyName, m_textureCoordSet );
  991. if( dataCollector.IsTemplate )
  992. {
  993. string propertyHelperVar = propertyName + "_ST";
  994. dataCollector.AddToUniforms( UniqueId, "float4", propertyHelperVar );
  995. string uvName = string.Empty;
  996. if( dataCollector.TemplateDataCollectorInstance.HasUV( m_textureCoordSet ) )
  997. {
  998. uvName = dataCollector.TemplateDataCollectorInstance.GetUVName( m_textureCoordSet );
  999. }
  1000. else
  1001. {
  1002. uvName = dataCollector.TemplateDataCollectorInstance.RegisterUV( m_textureCoordSet );
  1003. }
  1004. uvChannelName = "uv" + propertyName;
  1005. if( isVertex )
  1006. {
  1007. string value = string.Format( Constants.TilingOffsetFormat, uvName, propertyHelperVar + ".xy", propertyHelperVar + ".zw" );
  1008. string lodLevel = "0";
  1009. value = "float4( " + value + ", 0 , " + lodLevel + " )";
  1010. dataCollector.AddLocalVariable( UniqueId, m_currentPrecisionType, WirePortDataType.FLOAT4, uvChannelName, value );
  1011. }
  1012. else
  1013. {
  1014. dataCollector.AddLocalVariable( UniqueId, m_currentPrecisionType, WirePortDataType.FLOAT2, uvChannelName, string.Format( Constants.TilingOffsetFormat, uvName, propertyHelperVar + ".xy", propertyHelperVar + ".zw" ) );
  1015. }
  1016. }
  1017. else
  1018. {
  1019. string vertexCoords = Constants.VertexShaderInputStr + ".texcoord";
  1020. if( m_textureCoordSet > 0 )
  1021. {
  1022. vertexCoords += m_textureCoordSet.ToString();
  1023. }
  1024. string dummyPropUV = "_texcoord" + ( m_textureCoordSet > 0 ? ( m_textureCoordSet + 1 ).ToString() : "" );
  1025. string dummyUV = "uv" + ( m_textureCoordSet > 0 ? ( m_textureCoordSet + 1 ).ToString() : "" ) + dummyPropUV;
  1026. dataCollector.AddToUniforms( UniqueId, "uniform float4 " + propertyName + "_ST;" );
  1027. dataCollector.AddToProperties( UniqueId, "[HideInInspector] " + dummyPropUV + "( \"\", 2D ) = \"white\" {}", 100 );
  1028. dataCollector.AddToInput( UniqueId, dummyUV, WirePortDataType.FLOAT2 );
  1029. if( isVertex )
  1030. {
  1031. dataCollector.AddToVertexLocalVariables( UniqueId, "float4 " + uvChannelName + " = float4(" + vertexCoords + " * " + propertyName + "_ST.xy + " + propertyName + "_ST.zw, 0 ,0);" );
  1032. return uvChannelName;
  1033. }
  1034. else
  1035. dataCollector.AddToLocalVariables( UniqueId, PrecisionType.Float, WirePortDataType.FLOAT2, uvChannelName, Constants.InputVarStr + "." + dummyUV + " * " + propertyName + "_ST.xy + " + propertyName + "_ST.zw" );
  1036. }
  1037. return uvChannelName;
  1038. }
  1039. }
  1040. public override void UpdateMaterial( Material mat )
  1041. {
  1042. base.UpdateMaterial( mat );
  1043. if( m_substanceGraph != null )
  1044. {
  1045. List<Texture2D> textures = m_substanceGraph.generatedTextures;
  1046. for( int i = 0; i < textures.Count; i++ )
  1047. {
  1048. string textureName = UIUtils.GeneratePropertyName( textures[ i ].name, PropertyType.Property );
  1049. if( mat.HasProperty( textureName ) && !InsideShaderFunction )
  1050. {
  1051. mat.SetTexture( textureName, textures[ i ] );
  1052. }
  1053. }
  1054. }
  1055. }
  1056. public override bool UpdateShaderDefaults( ref Shader shader, ref TextureDefaultsDataColector defaultCol )
  1057. {
  1058. if( m_substanceGraph != null )
  1059. {
  1060. List<Texture2D> textures = m_substanceGraph.generatedTextures;
  1061. for( int i = 0; i < textures.Count; i++ )
  1062. {
  1063. defaultCol.AddValue( UIUtils.GeneratePropertyName( textures[ i ].name, PropertyType.Property ), textures[ i ] );
  1064. }
  1065. }
  1066. return true;
  1067. }
  1068. public override void OnNodeLogicUpdate( DrawInfo drawInfo )
  1069. {
  1070. base.OnNodeLogicUpdate( drawInfo );
  1071. if( m_substanceGraph == null && !string.IsNullOrEmpty( m_substanceGUID ) )
  1072. {
  1073. SubstanceGraph = AssetDatabase.LoadAssetAtPath<SubstanceGraph>( AssetDatabase.GUIDToAssetPath( m_substanceGUID ) );
  1074. if( m_substanceGraph == null )
  1075. {
  1076. m_substanceGUID = string.Empty;
  1077. }
  1078. }
  1079. }
  1080. public override void Destroy()
  1081. {
  1082. base.Destroy();
  1083. m_textures = null;
  1084. m_substanceGraph = null;
  1085. m_substanceGUID = string.Empty;
  1086. m_cacheNodeConnections.Clear();
  1087. m_cacheNodeConnections = null;
  1088. m_outputConns.Clear();
  1089. m_outputConns = null;
  1090. }
  1091. public override string GetPropertyValStr()
  1092. {
  1093. return m_substanceGraph ? m_substanceGraph.name : string.Empty;
  1094. }
  1095. public override void ReadFromString( ref string[] nodeParams )
  1096. {
  1097. base.ReadFromString( ref nodeParams );
  1098. string guid = GetCurrentParam( ref nodeParams );
  1099. m_textureCoordSet = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  1100. m_autoNormal = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  1101. if( guid.Length > 1 )
  1102. {
  1103. SubstanceGraph = AssetDatabase.LoadAssetAtPath<SubstanceGraph>( AssetDatabase.GUIDToAssetPath( guid ) );
  1104. if( m_substanceGraph != null )
  1105. {
  1106. ConfigPortsFromMaterial();
  1107. }
  1108. else
  1109. {
  1110. UIUtils.ShowMessage( "Substance not found ", MessageSeverity.Error );
  1111. }
  1112. }
  1113. }
  1114. public override void WriteToString( ref string nodeInfo, ref string connectionsInfo )
  1115. {
  1116. base.WriteToString( ref nodeInfo, ref connectionsInfo );
  1117. string guid = ( m_substanceGraph != null ) ? AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath( m_substanceGraph ) ) : "0";
  1118. IOUtils.AddFieldValueToString( ref nodeInfo, guid );
  1119. IOUtils.AddFieldValueToString( ref nodeInfo, m_textureCoordSet );
  1120. IOUtils.AddFieldValueToString( ref nodeInfo, m_autoNormal );
  1121. }
  1122. public SubstanceGraph SubstanceGraph
  1123. {
  1124. set
  1125. {
  1126. m_substanceGraph = value;
  1127. if( value != null )
  1128. {
  1129. m_substanceGUID = AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath( value ) );
  1130. }
  1131. else
  1132. {
  1133. m_substanceGUID = string.Empty;
  1134. }
  1135. }
  1136. get { return m_substanceGraph; }
  1137. }
  1138. }
  1139. #pragma warning restore 0618
  1140. }
  1141. #endif