快照GO的旋转无法正常工作

时间:2018-12-07 11:33:31

标签: unity3d rotation snapping

我目前正在尝试将对象(立方体,金字塔,圆环)对齐在一起。我为对象边界框的每个面分配了“允许捕捉”变量,并在发生碰撞时尝试找到彼此最接近的两侧。然后,我将主要对象移到碰撞侧并相应地旋转它。

代码如下:

private static Vector3[] sides = {
    Vector3.up,
    Vector3.forward,
    Vector3.right,
    Vector3.down,
    Vector3.back,
    Vector3.left
};

private void Snap() {
    if (!snappedObject)
        return;

    if (lastSnapping > LeftController.GetLastSnappingToggle()) {
        //we dont calculate new sides, only use the old ones
        //but we have to check whether we are now further away 
        float dis = Vector3.Distance(GetWorldPositionFace(this.gameObject, lastSelf),
                                     GetWorldPositionFace(snappedObject, lastOther));
        float max = Mathf.Max(Mathf.Abs(size.x), Mathf.Max(Mathf.Abs(size.y), Mathf.Abs(size.z)));
        if (dis > max)
            return;

        ApplyToOther(lastSelf, lastOther, snappedObject);
    } else {
        //we need to find both new closest sides
        MeshSnapping other = snappedObject.GetComponent<MeshSnapping>();
        float otherDis = float.MaxValue;
        int otherSide = -1;
        //find the closest side from the other object
        for (int i = 0; i < NUM_SIDES; i++) {
            float dis = Vector3.Distance(transform.position, GetWorldPositionFace(snappedObject, i));
            if (dis < otherDis && other.sidesAllowed[i]) {
                otherDis = dis;
                otherSide = i;
            }
        }

        //find the closest side of our object
        float selfDis = float.MaxValue;
        int selfSide = 0;
        for (int i = 0; i < NUM_SIDES; i++) {
            float dis = Vector3.Distance(GetWorldPositionFace(this.gameObject, i),
                                            GetWorldPositionFace(snappedObject, otherSide));
            if (dis < selfDis && sidesAllowed[i]) {
                selfDis = dis;
                selfSide = i;
            }
        }


        //are we to far away or at a prohibited side?
        float max = Mathf.Max(Mathf.Abs(size.x), Mathf.Max(Mathf.Abs(size.y), Mathf.Abs(size.z)));
        if (selfDis > max)
            return;

        ApplyToOther(selfSide, otherSide, snappedObject);
        //save the sides for next iteration
        lastSelf = selfSide;
        lastOther = otherSide;
    }

    lastSnapping = Time.time;
}


private void OnCollisionEnter(Collision collision) {
    snappedObject = collision.gameObject;
}

private void OnCollisionExit(Collision collision) {
    snappedObject = null;
}

private Vector3 GetWorldPositionFace(GameObject other, int i) {
    //get the side in local coordinates, scaled to size
    Vector3 otherLocalSize = other.transform.localScale;
    Vector3 otherSidePoint = new Vector3(otherLocalSize.x * sides[i].x, otherLocalSize.y * sides[i].y, otherLocalSize.z * sides[i].z) / 2f;
    //rotate it according to world position
    Vector3 dir = (other.transform.rotation * otherSidePoint);
    //actually move it to world position
    Vector3 center = other.transform.position + dir;
    return center;
}


private void ApplyToOther(int selfI, int otherI, GameObject other) {
    //first get the midpoint of face of other go
    Vector3 edge = GetWorldPositionFace(other, otherI);
    Vector3 dir = edge - other.transform.position;

    RotateSides(selfI, otherI, dir);

    selfI = (selfI + NUM_SIDES / 2) % NUM_SIDES;

    //get midpoint of face of self go
    edge += GetWorldPositionFace(this.gameObject, selfI) - transform.position;
    //now move towards the combination
    transform.position = edge;
}

private void RotateSides(int selfI, int otherI, Vector3 dir) {
    //rotate self side towards this point
    switch (selfI) {
        case 0: transform.up = -dir; break;
        case 1: transform.forward = -dir; break;
        case 2: transform.right = -dir; break;
        case 3: transform.up = dir; break;
        case 4: transform.forward = dir; break;
        case 5: transform.right = dir; break;
    }

}

我可以通过变换方向向量,将对象当前的旋转和位置应用于边界向量来找到边界框的每个中点(请参阅GetWorldPositionFace())。找到最佳组合后,ApplyToOther()将对象移动到位置并根据选定的脸部法线对其进行旋转。到目前为止一切顺利,但结果是not aligned。如您所见,前表面朝向的方向不同,即我想使上立方体绕着transform.up轴旋转此量。 This将是我想要的结果。

但是,如果我添加

float angle = Vector3.Angle(transform.forward, snappedObject.transform.forward);
transform.Rotate(transform.up, angle);

到RotateSides()函数,结果为this。旋转轴错误。

使用

Quaternion.FromToRotation(transform.up, snappedObject.transform.up)

也不起作用。

我想念什么?感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

我发现了我的问题。通过分别设置transform.forward和transform.up(例如,将transform.rotate绕轴旋转),只有其中之一是正确的。使用Quaternion.LookRotation()可以解决这个问题。