如何在Unity3D

时间:2019-01-25 18:01:59

标签: c# unity3d matrix transform

对于Unity3D中的项目,我试图通过更改框架来转换世界上的所有对象。这意味着旋转,平移和缩放新框架的原点以匹配旧框架的原点,然后将此操作应用于所有其他对象(包括旧的原点)。 为此,我需要一个广义的3维(因此为4x4)转换矩阵。

我已经看过使用Unity内置的Matrix4x4.TRS()方法,但这似乎没有用,因为它仅将平移,旋转和缩放应用于定义的点。 我要寻找的是更改框架,其中新框架相对于原始框架具有不同的原点,旋转和比例。

为显示问题,我制作了一个小的GIF(我目前有3D的工作版本,没有使用Matrix,也没有任何旋转): https://gyazo.com/8a7ab04dfef2c96f53015084eefbdb01

每个球体的值:

Origin1 (Red Sphere)

Before:   
Position (-10, 0, 0)
Rotation (0,0,0)
Scale    (4,4,4)   

After:
Position (10, 0, 0)
Rotation (0,0,0)
Scale    (8,8,8)   

-
Origin2 (Blue Sphere)

Before:   
Position (-20, 0, 0)
Rotation (0,0,0)
Scale    (2,2,2)   

After:
Position (-10, 0, 0)
Rotation (0,0,0)
Scale    (4,4,4)   

-
World-Object (White Sphere)

Before:   
Position (0, 0, 10)
Rotation (0,0,0)
Scale    (2,2,2)   

After:
Position (30, 0, 20)
Rotation (0,0,0)
Scale    (4,4,4)  

当前,我只是简单地将两个原点之间的Vector取下,将其缩放为两个原点之间的差,然后将其应用到原始(第一个)原点的新位置之上。 当将旋转应用于两个原点中的任何一个时,这当然是行不通的。

// Position in original axes
Vector3 positionBefore = testPosition.TestPosition - origin.TestPosition;
// Position in new axes
Vector3 positionAfter = (positionBefore * scaleFactor) + origin.transform.position;

我正在寻找的是一个可以做到这一点的矩阵(包括旋转,这样Origin2旋转到了转换之前Origin1的旋转,所有其他对象都移到了正确的位置)。

有没有一种方法可以在不对每个Vector进行完全计算的情况下进行此操作(即,变换Vector之前的位置)?它需要每帧应用于(非常)大量的对象,因此需要(相当)优化。

编辑:缩放比例总是一致的。

2 个答案:

答案 0 :(得分:0)

也许还有其他解决方案,但这就是我要做的

  1. 将您的对象包装到以下层次结构中

    WorldAnchorObject
    |- Red Sphere
    |- Blue Sphere
    |- White Sphere
    
  2. 确保WorldAnchorObject拥有

    position: 0,0,0
    rotation: 0,0,0
    localScale: 1,1,1
    
  3. 定位/旋转/缩放球体(相对于WorldAnchorObject现在会发生)

  4. 现在剩下的就是对WorldAnchorObject->进行变形,它将移动,缩放和旋转其他任何东西,并保持相对转换不变。

    您如何精确地移动世界锚点。我想您想一直居中并规范化某些子对象。也许像

    public void CenterOnObject(GameObject targetCenter)
    {
        var targetTransform = targetCenter.transform;
        // The localPosition and localRotation are relative to the parent
        var targetPos = transform.localPosition;
        var targetRot = targetTransform.localRotation;
        var targetScale = targetTransform.localScale;
    
        // First reset everything
        transform.position = Vector3.zero;
        transform.rotation = Quaternion.Idendity;
        transform.localScale = Vector3.one;
    
        // set yourself to inverted target position
        // After this action the target should be on 0,0,0
        transform.position = targetPos * -1;
        // Scale yourself relative to 0,0,0
        var newScale = Vector3.one * 1/targetScale.x;
        ScaleAround(gameObject, Vector3.zero, newScale);
        // Now everything should be scaled so that the target 
        // has scale 1,1,1 and still is on position 0,0,0
    
        // Now rotate around 0,0,0 so that the rotation of the target gets normalized
        transform.rotation = Quaternion.Inverse(targetRotation);
    }
    
    // This scales an object around a certain pivot and 
    // takes care of the correct position translation as well
    private void ScaleAround(GameObject target, Vector3 pivot, Vector3 newScale)
    {
        Vector3 A = target.transform.localPosition;
        Vector3 B = pivot;
    
        Vector3 C = A - B; // diff from object pivot to desired pivot/origin
    
        float RS = newScale.x / target.transform.localScale.x; // relative scale factor
    
        // calc final position post-scale
        Vector3 FP = B + C * RS;
    
        // finally, actually perform the scale/translation
        target.transform.localScale = newScale;
        target.transform.localPosition = FP;
    }
    

    现在,您称它为传递一个孩子,例如,

    worldAnchorReference.CenterOnObject(RedSphere);
    

    应该会导致您想要实现的目标。 (在智能手机上安装了此工具,因此没有任何保证,但是如果遇到问题,我可以在再次使用PC时立即对其进行检查。))

答案 1 :(得分:0)

没关系。 在创建TRS之前必须将旋转和缩放应用于平移 D'Oh