我想基于十二面体创建一个行星的三维模型,并为每一侧提供不同的纹理,代表该区域的主要景观和其他内容。 (或者,一个分成12个五边形的地球仪会更好,但可能更复杂。)
作为一个游戏项目,我想在Unity3d中完成它,但任何方法(脚本或免费的3D图形工具)都会有所帮助。
我已经研究了柏拉图主体的几何形状,并试图找出如何绘制五边形,然后恰当地调整它们的角度,或者只是为此得到一个现成的解决方案,但到目前为止我还没有找到任何方法。
答案 0 :(得分:2)
经过一番摆弄后,我确实找到了答案:
第1步:在Blender中创建五角大楼
这实际上非常简单。创建一个圆并将顶点数减少到5.我实际上选择了尺寸为X = 1,Y = 1,Z = 0.1的圆柱体,但对于平面五边形,整体解决方案是相同的。
第2步:将其纳入Unity3d
Unity3d自然导入.blend文件,所以我把五角大楼保存为.blend文件并将其作为资产导入Unity3d。
第3步:将五角大楼放在棍子上。
为了轻松地围绕后十二面体的中心旋转五边形,我在Unity3d中创建了一个尺寸为X = 0.1,Y = 2,Z = 0.1的圆柱体。然后我把五角大楼 - 作为一个儿童对象 - 放在那个圆柱体的确切的末端(我的三维五边形变换Y = 9,75,如果使用扁平五边形,旋转X = 90,则为10)。五角大楼转过身来,我在另一端做了同样的事情。 (变换= -9,75并且旋转X = 90,Z = 180)同时进行两个半部分。
第3步:使用旋转和缩放
所以现在我可以通过X = 63.435(十二面体的两边之间的角度)复制和旋转圆柱体(连接五角大楼)并且Y = 180(因此边缘彼此面对)以使其进入正确的位置。现在我必须找到正确的五角形缩放以缩小差距,恰好在15.275接近。用相应的角度重复五次(y = 180 +/- 72的倍数,五边形两边的角度)。
完成。强>
答案 1 :(得分:0)
首先创建一些数学助手:
using System;
using UnityEngine;
public static class MathUtils
{
public static Vector3 MultiplyMatrixAndVector(float[,] m, Vector3 v)
{
return new Vector3(
v.x * m[0, 0] + v.y * m[0, 1] + v.z * m[0, 2],
v.x * m[1, 0] + v.y * m[1, 1] + v.z * m[1, 2],
v.x * m[2, 0] + v.y * m[2, 1] + v.z * m[2, 2]
);
}
public static Vector3 RotateVectorAroundAxis(Vector3 vector, Vector3 a, Vector3 b, double angle)
{
var normalizedAxis = (b - a).normalized;
var x = normalizedAxis.x;
var y = normalizedAxis.y;
var z = normalizedAxis.z;
var translationVector = ProjectPointOnAxis(vector, a, b);
var c = (float) Math.Cos(angle);
var s = (float) Math.Sin(angle);
var rotationMatrix = new float[3, 3];
rotationMatrix[0, 0] = c + x * x * (1 - c);
rotationMatrix[0, 1] = x * y * (1 - c) - z * s;
rotationMatrix[0, 2] = x * z * (1 - c) + y * s;
rotationMatrix[1, 0] = y * x * (1 - c) + z * s;
rotationMatrix[1, 1] = c + y * y * (1 - c);
rotationMatrix[1, 2] = y * z * (1 - c) - x * s;
rotationMatrix[2, 0] = z * x * (1 - c) - y * s;
rotationMatrix[2, 1] = z * y * (1 - c) + x * s;
rotationMatrix[2, 2] = c + z * z * (1 - c);
return MultiplyMatrixAndVector(rotationMatrix, vector - translationVector) + translationVector;
}
public static Vector3 ProjectPointOnAxis(Vector3 vector, Vector3 a, Vector3 b)
{
var ba = b - a;
var lambda = Vector3.Dot(ba, vector - a) / Vector3.Dot(ba, ba);
return a + lambda * ba;
}
}
然后创建一个多面体管理器:
using System;
using System.Collections.Generic;
using UnityEngine;
public static class PolyhedronManager
{
public static GameObject CreatePolyhedron(string name)
{
var material = Resources.Load("Materials/Cube") as Material;
var gameObject = new GameObject();
Mesh mesh;
switch (name)
{
case "hexahedron":
{
mesh = CreatePolyhedronMesh(4, Math.PI / 2);
break;
}
case "tetrahedron":
{
mesh = CreatePolyhedronMesh(3, Math.Acos(1d / 3));
break;
}
case "octahedron":
{
mesh = CreatePolyhedronMesh(3, Math.Acos(-1d / 3));
break;
}
case "icosahedron":
{
mesh = CreatePolyhedronMesh(3, Math.Acos(-Math.Sqrt(5) / 3));
break;
}
case "dodecahedron":
{
mesh = CreatePolyhedronMesh(5, 2 * Math.Atan2(1 + Math.Sqrt(5), 2));
break;
}
default:
{
throw new Exception("Invalid polyhedron name");
}
}
mesh.RecalculateNormals();
gameObject.AddComponent<MeshRenderer>().material = material;
gameObject.AddComponent<MeshFilter>().mesh = mesh;
gameObject.name = char.ToUpper(name[0]) + name.Substring(1);
gameObject.transform.rotation = Quaternion.Euler(180, 0, 0);
return gameObject;
}
private static List<Vector3> CreatePolygonVertices(int nSides, Vector3 origin, Vector3 normal, Vector3 firstNode, bool shouldUseFirstNode)
{
var angle = 2 * Math.PI / nSides;
var distanceFromCenter = (float) Math.Sqrt(0.5 / (1 - Math.Cos(angle)));
var actualFirstNode = shouldUseFirstNode ? firstNode : origin + distanceFromCenter * Vector3.right;
var vertices = new List<Vector3> {actualFirstNode};
for (var i = 1; i < nSides; i++)
{
vertices.Add(MathUtils.RotateVectorAroundAxis(vertices[i - 1], origin, origin + normal, angle));
}
return vertices;
}
private static Mesh CreatePolyhedronMesh(int nSides, double dihedralAngle)
{
var supplementaryAngle = Math.PI - dihedralAngle;
var origin = Vector3.zero;
var faces = new List<List<Vector3>> {CreatePolygonVertices(nSides, origin, Vector3.up, origin, false)};
var centers = new List<Vector3> {origin};
var facesQueue = new List<List<Vector3>> {faces[0]};
var centersQueue = new List<Vector3> {centers[0]};
while (true)
{
if (facesQueue.Count == 0)
{
break;
}
var face = facesQueue[0];
var center = centersQueue[0];
facesQueue.RemoveAt(0);
centersQueue.RemoveAt(0);
for (var i = 0; i < nSides; i++)
{
var a = face[i];
var b = face[i == nSides - 1 ? 0 : i + 1];
var dihedralAxis = b - a;
var pivot = (b + a) / 2;
var p = pivot - center;
var nextCenter = pivot + p;
var rotatedCenter = MathUtils.RotateVectorAroundAxis(nextCenter, a, b, supplementaryAngle);
var centerAlreadyExists = false;
centers.ForEach(existingCenter =>
{
if ((rotatedCenter - existingCenter).sqrMagnitude < 0.01)
{
centerAlreadyExists = true;
}
});
if (centerAlreadyExists)
{
continue;
}
var normal = Vector3.Cross(p, dihedralAxis);
var nextFace = CreatePolygonVertices(nSides, nextCenter, normal, a, true)
.ConvertAll(new Converter<Vector3, Vector3>(vertex => MathUtils.RotateVectorAroundAxis(vertex, a, b, supplementaryAngle)));
faces.Add(nextFace);
centers.Add(rotatedCenter);
facesQueue.Add(nextFace);
centersQueue.Add(rotatedCenter);
}
}
var vertices = new List<Vector3>();
var triangles = new List<int>();
var c = -1;
for (var i = 0; i < faces.Count; i++)
{
var face = faces[i];
var center = centers[i];
c++;
vertices.Add(center);
var centerVertexIndex = c;
for (var j = 0; j < face.Count; j++)
{
var vertex = face[j];
c++;
vertices.Add(vertex);
triangles.Add(centerVertexIndex);
triangles.Add(c);
triangles.Add(j == face.Count - 1 ? centerVertexIndex + 1 : c + 1);
}
}
return new Mesh
{
vertices = vertices.ToArray(),
triangles = triangles.ToArray()
};
}
}
然后像下面这样调用您的多管管理器:
var polyhedronGameObject = PolyhedronManager.CreatePolyhedron("dodecahedron");
此脚本根据多边形边上的数字和多面体的二面角生成顶点和三角形。为此,它使用“呼吸优先”搜索策略在脸上构造多面体。
希望这会有所帮助。