我正在为一款游戏建立一个相对简单的基于voxel的世界。高层次的想法是,首先按照斐波那契网格生成体素位置,然后旋转立方体,使斐波那契网格的外表面像一个球体,最后确定立方体的大小,使它们大致覆盖球体的表面(重叠即可)。请看下面沿斐波那契网格生成伏笔的代码。
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;
}
这将生成一个看起来像楼梯的球体。
所以,我目前的方法是让这个看起来更球形一些,基本上是在每一对轴上旋转每个立方体,然后组合所有的旋转。
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;
}
最主要的是,我发现这些旋转中的每一个似乎都能单独工作,但当把它们结合起来时,事情就会变得有点混乱(如下图),我不确定到底是什么问题。我最好的猜测是,我在我的旋转中做了一些符号旋转的不匹配,所以他们没有正确的结合。我可以让两个工作,但从来没有三个一起。
上面是一个和两个成功旋转的图片,然后是当我试图结合它们时的错误模式。任何帮助,无论是告诉我我所遵循的方法太过曲折,还是帮助我理解什么是正确的组合这些旋转的方法,都将是非常有用的。下面是笛卡尔坐标转换,供参考。
[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);
}
}
我设法找到了解决这个问题的方法,不过我还是不清楚上述代码的问题在哪里。
Unity有一个非常方便的函数,叫做 Quaternion.FromToRotation
只要输入适当的目标向量,就会产生适当的旋转。
在我的例子中,我可以只做。voxelObject.transform.rotation = Quaternion.FromToRotation(new Vector3(0, 0, 1), voxel.location.cartesianCoordinates);