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.

254 lines
10 KiB

  1. // Amplify Shader Editor - Visual Shader Editing Tool
  2. // Copyright (c) Amplify Creations, Lda <info@amplify.pt>
  3. // Based on the work by https://github.com/keijiro/NoiseShader
  4. using System;
  5. using UnityEditor;
  6. using UnityEngine;
  7. namespace AmplifyShaderEditor
  8. {
  9. public enum NoiseGeneratorType
  10. {
  11. Simplex2D,
  12. Simplex3D
  13. };
  14. [Serializable]
  15. [NodeAttributes( "Noise Generator", "Miscellaneous", "Collection of procedural noise generators" )]
  16. public sealed class NoiseGeneratorNode : ParentNode
  17. {
  18. private const string TypeLabelStr = "Type";
  19. // Simplex 2D
  20. private const string Simplex2DFloat3Mod289Func = "float3 mod2D289( float3 x ) { return x - floor( x * ( 1.0 / 289.0 ) ) * 289.0; }";
  21. private const string Simplex2DFloat2Mod289Func = "float2 mod2D289( float2 x ) { return x - floor( x * ( 1.0 / 289.0 ) ) * 289.0; }";
  22. private const string Simplex2DPermuteFunc = "float3 permute( float3 x ) { return mod2D289( ( ( x * 34.0 ) + 1.0 ) * x ); }";
  23. private const string SimplexNoise2DHeader = "float snoise( float2 v )";
  24. private const string SimplexNoise2DFunc = "snoise( {0} )";
  25. private readonly string[] SimplexNoise2DBody = {"float snoise( float2 v )\n",
  26. "{\n",
  27. "\tconst float4 C = float4( 0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439 );\n",
  28. "\tfloat2 i = floor( v + dot( v, C.yy ) );\n",
  29. "\tfloat2 x0 = v - i + dot( i, C.xx );\n",
  30. "\tfloat2 i1;\n",
  31. "\ti1 = ( x0.x > x0.y ) ? float2( 1.0, 0.0 ) : float2( 0.0, 1.0 );\n",
  32. "\tfloat4 x12 = x0.xyxy + C.xxzz;\n",
  33. "\tx12.xy -= i1;\n",
  34. "\ti = mod2D289( i );\n",
  35. "\tfloat3 p = permute( permute( i.y + float3( 0.0, i1.y, 1.0 ) ) + i.x + float3( 0.0, i1.x, 1.0 ) );\n",
  36. "\tfloat3 m = max( 0.5 - float3( dot( x0, x0 ), dot( x12.xy, x12.xy ), dot( x12.zw, x12.zw ) ), 0.0 );\n",
  37. "\tm = m * m;\n",
  38. "\tm = m * m;\n",
  39. "\tfloat3 x = 2.0 * frac( p * C.www ) - 1.0;\n",
  40. "\tfloat3 h = abs( x ) - 0.5;\n",
  41. "\tfloat3 ox = floor( x + 0.5 );\n",
  42. "\tfloat3 a0 = x - ox;\n",
  43. "\tm *= 1.79284291400159 - 0.85373472095314 * ( a0 * a0 + h * h );\n",
  44. "\tfloat3 g;\n",
  45. "\tg.x = a0.x * x0.x + h.x * x0.y;\n",
  46. "\tg.yz = a0.yz * x12.xz + h.yz * x12.yw;\n",
  47. "\treturn 130.0 * dot( m, g );\n",
  48. "}\n"};
  49. // Simplex 3D
  50. private const string Simplex3DFloat3Mod289 = "float3 mod3D289( float3 x ) { return x - floor( x / 289.0 ) * 289.0; }";
  51. private const string Simplex3DFloat4Mod289 = "float4 mod3D289( float4 x ) { return x - floor( x / 289.0 ) * 289.0; }";
  52. private const string Simplex3DFloat4Permute = "float4 permute( float4 x ) { return mod3D289( ( x * 34.0 + 1.0 ) * x ); }";
  53. private const string TaylorInvSqrtFunc = "float4 taylorInvSqrt( float4 r ) { return 1.79284291400159 - r * 0.85373472095314; }";
  54. private const string SimplexNoise3DHeader = "float snoise( float3 v )";
  55. private const string SimplexNoise3DFunc = "snoise( {0} )";
  56. private readonly string[] SimplexNoise3DBody = {"float snoise( float3 v )\n",
  57. "{\n",
  58. "\tconst float2 C = float2( 1.0 / 6.0, 1.0 / 3.0 );\n",
  59. "\tfloat3 i = floor( v + dot( v, C.yyy ) );\n",
  60. "\tfloat3 x0 = v - i + dot( i, C.xxx );\n",
  61. "\tfloat3 g = step( x0.yzx, x0.xyz );\n",
  62. "\tfloat3 l = 1.0 - g;\n",
  63. "\tfloat3 i1 = min( g.xyz, l.zxy );\n",
  64. "\tfloat3 i2 = max( g.xyz, l.zxy );\n",
  65. "\tfloat3 x1 = x0 - i1 + C.xxx;\n",
  66. "\tfloat3 x2 = x0 - i2 + C.yyy;\n",
  67. "\tfloat3 x3 = x0 - 0.5;\n",
  68. "\ti = mod3D289( i);\n",
  69. "\tfloat4 p = permute( permute( permute( i.z + float4( 0.0, i1.z, i2.z, 1.0 ) ) + i.y + float4( 0.0, i1.y, i2.y, 1.0 ) ) + i.x + float4( 0.0, i1.x, i2.x, 1.0 ) );\n",
  70. "\tfloat4 j = p - 49.0 * floor( p / 49.0 ); // mod(p,7*7)\n",
  71. "\tfloat4 x_ = floor( j / 7.0 );\n",
  72. "\tfloat4 y_ = floor( j - 7.0 * x_ ); // mod(j,N)\n",
  73. "\tfloat4 x = ( x_ * 2.0 + 0.5 ) / 7.0 - 1.0;\n",
  74. "\tfloat4 y = ( y_ * 2.0 + 0.5 ) / 7.0 - 1.0;\n",
  75. "\tfloat4 h = 1.0 - abs( x ) - abs( y );\n",
  76. "\tfloat4 b0 = float4( x.xy, y.xy );\n",
  77. "\tfloat4 b1 = float4( x.zw, y.zw );\n",
  78. "\tfloat4 s0 = floor( b0 ) * 2.0 + 1.0;\n",
  79. "\tfloat4 s1 = floor( b1 ) * 2.0 + 1.0;\n",
  80. "\tfloat4 sh = -step( h, 0.0 );\n",
  81. "\tfloat4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;\n",
  82. "\tfloat4 a1 = b1.xzyw + s1.xzyw * sh.zzww;\n",
  83. "\tfloat3 g0 = float3( a0.xy, h.x );\n",
  84. "\tfloat3 g1 = float3( a0.zw, h.y );\n",
  85. "\tfloat3 g2 = float3( a1.xy, h.z );\n",
  86. "\tfloat3 g3 = float3( a1.zw, h.w );\n",
  87. "\tfloat4 norm = taylorInvSqrt( float4( dot( g0, g0 ), dot( g1, g1 ), dot( g2, g2 ), dot( g3, g3 ) ) );\n",
  88. "\tg0 *= norm.x;\n",
  89. "\tg1 *= norm.y;\n",
  90. "\tg2 *= norm.z;\n",
  91. "\tg3 *= norm.w;\n",
  92. "\tfloat4 m = max( 0.6 - float4( dot( x0, x0 ), dot( x1, x1 ), dot( x2, x2 ), dot( x3, x3 ) ), 0.0 );\n",
  93. "\tm = m* m;\n",
  94. "\tm = m* m;\n",
  95. "\tfloat4 px = float4( dot( x0, g0 ), dot( x1, g1 ), dot( x2, g2 ), dot( x3, g3 ) );\n",
  96. "\treturn 42.0 * dot( m, px);\n",
  97. "}\n"};
  98. [SerializeField]
  99. private NoiseGeneratorType m_type = NoiseGeneratorType.Simplex2D;
  100. private UpperLeftWidgetHelper m_upperLeftWidget = new UpperLeftWidgetHelper();
  101. protected override void CommonInit( int uniqueId )
  102. {
  103. base.CommonInit( uniqueId );
  104. AddInputPort( WirePortDataType.FLOAT2, false, "Size" );
  105. AddOutputPort( WirePortDataType.FLOAT, Constants.EmptyPortValue );
  106. m_useInternalPortData = true;
  107. m_autoWrapProperties = true;
  108. m_hasLeftDropdown = true;
  109. SetAdditonalTitleText( string.Format( Constants.SubTitleTypeFormatStr, m_type ) );
  110. m_previewShaderGUID = "cd2d37ef5da190b42a91a5a690ba2a7d";
  111. }
  112. public override void AfterCommonInit()
  113. {
  114. base.AfterCommonInit();
  115. if( PaddingTitleLeft == 0 )
  116. {
  117. PaddingTitleLeft = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin;
  118. if( PaddingTitleRight == 0 )
  119. PaddingTitleRight = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin;
  120. }
  121. }
  122. public override void Destroy()
  123. {
  124. base.Destroy();
  125. m_upperLeftWidget = null;
  126. }
  127. public override void Draw( DrawInfo drawInfo )
  128. {
  129. base.Draw( drawInfo );
  130. m_upperLeftWidget.DrawWidget<NoiseGeneratorType>( ref m_type, this, OnWidgetUpdate );
  131. }
  132. private readonly Action<ParentNode> OnWidgetUpdate = ( x ) =>
  133. {
  134. ( x as NoiseGeneratorNode ).ConfigurePorts();
  135. };
  136. public override void DrawProperties()
  137. {
  138. base.DrawProperties();
  139. EditorGUI.BeginChangeCheck();
  140. m_type = (NoiseGeneratorType)EditorGUILayoutEnumPopup( TypeLabelStr, m_type );
  141. if( EditorGUI.EndChangeCheck() )
  142. {
  143. ConfigurePorts();
  144. }
  145. //EditorGUILayout.HelpBox( "Node still under construction. Use with caution", MessageType.Info );
  146. }
  147. private void ConfigurePorts()
  148. {
  149. SetAdditonalTitleText( string.Format( Constants.SubTitleTypeFormatStr, m_type ) );
  150. switch( m_type )
  151. {
  152. case NoiseGeneratorType.Simplex2D:
  153. {
  154. m_inputPorts[ 0 ].ChangeType( WirePortDataType.FLOAT2, false );
  155. m_previewMaterialPassId = 0;
  156. }
  157. break;
  158. case NoiseGeneratorType.Simplex3D:
  159. {
  160. m_inputPorts[ 0 ].ChangeType( WirePortDataType.FLOAT3, false );
  161. m_previewMaterialPassId = 1;
  162. }
  163. break;
  164. }
  165. }
  166. public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar )
  167. {
  168. if( m_outputPorts[ 0 ].IsLocalValue( dataCollector.PortCategory ) )
  169. {
  170. return m_outputPorts[ 0 ].LocalValue( dataCollector.PortCategory );
  171. }
  172. switch( m_type )
  173. {
  174. case NoiseGeneratorType.Simplex2D:
  175. {
  176. string float3Mod289Func = ( dataCollector.IsTemplate ) ? Simplex2DFloat3Mod289Func : "\t\t" + Simplex2DFloat3Mod289Func;
  177. dataCollector.AddFunction( Simplex2DFloat3Mod289Func, float3Mod289Func );
  178. string float2Mod289Func = ( dataCollector.IsTemplate ) ? Simplex2DFloat2Mod289Func : "\t\t" + Simplex2DFloat2Mod289Func;
  179. dataCollector.AddFunction( Simplex2DFloat2Mod289Func, float2Mod289Func );
  180. string permuteFunc = ( dataCollector.IsTemplate ) ? Simplex2DPermuteFunc : "\t\t" + Simplex2DPermuteFunc;
  181. dataCollector.AddFunction( Simplex2DPermuteFunc, permuteFunc );
  182. dataCollector.AddFunction( SimplexNoise2DHeader, SimplexNoise2DBody, false );
  183. string size = m_inputPorts[ 0 ].GeneratePortInstructions( ref dataCollector );
  184. RegisterLocalVariable( 0, string.Format( SimplexNoise2DFunc, size ), ref dataCollector, ( "simplePerlin2D" + OutputId ) );
  185. }
  186. break;
  187. case NoiseGeneratorType.Simplex3D:
  188. {
  189. string float3Mod289Func = ( dataCollector.IsTemplate ) ? Simplex3DFloat3Mod289 : "\t\t" + Simplex3DFloat3Mod289;
  190. dataCollector.AddFunction( Simplex3DFloat3Mod289, float3Mod289Func );
  191. string float4Mod289Func = ( dataCollector.IsTemplate ) ? Simplex3DFloat4Mod289 : "\t\t" + Simplex3DFloat4Mod289;
  192. dataCollector.AddFunction( Simplex3DFloat4Mod289, float4Mod289Func );
  193. string permuteFunc = ( dataCollector.IsTemplate ) ? Simplex3DFloat4Permute : "\t\t" + Simplex3DFloat4Permute;
  194. dataCollector.AddFunction( Simplex3DFloat4Permute, permuteFunc );
  195. string taylorInvSqrtFunc = ( dataCollector.IsTemplate ) ? TaylorInvSqrtFunc : "\t\t" + TaylorInvSqrtFunc;
  196. dataCollector.AddFunction( TaylorInvSqrtFunc, taylorInvSqrtFunc );
  197. dataCollector.AddFunction( SimplexNoise3DHeader, SimplexNoise3DBody, false );
  198. string size = m_inputPorts[ 0 ].GeneratePortInstructions( ref dataCollector );
  199. RegisterLocalVariable( 0, string.Format( SimplexNoise3DFunc, size ), ref dataCollector, ( "simplePerlin3D" + OutputId ) );
  200. }
  201. break;
  202. }
  203. return m_outputPorts[ 0 ].LocalValue( dataCollector.PortCategory );
  204. }
  205. public override void ReadFromString( ref string[] nodeParams )
  206. {
  207. base.ReadFromString( ref nodeParams );
  208. m_type = (NoiseGeneratorType)Enum.Parse( typeof( NoiseGeneratorType ), GetCurrentParam( ref nodeParams ) );
  209. ConfigurePorts();
  210. }
  211. public override void WriteToString( ref string nodeInfo, ref string connectionsInfo )
  212. {
  213. base.WriteToString( ref nodeInfo, ref connectionsInfo );
  214. IOUtils.AddFieldValueToString( ref nodeInfo, m_type );
  215. }
  216. }
  217. }