Open yosun opened 2 years ago
May I learn more about your runtime use-case?
Runtime imported models may need pivots corrected at runtime
So just a method to call it at runtime
On Tue, Jan 18, 2022 at 4:49 AM Süleyman Yasir KULA < @.***> wrote:
May I learn more about your runtime use-case?
— Reply to this email directly, view it on GitHub https://github.com/yasirkula/UnityAdjustPivot/issues/2#issuecomment-1015379240, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAG57PXLIQK7PNIHO3AUX73UWVOWJANCNFSM5MHBAW4A . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you authored the thread.Message ID: @.***>
-- Yosun Chang, Founder and CTO
Permute.xyz | AIMagical.com
Phone: (415) 779 6786 WWW: AReality3D.com Twitter: @yosun
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 );
}
}
Hi! Can you add runtime support?