Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime support #2

Open
yosun opened this issue Jan 18, 2022 · 3 comments
Open

Runtime support #2

yosun opened this issue Jan 18, 2022 · 3 comments
Labels

Comments

@yosun
Copy link

yosun commented Jan 18, 2022

Hi! Can you add runtime support?

@yosun yosun added the bug label Jan 18, 2022
@yasirkula
Copy link
Owner

May I learn more about your runtime use-case?

@yosun
Copy link
Author

yosun commented Jan 18, 2022 via email

@yasirkula
Copy link
Owner

I've decided not to add this feature to the plugin at the moment. However, I've created the following class which you may find useful:

NOTE: CopyComponent needs to be implemented if createColliderObjectOnPivotChange or createNavMeshObstacleObjectOnPivotChange is set to true. It was originally handled via EditorUtility.CopySerialized.

using UnityEngine;
using UnityEngine.SceneManagement;
#if UNITY_5_5_OR_NEWER
using UnityEngine.AI;
#endif

public static class AdjustPivotRuntime
{
	private const string GENERATED_COLLIDER_NAME = "__GeneratedCollider";
	private const string GENERATED_NAVMESH_OBSTACLE_NAME = "__GeneratedNavMeshObstacle";
	private const string GENERATED_EMPTY_PARENT_NAME = "__GeneratedParent";

	public static void ModifyPivot( Transform transform, Vector3 pivotLocalPosition, Vector3 pivotLocalEulerAngles, bool createColliderObjectOnPivotChange = false, bool createNavMeshObstacleObjectOnPivotChange = false )
	{
		if( pivotLocalPosition == Vector3.zero && pivotLocalEulerAngles == Vector3.zero )
		{
			Debug.LogWarning( "Pivot hasn't changed!" );
			return;
		}

		if( pivotLocalEulerAngles != Vector3.zero )
		{
			Vector3 parentScale = transform.localScale;
			if( !Mathf.Approximately( parentScale.x, parentScale.y ) || !Mathf.Approximately( parentScale.x, parentScale.z ) )
			{
				// This is an edge case (object has non-uniform scale and pivot is rotated). We must create an empty parent GameObject in this scenario
				GameObject emptyParentObject = new GameObject( GENERATED_EMPTY_PARENT_NAME );
				if( !IsNull( transform.parent ) )
					emptyParentObject.transform.SetParent( transform.parent, false );
				else
					SceneManager.MoveGameObjectToScene( emptyParentObject, transform.gameObject.scene );

				emptyParentObject.transform.localPosition = transform.localPosition;
				emptyParentObject.transform.localRotation = transform.localRotation;
				emptyParentObject.transform.localScale = transform.localScale;

				transform.SetParent( emptyParentObject.transform );
			}
		}

		MeshFilter meshFilter = transform.GetComponent<MeshFilter>();
		Mesh originalMesh = null;
		if( !IsNull( meshFilter ) && !IsNull( meshFilter.sharedMesh ) )
		{
			originalMesh = meshFilter.sharedMesh;
			Mesh mesh = Object.Instantiate( meshFilter.sharedMesh );
			meshFilter.sharedMesh = mesh;

			Vector3[] vertices = mesh.vertices;
			Vector3[] normals = mesh.normals;
			Vector4[] tangents = mesh.tangents;

			if( pivotLocalPosition != Vector3.zero )
			{
				Vector3 deltaPosition = -pivotLocalPosition;
				for( int i = 0; i < vertices.Length; i++ )
					vertices[i] += deltaPosition;
			}

			if( pivotLocalEulerAngles != Vector3.zero )
			{
				Quaternion deltaRotation = Quaternion.Inverse( Quaternion.Euler( pivotLocalEulerAngles ) );
				for( int i = 0; i < vertices.Length; i++ )
				{
					vertices[i] = deltaRotation * vertices[i];
					normals[i] = deltaRotation * normals[i];

					Vector3 tangentDir = deltaRotation * tangents[i];
					tangents[i] = new Vector4( tangentDir.x, tangentDir.y, tangentDir.z, tangents[i].w );
				}
			}

			mesh.vertices = vertices;
			mesh.normals = normals;
			mesh.tangents = tangents;

			mesh.RecalculateBounds();
		}

		Collider[] colliders = transform.GetComponents<Collider>();
		foreach( Collider collider in colliders )
		{
			MeshCollider meshCollider = collider as MeshCollider;
			if( !IsNull( meshCollider ) && !IsNull( originalMesh ) && meshCollider.sharedMesh == originalMesh )
				meshCollider.sharedMesh = meshFilter.sharedMesh;
		}

		if( createColliderObjectOnPivotChange && IsNull( transform.Find( GENERATED_COLLIDER_NAME ) ) )
		{
			GameObject colliderObj = null;
			foreach( Collider collider in colliders )
			{
				if( IsNull( collider ) )
					continue;

				MeshCollider meshCollider = collider as MeshCollider;
				if( IsNull( meshCollider ) || meshCollider.sharedMesh != meshFilter.sharedMesh )
				{
					if( colliderObj == null )
					{
						colliderObj = new GameObject( GENERATED_COLLIDER_NAME );
						colliderObj.transform.SetParent( transform, false );
					}

					CopyComponent( collider, colliderObj.AddComponent( collider.GetType() ) );
				}
			}
		}

		if( createNavMeshObstacleObjectOnPivotChange && IsNull( transform.Find( GENERATED_NAVMESH_OBSTACLE_NAME ) ) )
		{
			NavMeshObstacle obstacle = transform.GetComponent<NavMeshObstacle>();
			if( !IsNull( obstacle ) )
			{
				GameObject obstacleObj = new GameObject( GENERATED_NAVMESH_OBSTACLE_NAME );
				obstacleObj.transform.SetParent( transform, false );
				CopyComponent( obstacle, obstacleObj.AddComponent( obstacle.GetType() ) );
			}
		}

		Transform[] children = new Transform[transform.childCount];
		Vector3[] childrenPositions = new Vector3[children.Length];
		Quaternion[] childrenRotations = new Quaternion[children.Length];
		for( int i = children.Length - 1; i >= 0; i-- )
		{
			children[i] = transform.GetChild( i );
			childrenPositions[i] = children[i].position;
			childrenRotations[i] = children[i].rotation;
		}

		transform.position = transform.TransformPoint( pivotLocalPosition );
		transform.rotation = transform.rotation * Quaternion.Euler( pivotLocalEulerAngles );

		for( int i = 0; i < children.Length; i++ )
		{
			children[i].position = childrenPositions[i];
			children[i].rotation = childrenRotations[i];
		}
	}

	private static void CopyComponent<T>( T from, T to ) where T : Component
	{
		throw new System.NotImplementedException();
	}

	private static bool IsNull( Object obj )
	{
		return obj == null || obj.Equals( null );
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants