Вращение Snapped GO не работает должным образом - PullRequest
0 голосов
/ 07 декабря 2018

Я сейчас пытаюсь привязать объекты (кубы, пирамиды, тора) вместе.Я назначил каждой грани ограничивающего прямоугольника объекты переменную «привязка разрешена» и при столкновении пытаюсь найти две ближайшие стороны друг к другу.Затем я перемещаю основной объект в сторону столкновения и поворачиваю его соответствующим образом.

Код выглядит следующим образом:

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 () перемещает объекты в нужное положение и поворачивает их в соответствии с выбранными нормалями лица.Пока все хорошо, но результат не выровнен .Как вы можете видеть, передние грани не обращены в одном направлении, т.е. я хочу повернуть верхний куб вокруг оси transform.up на эту величину. Этот будет желаемым результатом.

Но, если я добавлю

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 голосов
/ 10 декабря 2018

Я разобрался в своей проблеме.Устанавливая transform.forward и transform.up отдельно (например, с transform.rotate вокруг оси), только один из них был правильным.Использование Quaternion.LookRotation () решает эту проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...