Вращение кубов лицом к исходной точке с помощью кватернионов - PullRequest
0 голосов
/ 29 мая 2020

Я в процессе настройки относительно простого мира на основе вокселей для игры. Идея высокого уровня состоит в том, чтобы сначала сгенерировать местоположения вокселей в соответствии с сеткой Фибоначчи, затем повернуть кубы так, чтобы внешняя поверхность сетки Фибоначчи напоминала сферу, и, наконец, размер кубов так, чтобы они примерно покрывали поверхность сферы (перекрытие - это хорошо). См. Ниже код для генерации вокселей по сетке Фибоначчи:

    public static Voxel[] CreateInitialVoxels(int numberOfPoints, int radius)
    {
        float goldenRatio = (1 + Mathf.Sqrt(5)) / 2;
        Voxel[] voxels = new Voxel[numberOfPoints];
        for (int i = 0; i < numberOfPoints; i++)
        {
            float n = i - numberOfPoints / 2;  // Center at zero
            float theta = 2 * Mathf.PI * n / goldenRatio;
            float phi = (Mathf.PI / 2) + Mathf.Asin(2 * n / numberOfPoints);
            voxels[i] = new Voxel(new Location(theta, phi, radius));
        }
        return voxels;
    }

Это создает сферу, которая выглядит примерно как лестница

enter image description here

Итак, мой текущий подход к тому, чтобы это выглядело немного более сферически, заключается в том, чтобы в основном вращать каждый куб в каждой паре осей, а затем объединять все вращения:

private void DrawVoxel(Voxel voxel, GameObject voxelContainer)
{
    GameObject voxelObject = Instantiate<GameObject>(GetVoxelPrefab());

    voxelObject.transform.position = voxel.location.cartesianCoordinates;
    voxelObject.transform.parent = voxelContainer.transform;

    Vector3 norm = voxel.location.cartesianCoordinates.normalized;

    float xyRotationDegree = Mathf.Atan(norm.y / norm.x) * (180 / Mathf.PI);
    float zxRotationDegree = Mathf.Atan(norm.z / norm.x) * (180 / Mathf.PI);
    float yzRotationDegree = Mathf.Atan(norm.z / norm.y) * (180 / Mathf.PI);

    Quaternion xyRotation = Quaternion.AngleAxis(xyRotationDegree, new Vector3(0, 0, 1));
    Quaternion zxRotation = Quaternion.AngleAxis(zxRotationDegree, new Vector3(0, 1, 0));
    Quaternion yzRotation = Quaternion.AngleAxis(yzRotationDegree, new Vector3(1, 0, 0));

    voxelObject.transform.rotation = zxRotation * yzRotation * xyRotation;
}

Главное, что я Я понимаю, что каждое из этих вращений, кажется, отлично работает для меня по отдельности, но при их объединении все имеет тенденцию go немного сбиться с пути (изображения ниже). Я не совсем уверен, в чем проблема. Я предполагаю, что я сделал некоторые несоответствия знака / поворота в моих поворотах, поэтому они не сочетаются правильно. Я могу заставить работать два, но никогда все три вместе.

Success in One Axis View From third axis when two rotations have been successfully applied Standard Failure Mode when attempting to combine third rotation

Выше приведены изображения одного и двух успешных вращений, за которыми следует режим ошибки, когда я пытаюсь их объединить. Любая помощь в том, чтобы сказать мне, что подход, которому я следую, слишком запутанный, или помочь мне понять, как правильно комбинировать эти вращения, была бы очень полезна. Преобразование декартовых координат ниже для справки.

[System.Serializable]
public struct Location
{
    public float theta, phi, r;
    public Vector3 polarCoordinates;

    public float x, y, z;
    public Vector3 cartesianCoordinates;

    public Location(float theta, float phi, float r)
    {
        this.theta = theta;
        this.phi = phi;
        this.r= r;
        this.polarCoordinates = new Vector3(theta, phi, r);

        this.x = r * Mathf.Sin(phi) * Mathf.Cos(theta);
        this.y = r * Mathf.Sin(phi) * Mathf.Sin(theta);
        this.z = r * Mathf.Cos(phi);
        this.cartesianCoordinates = new Vector3(x, y, z);
    }
}

1 Ответ

0 голосов
/ 29 мая 2020

Мне удалось найти решение этой проблемы, хотя мне все еще непонятно, в чем проблема с приведенным выше кодом.

В Unity есть очень удобная функция под названием Quaternion.FromToRotation, которая генерирует соответствующие вращение, если вы просто передаете соответствующий вектор назначения.

В моем случае я мог просто сделать: voxelObject.transform.rotation = Quaternion.FromToRotation(new Vector3(0, 0, 1), voxel.location.cartesianCoordinates);

...