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.

376 lines
13 KiB

  1. // Amplify Shader Editor - Visual Shader Editing Tool
  2. // Copyright (c) Amplify Creations, Lda <info@amplify.pt>
  3. // http://kylehalladay.com/blog/tutorial/2014/02/18/Fresnel-Shaders-From-The-Ground-Up.html
  4. // http://http.developer.nvidia.com/CgTutorial/cg_tutorial_chapter07.html
  5. using System;
  6. using UnityEngine;
  7. using UnityEditor;
  8. namespace AmplifyShaderEditor
  9. {
  10. [Serializable]
  11. [NodeAttributes( "Fresnel", "Surface Data", "Simple Fresnel effect" )]
  12. public sealed class FresnelNode : ParentNode
  13. {
  14. private const string FresnedFinalVar = "fresnelNode";
  15. [SerializeField]
  16. private ViewSpace m_normalSpace = ViewSpace.Tangent;
  17. enum FresnelType
  18. {
  19. Standard = 0,
  20. Schlick,
  21. SchlickIOR,
  22. }
  23. enum NormalType
  24. {
  25. WorldNormal = 0,
  26. TangentNormal,
  27. HalfVector,
  28. }
  29. enum ViewType
  30. {
  31. ViewDir = 0,
  32. LightDir,
  33. }
  34. [SerializeField]
  35. private FresnelType m_fresnelType = FresnelType.Standard;
  36. [SerializeField]
  37. private NormalType m_normalType = NormalType.WorldNormal;
  38. [SerializeField]
  39. private ViewType m_viewType = ViewType.ViewDir;
  40. [SerializeField]
  41. private bool m_normalizeVectors = false;
  42. private InputPort m_normalVecPort;
  43. private InputPort m_viewVecPort;
  44. private InputPort m_biasPort;
  45. private InputPort m_scalePort;
  46. private InputPort m_powerPort;
  47. protected override void CommonInit( int uniqueId )
  48. {
  49. base.CommonInit( uniqueId );
  50. AddInputPort( WirePortDataType.FLOAT3, false, "World Normal", -1, MasterNodePortCategory.Fragment, 0 );
  51. AddInputPort( WirePortDataType.FLOAT3, false, "View Dir", -1, MasterNodePortCategory.Fragment, 4 );
  52. AddInputPort( WirePortDataType.FLOAT, false, "Bias", -1, MasterNodePortCategory.Fragment, 1 );
  53. AddInputPort( WirePortDataType.FLOAT, false, "Scale", -1, MasterNodePortCategory.Fragment, 2 );
  54. AddInputPort( WirePortDataType.FLOAT, false, "Power", -1, MasterNodePortCategory.Fragment, 3 );
  55. AddOutputPort( WirePortDataType.FLOAT, "Out" );
  56. m_normalVecPort = m_inputPorts[ 0 ];
  57. m_viewVecPort = m_inputPorts[ 1 ];
  58. m_biasPort = m_inputPorts[ 2 ];
  59. m_scalePort = m_inputPorts[ 3 ];
  60. m_powerPort = m_inputPorts[ 4 ];
  61. m_biasPort.AutoDrawInternalData = true;
  62. m_scalePort.AutoDrawInternalData = true;
  63. m_powerPort.AutoDrawInternalData = true;
  64. m_autoWrapProperties = true;
  65. m_drawPreviewAsSphere = true;
  66. m_normalVecPort.Vector3InternalData = Vector3.forward;
  67. m_scalePort.FloatInternalData = 1;
  68. m_powerPort.FloatInternalData = 5;
  69. m_previewShaderGUID = "240145eb70cf79f428015012559f4e7d";
  70. }
  71. public override void SetPreviewInputs()
  72. {
  73. base.SetPreviewInputs();
  74. //m_mate
  75. PreviewMaterial.SetInt( "_FresnelType", (int)m_fresnelType );
  76. if( m_normalType == NormalType.TangentNormal && m_normalVecPort.IsConnected )
  77. m_previewMaterialPassId = 2;
  78. else if( (m_normalType == NormalType.WorldNormal || m_normalType == NormalType.HalfVector ) && m_normalVecPort.IsConnected && !m_viewVecPort.IsConnected )
  79. m_previewMaterialPassId = 1;
  80. else if( m_normalType == NormalType.HalfVector && !m_normalVecPort.IsConnected && !m_viewVecPort.IsConnected )
  81. m_previewMaterialPassId = 3;
  82. else if( m_normalVecPort.IsConnected && m_viewVecPort.IsConnected )
  83. m_previewMaterialPassId = 4;
  84. else if( !m_normalVecPort.IsConnected && !m_viewVecPort.IsConnected && m_viewType == ViewType.LightDir )
  85. m_previewMaterialPassId = 5;
  86. else if( !m_normalVecPort.IsConnected && m_viewVecPort.IsConnected && m_normalType == NormalType.HalfVector )
  87. m_previewMaterialPassId = 7;
  88. else if( !m_normalVecPort.IsConnected && m_viewVecPort.IsConnected )
  89. m_previewMaterialPassId = 6;
  90. else
  91. m_previewMaterialPassId = 0;
  92. }
  93. public override void DrawProperties()
  94. {
  95. base.DrawProperties();
  96. EditorGUI.BeginChangeCheck();
  97. m_fresnelType = (FresnelType)EditorGUILayoutEnumPopup( "Type", m_fresnelType );
  98. m_normalType = (NormalType)EditorGUILayoutEnumPopup( "Normal Vector", m_normalType );
  99. m_viewType = (ViewType)EditorGUILayoutEnumPopup( "View Vector", m_viewType );
  100. if( EditorGUI.EndChangeCheck() )
  101. {
  102. UpdatePort();
  103. }
  104. if( !m_biasPort.IsConnected && m_biasPort.Visible )
  105. m_biasPort.FloatInternalData = EditorGUILayoutFloatField( m_biasPort.Name, m_biasPort.FloatInternalData );
  106. if( !m_scalePort.IsConnected && m_scalePort.Visible )
  107. m_scalePort.FloatInternalData = EditorGUILayoutFloatField( m_scalePort.Name, m_scalePort.FloatInternalData );
  108. if( !m_powerPort.IsConnected && m_powerPort.Visible )
  109. m_powerPort.FloatInternalData = EditorGUILayoutFloatField( m_powerPort.Name, m_powerPort.FloatInternalData );
  110. m_normalizeVectors = EditorGUILayoutToggle( "Normalize Vectors", m_normalizeVectors );
  111. }
  112. private void UpdatePort()
  113. {
  114. switch( m_normalType )
  115. {
  116. default:
  117. case NormalType.WorldNormal:
  118. m_normalVecPort.Name = "World Normal";
  119. break;
  120. case NormalType.TangentNormal:
  121. m_normalVecPort.Name = "Normal";
  122. break;
  123. case NormalType.HalfVector:
  124. m_normalVecPort.Name = "Half Vector";
  125. break;
  126. }
  127. switch( m_viewType )
  128. {
  129. default:
  130. case ViewType.ViewDir:
  131. m_viewVecPort.Name = "View Dir";
  132. break;
  133. case ViewType.LightDir:
  134. m_viewVecPort.Name = "Light Dir";
  135. break;
  136. }
  137. switch( m_fresnelType )
  138. {
  139. default:
  140. case FresnelType.Standard:
  141. m_biasPort.Visible = true;
  142. m_biasPort.Name = "Bias";
  143. m_scalePort.Name = "Scale";
  144. m_scalePort.Visible = true;
  145. m_powerPort.Visible = true;
  146. break;
  147. case FresnelType.Schlick:
  148. m_biasPort.Visible = true;
  149. m_biasPort.Name = "F0";
  150. m_scalePort.Visible = false;
  151. m_powerPort.Visible = false;
  152. break;
  153. case FresnelType.SchlickIOR:
  154. m_biasPort.Visible = false;
  155. m_scalePort.Name = "IOR";
  156. m_scalePort.Visible = true;
  157. m_powerPort.Visible = false;
  158. break;
  159. }
  160. m_sizeIsDirty = true;
  161. }
  162. public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar )
  163. {
  164. if( m_outputPorts[ 0 ].IsLocalValue( dataCollector.PortCategory ) )
  165. return m_outputPorts[ 0 ].LocalValue( dataCollector.PortCategory );
  166. if( dataCollector.IsFragmentCategory )
  167. dataCollector.AddToInput( UniqueId, SurfaceInputs.WORLD_POS );
  168. string viewdir = string.Empty;
  169. if( m_viewType == ViewType.ViewDir )
  170. {
  171. if( m_viewVecPort.IsConnected )
  172. viewdir = m_viewVecPort.GeneratePortInstructions( ref dataCollector );
  173. else
  174. viewdir = GeneratorUtils.GenerateViewDirection( ref dataCollector, UniqueId, ViewSpace.World );
  175. }
  176. else
  177. {
  178. if( m_viewVecPort.IsConnected )
  179. viewdir = m_viewVecPort.GeneratePortInstructions( ref dataCollector );
  180. else
  181. viewdir = GeneratorUtils.GenerateWorldLightDirection( ref dataCollector, UniqueId, m_currentPrecisionType );
  182. }
  183. string normal = string.Empty;
  184. if( m_normalType == NormalType.WorldNormal || m_normalType == NormalType.TangentNormal )
  185. {
  186. if( m_normalVecPort.IsConnected )
  187. {
  188. normal = m_normalVecPort.GeneratePortInstructions( ref dataCollector );
  189. if( dataCollector.IsFragmentCategory )
  190. {
  191. dataCollector.AddToInput( UniqueId, SurfaceInputs.INTERNALDATA, addSemiColon: false );
  192. if( m_normalType == NormalType.TangentNormal )
  193. {
  194. if( dataCollector.IsTemplate )
  195. {
  196. normal = dataCollector.TemplateDataCollectorInstance.GetWorldNormal( UniqueId, m_currentPrecisionType, normal, OutputId );
  197. }
  198. else
  199. {
  200. normal = GeneratorUtils.GenerateWorldNormal( ref dataCollector, UniqueId, m_currentPrecisionType, normal, OutputId );
  201. dataCollector.AddToInput( UniqueId, SurfaceInputs.WORLD_NORMAL, m_currentPrecisionType );
  202. dataCollector.ForceNormal = true;
  203. }
  204. }
  205. else
  206. {
  207. if( m_normalizeVectors )
  208. normal = string.Format( "normalize( {0} )", normal );
  209. }
  210. }
  211. else
  212. {
  213. if( m_normalType == NormalType.TangentNormal )
  214. {
  215. string wtMatrix = GeneratorUtils.GenerateWorldToTangentMatrix( ref dataCollector, UniqueId, m_currentPrecisionType );
  216. normal = "mul( " + normal + "," + wtMatrix + " )";
  217. }
  218. }
  219. }
  220. else
  221. {
  222. if( dataCollector.IsFragmentCategory )
  223. {
  224. dataCollector.AddToInput( UniqueId, SurfaceInputs.WORLD_NORMAL, m_currentPrecisionType );
  225. if( dataCollector.DirtyNormal )
  226. dataCollector.AddToInput( UniqueId, SurfaceInputs.INTERNALDATA, addSemiColon: false );
  227. }
  228. if( dataCollector.IsTemplate )
  229. normal = dataCollector.TemplateDataCollectorInstance.GetWorldNormal( m_currentPrecisionType, normalize: ( dataCollector.DirtyNormal && m_normalizeVectors ) );
  230. else
  231. normal = GeneratorUtils.GenerateWorldNormal( ref dataCollector, UniqueId, ( dataCollector.DirtyNormal && m_normalizeVectors ) );
  232. if( dataCollector.DirtyNormal )
  233. {
  234. dataCollector.ForceNormal = true;
  235. }
  236. }
  237. }
  238. else
  239. {
  240. // generate HV
  241. if( !m_normalVecPort.IsConnected )
  242. {
  243. string halfView = GeneratorUtils.GenerateViewDirection( ref dataCollector, UniqueId, ViewSpace.World );
  244. string halfLight = GeneratorUtils.GenerateWorldLightDirection( ref dataCollector, UniqueId, m_currentPrecisionType );
  245. normal = "halfVector" + OutputId;
  246. dataCollector.AddLocalVariable( UniqueId, m_currentPrecisionType, WirePortDataType.FLOAT3, normal, "normalize( " + halfView + " + " + halfLight + " )" );
  247. }
  248. else
  249. {
  250. normal = m_normalVecPort.GeneratePortInstructions( ref dataCollector );
  251. if( m_normalizeVectors )
  252. normal = string.Format( "normalize( {0} )", normal );
  253. }
  254. }
  255. string bias = m_biasPort.GeneratePortInstructions( ref dataCollector );
  256. string scale = m_scalePort.GeneratePortInstructions( ref dataCollector );
  257. string power = m_powerPort.GeneratePortInstructions( ref dataCollector );
  258. string fresnelNDotVLocalValue = "dot( " + normal + ", " + viewdir + " )";
  259. string fresnelNDotVLocalVar = "fresnelNdotV" + OutputId;
  260. dataCollector.AddLocalVariable( UniqueId, m_currentPrecisionType, WirePortDataType.FLOAT, fresnelNDotVLocalVar, fresnelNDotVLocalValue );
  261. string fresnelFinalVar = FresnedFinalVar + OutputId;
  262. string result = string.Empty;
  263. switch( m_fresnelType )
  264. {
  265. default:
  266. case FresnelType.Standard:
  267. {
  268. result = string.Format( "( {0} + {1} * pow( 1.0 - {2}, {3} ) )", bias, scale, fresnelNDotVLocalVar, power );
  269. }
  270. break;
  271. case FresnelType.Schlick:
  272. {
  273. string f0VarName = "f0" + OutputId;
  274. dataCollector.AddLocalVariable( UniqueId, m_currentPrecisionType, WirePortDataType.FLOAT, f0VarName, bias );
  275. result = string.Format( "( {0} + ( 1.0 - {0} ) * pow( 1.0 - {1}, 5 ) )", f0VarName, fresnelNDotVLocalVar );
  276. }
  277. break;
  278. case FresnelType.SchlickIOR:
  279. {
  280. string iorVarName = "ior" + OutputId;
  281. dataCollector.AddLocalVariable( UniqueId, m_currentPrecisionType, WirePortDataType.FLOAT, iorVarName, scale );
  282. dataCollector.AddLocalVariable( UniqueId, iorVarName +" = pow( ( 1-"+ iorVarName +" )/( 1+"+iorVarName+" ), 2 );");
  283. result = string.Format( "( {0} + ( 1.0 - {0} ) * pow( 1.0 - {1}, 5 ) )", iorVarName, fresnelNDotVLocalVar );
  284. }
  285. break;
  286. }
  287. RegisterLocalVariable( 0, result, ref dataCollector, fresnelFinalVar );
  288. return m_outputPorts[ 0 ].LocalValue( dataCollector.PortCategory );
  289. }
  290. public override void PropagateNodeData( NodeData nodeData, ref MasterNodeDataCollector dataCollector )
  291. {
  292. base.PropagateNodeData( nodeData, ref dataCollector );
  293. if( m_normalType == NormalType.TangentNormal && m_normalVecPort.IsConnected )
  294. dataCollector.DirtyNormal = true;
  295. }
  296. public override void ReadFromString( ref string[] nodeParams )
  297. {
  298. base.ReadFromString( ref nodeParams );
  299. if( UIUtils.CurrentShaderVersion() > 15305 )
  300. {
  301. m_fresnelType = (FresnelType)Enum.Parse( typeof( FresnelType ), GetCurrentParam( ref nodeParams ) );
  302. m_normalType = (NormalType)Enum.Parse( typeof( NormalType ), GetCurrentParam( ref nodeParams ) );
  303. m_viewType = (ViewType)Enum.Parse( typeof( ViewType ), GetCurrentParam( ref nodeParams ) );
  304. m_normalizeVectors = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  305. }
  306. else
  307. {
  308. if( UIUtils.CurrentShaderVersion() >= 13202 )
  309. {
  310. m_normalSpace = (ViewSpace)Enum.Parse( typeof( ViewSpace ), GetCurrentParam( ref nodeParams ) );
  311. }
  312. else
  313. {
  314. m_normalSpace = ViewSpace.World;
  315. }
  316. if( m_normalSpace == ViewSpace.World )
  317. m_normalType = NormalType.WorldNormal;
  318. else
  319. m_normalType = NormalType.TangentNormal;
  320. }
  321. UpdatePort();
  322. }
  323. public override void WriteToString( ref string nodeInfo, ref string connectionsInfo )
  324. {
  325. base.WriteToString( ref nodeInfo, ref connectionsInfo );
  326. IOUtils.AddFieldValueToString( ref nodeInfo, m_fresnelType );
  327. IOUtils.AddFieldValueToString( ref nodeInfo, m_normalType );
  328. IOUtils.AddFieldValueToString( ref nodeInfo, m_viewType );
  329. IOUtils.AddFieldValueToString( ref nodeInfo, m_normalizeVectors );
  330. }
  331. }
  332. }