You've already forked FateViewer
							
							
		
			
				
	
	
		
			250 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
// Amplify Shader Editor - Visual Shader Editing Tool
 | 
						|
// Copyright (c) Amplify Creations, Lda <info@amplify.pt>
 | 
						|
 | 
						|
// Billboard based on:
 | 
						|
// https://gist.github.com/renaudbedard/7a90ec4a5a7359712202
 | 
						|
using System;
 | 
						|
using UnityEngine;
 | 
						|
using System.Collections.Generic;
 | 
						|
 | 
						|
namespace AmplifyShaderEditor
 | 
						|
{
 | 
						|
	public enum BillboardType
 | 
						|
	{
 | 
						|
		Cylindrical,
 | 
						|
		Spherical
 | 
						|
	}
 | 
						|
 | 
						|
	[Serializable]
 | 
						|
	public class BillboardOpHelper
 | 
						|
	{
 | 
						|
		public static readonly string BillboardTitleStr = " Billboard";
 | 
						|
		public static readonly string BillboardTypeStr = "Type";
 | 
						|
		public static readonly string BillboardRotIndStr = "Ignore Rotation";
 | 
						|
 | 
						|
		public static readonly string[] BillboardCylindricalInstructions = { "//Calculate new billboard vertex position and normal",
 | 
						|
																			"float3 upCamVec = float3( 0, 1, 0 )"};
 | 
						|
 | 
						|
		public static readonly string[] BillboardSphericalInstructions = {   "//Calculate new billboard vertex position and normal",
 | 
						|
																			"float3 upCamVec = normalize ( UNITY_MATRIX_V._m10_m11_m12 )"};
 | 
						|
 | 
						|
 | 
						|
		public static readonly string[] BillboardCommonInstructions = { "float3 forwardCamVec = -normalize ( UNITY_MATRIX_V._m20_m21_m22 )",
 | 
						|
																		"float3 rightCamVec = normalize( UNITY_MATRIX_V._m00_m01_m02 )",
 | 
						|
																		"float4x4 rotationCamMatrix = float4x4( rightCamVec, 0, upCamVec, 0, forwardCamVec, 0, 0, 0, 0, 1 )",
 | 
						|
																		"{0} = normalize( mul( float4( {0} , 0 ), rotationCamMatrix )).xyz"};
 | 
						|
 | 
						|
		public static readonly string[] BillboardRotDependent = {   "//This unfortunately must be made to take non-uniform scaling into account",
 | 
						|
																	"//Transform to world coords, apply rotation and transform back to local",
 | 
						|
																	"{0} = mul( {1} , unity_ObjectToWorld ){2}",
 | 
						|
																	"{0} = mul( {1} , rotationCamMatrix ){2}",
 | 
						|
																	"{0} = mul( {1} , unity_WorldToObject ){2}"};
 | 
						|
 | 
						|
 | 
						|
		public static readonly string[] BillboardRotIndependent = { "{0}.x *= length( unity_ObjectToWorld._m00_m10_m20 )",
 | 
						|
																	"{0}.y *= length( unity_ObjectToWorld._m01_m11_m21 )",
 | 
						|
																	"{0}.z *= length( unity_ObjectToWorld._m02_m12_m22 )",
 | 
						|
																	"{0} = mul( {0}, rotationCamMatrix )",
 | 
						|
																	"{0}.xyz += unity_ObjectToWorld._m03_m13_m23",
 | 
						|
																	"//Need to nullify rotation inserted by generated surface shader",
 | 
						|
																	"{0} = mul( unity_WorldToObject, {0} )"};
 | 
						|
 | 
						|
 | 
						|
 | 
						|
		public static readonly string[] BillboardHDRotDependent = {   "//This unfortunately must be made to take non-uniform scaling into account",
 | 
						|
																	"//Transform to world coords, apply rotation and transform back to local",
 | 
						|
																	"{0} = mul( {1} , GetObjectToWorldMatrix() ){2}",
 | 
						|
																	"{0} = mul( {1} , rotationCamMatrix ){2}",
 | 
						|
																	"{0} = mul( {1} , GetWorldToObjectMatrix() ){2}"};
 | 
						|
 | 
						|
 | 
						|
		public static readonly string[] BillboardHDRotIndependent = { "{0}.x *= length( GetObjectToWorldMatrix()._m00_m10_m20 )",
 | 
						|
																	"{0}.y *= length( GetObjectToWorldMatrix()._m01_m11_m21 )",
 | 
						|
																	"{0}.z *= length( GetObjectToWorldMatrix()._m02_m12_m22 )",
 | 
						|
																	"{0} = mul( {0}, rotationCamMatrix )",
 | 
						|
																	//Had to comment this one out in HDRP since it was moving the vertices to incorrect locations
 | 
						|
																	// Over HDRP the correct results are achievied without having to do this operation
 | 
						|
																	//This is because the vertex position variable is a float3 and an implicit cast is done to float4
 | 
						|
																	//with w set to 0, this makes the multiplication below only affects rotation and not translation
 | 
						|
																	//thus no adding the world translation is needed to counter the GetObjectToWorldMatrix() operation
 | 
						|
																	"//{0}.xyz += GetObjectToWorldMatrix()._m03_m13_m23",
 | 
						|
																	"//Need to nullify rotation inserted by generated surface shader",
 | 
						|
																	"{0} = mul( GetWorldToObjectMatrix(), {0} )"};
 | 
						|
 | 
						|
 | 
						|
		[SerializeField]
 | 
						|
		private bool m_isBillboard = false;
 | 
						|
 | 
						|
		[SerializeField]
 | 
						|
		private BillboardType m_billboardType = BillboardType.Cylindrical;
 | 
						|
 | 
						|
		[SerializeField]
 | 
						|
		private bool m_rotationIndependent = false;
 | 
						|
 | 
						|
		public void Draw( ParentNode owner )
 | 
						|
		{
 | 
						|
			bool visible = owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedVertexOptions;
 | 
						|
			bool enabled = m_isBillboard;
 | 
						|
			NodeUtils.DrawPropertyGroup( owner, ref visible, ref m_isBillboard, BillboardTitleStr, () =>
 | 
						|
			{
 | 
						|
				m_billboardType = (BillboardType)owner.EditorGUILayoutEnumPopup( BillboardTypeStr, m_billboardType );
 | 
						|
				m_rotationIndependent = owner.EditorGUILayoutToggle( BillboardRotIndStr, m_rotationIndependent );
 | 
						|
			} );
 | 
						|
 | 
						|
			owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedVertexOptions = visible;
 | 
						|
			if( m_isBillboard != enabled )
 | 
						|
			{
 | 
						|
				UIUtils.RequestSave();
 | 
						|
			}
 | 
						|
		}
 | 
						|
		public void FillDataCollectorWithInternalData( ref MasterNodeDataCollector dataCollector )
 | 
						|
		{
 | 
						|
			if( m_isBillboard )
 | 
						|
			{
 | 
						|
				FillDataCollector( ref dataCollector, m_billboardType, m_rotationIndependent, "v.vertex", "v.normal", false );
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
 | 
						|
		// This should be called after the Vertex Offset and Vertex Normal ports are analised
 | 
						|
		public static void FillDataCollector( ref MasterNodeDataCollector dataCollector, BillboardType billboardType, bool rotationIndependent, string vertexPosValue, string vertexNormalValue, bool vertexIsFloat3 )
 | 
						|
		{
 | 
						|
			switch( billboardType )
 | 
						|
			{
 | 
						|
				case BillboardType.Cylindrical:
 | 
						|
				{
 | 
						|
					for( int i = 0; i < BillboardCylindricalInstructions.Length; i++ )
 | 
						|
					{
 | 
						|
						dataCollector.AddVertexInstruction( BillboardCylindricalInstructions[ i ] + ( dataCollector.IsTemplate ? ";" : string.Empty ), -1, true );
 | 
						|
					}
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
				case BillboardType.Spherical:
 | 
						|
				{
 | 
						|
					for( int i = 0; i < BillboardCylindricalInstructions.Length; i++ )
 | 
						|
					{
 | 
						|
						dataCollector.AddVertexInstruction( BillboardSphericalInstructions[ i ] + ( dataCollector.IsTemplate ? ";" : string.Empty ), -1, true );
 | 
						|
					}
 | 
						|
				}
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			for( int i = 0; i < BillboardCommonInstructions.Length; i++ )
 | 
						|
			{
 | 
						|
				string value = ( i == 3 ) ? string.Format( BillboardCommonInstructions[ i ], vertexNormalValue ) : BillboardCommonInstructions[ i ];
 | 
						|
				dataCollector.AddVertexInstruction( value + ( dataCollector.IsTemplate ? ";" : string.Empty ), -1, true );
 | 
						|
			}
 | 
						|
 | 
						|
			if( rotationIndependent )
 | 
						|
			{
 | 
						|
				for( int i = 0; i < BillboardRotIndependent.Length; i++ )
 | 
						|
				{
 | 
						|
					string value = string.Empty;
 | 
						|
					if( dataCollector.IsTemplate && dataCollector.TemplateDataCollectorInstance.CurrentSRPType != TemplateSRPType.BuiltIn )
 | 
						|
					{
 | 
						|
						value = ( i != 5 ) ? string.Format( BillboardHDRotIndependent[ i ], vertexPosValue ) : BillboardHDRotIndependent[ i ];
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						value = ( i != 5 ) ? string.Format( BillboardRotIndependent[ i ], vertexPosValue ) : BillboardRotIndependent[ i ];
 | 
						|
					}
 | 
						|
					dataCollector.AddVertexInstruction( value + ( dataCollector.IsTemplate ? ";" : string.Empty ), -1, true );
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				string vertexPosConverted = vertexIsFloat3 ? string.Format( "float4({0},0)", vertexPosValue ) : vertexPosValue;
 | 
						|
				for( int i = 0; i < BillboardRotDependent.Length; i++ )
 | 
						|
				{
 | 
						|
					string value = string.Empty;
 | 
						|
					if( dataCollector.IsTemplate && dataCollector.TemplateDataCollectorInstance.CurrentSRPType == TemplateSRPType.HD )
 | 
						|
					{
 | 
						|
						value = ( i > 1 ) ? string.Format( BillboardHDRotDependent[ i ], vertexPosValue, vertexPosConverted, ( vertexIsFloat3 ? ".xyz" : string.Empty ) ) : BillboardHDRotDependent[ i ];
 | 
						|
					}
 | 
						|
					else
 | 
						|
					{
 | 
						|
						value = ( i > 1 ) ? string.Format( BillboardRotDependent[ i ], vertexPosValue, vertexPosConverted, ( vertexIsFloat3 ? ".xyz" : string.Empty ) ) : BillboardRotDependent[ i ];
 | 
						|
					}
 | 
						|
					dataCollector.AddVertexInstruction( value + ( dataCollector.IsTemplate ? ";" : string.Empty ), -1, true );
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		public string[] GetInternalMultilineInstructions()
 | 
						|
		{
 | 
						|
			// This method is only used on Surface ... no HD variation is needed
 | 
						|
			return GetMultilineInstructions( m_billboardType, m_rotationIndependent, "v.vertex", "v.normal" );
 | 
						|
		}
 | 
						|
 | 
						|
		public static string[] GetMultilineInstructions( BillboardType billboardType, bool rotationIndependent, string vertexPosValue, string vertexNormalValue )
 | 
						|
		{
 | 
						|
			// This method is only used on Surface ... no HD variation is needed
 | 
						|
			List<string> body = new List<string>();
 | 
						|
			switch( billboardType )
 | 
						|
			{
 | 
						|
				case BillboardType.Cylindrical:
 | 
						|
				{
 | 
						|
					for( int i = 0; i < BillboardCylindricalInstructions.Length; i++ )
 | 
						|
					{
 | 
						|
						body.Add( BillboardCylindricalInstructions[ i ] );
 | 
						|
					}
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
				case BillboardType.Spherical:
 | 
						|
				{
 | 
						|
					for( int i = 0; i < BillboardCylindricalInstructions.Length; i++ )
 | 
						|
					{
 | 
						|
						body.Add( BillboardSphericalInstructions[ i ] );
 | 
						|
					}
 | 
						|
				}
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
			for( int i = 0; i < BillboardCommonInstructions.Length; i++ )
 | 
						|
			{
 | 
						|
				string value = ( i == 3 ) ? string.Format( BillboardCommonInstructions[ i ], vertexNormalValue ) : BillboardCommonInstructions[ i ];
 | 
						|
				body.Add( value );
 | 
						|
			}
 | 
						|
 | 
						|
			if( rotationIndependent )
 | 
						|
			{
 | 
						|
				for( int i = 0; i < BillboardRotIndependent.Length; i++ )
 | 
						|
				{
 | 
						|
					string value = ( i != 5 ) ? string.Format( BillboardRotIndependent[ i ], vertexPosValue ) : BillboardRotIndependent[ i ];
 | 
						|
					body.Add( value );
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				for( int i = 0; i < BillboardRotDependent.Length; i++ )
 | 
						|
				{
 | 
						|
					string value = ( i > 1 ) ? string.Format( BillboardRotDependent[ i ], vertexPosValue ) : BillboardRotDependent[ i ];
 | 
						|
					body.Add( value );
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return body.ToArray();
 | 
						|
		}
 | 
						|
 | 
						|
		public void ReadFromString( ref uint index, ref string[] nodeParams )
 | 
						|
		{
 | 
						|
			m_isBillboard = Convert.ToBoolean( nodeParams[ index++ ] );
 | 
						|
			m_billboardType = (BillboardType)Enum.Parse( typeof( BillboardType ), nodeParams[ index++ ] );
 | 
						|
			if( UIUtils.CurrentShaderVersion() > 11007 )
 | 
						|
			{
 | 
						|
				m_rotationIndependent = Convert.ToBoolean( nodeParams[ index++ ] );
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		public void WriteToString( ref string nodeInfo )
 | 
						|
		{
 | 
						|
			IOUtils.AddFieldValueToString( ref nodeInfo, m_isBillboard );
 | 
						|
			IOUtils.AddFieldValueToString( ref nodeInfo, m_billboardType );
 | 
						|
			IOUtils.AddFieldValueToString( ref nodeInfo, m_rotationIndependent );
 | 
						|
		}
 | 
						|
 | 
						|
		public bool IsBillboard { get { return m_isBillboard; } }
 | 
						|
	}
 | 
						|
}
 |