Unity3d 如何构造十二面体及其边的纹理

Unity3d 如何构造十二面体及其边的纹理,unity3d,3d,polygons,Unity3d,3d,Polygons,我想创建一个基于十二面体的行星三维模型,给每一面不同的纹理,代表该区域的主要景观和其他内容。(或者,将地球分成12个五边形会更好,但可能更复杂。) 由于这是一个游戏项目,我想在Unity3d中完成,但任何方法(脚本或免费的3d图形工具)都会有所帮助 我已经研究了柏拉图式物体的几何学,并试图找出如何画五边形,然后将它们适当地倾斜,或者只是找到一个现成的解决方案,但到目前为止,我还没有找到任何方法。经过进一步的摸索,我确实找到了一个答案: 步骤1:在搅拌机中创建五角大楼 这其实非常简单。创建一个圆并

我想创建一个基于十二面体的行星三维模型,给每一面不同的纹理,代表该区域的主要景观和其他内容。(或者,将地球分成12个五边形会更好,但可能更复杂。)

由于这是一个游戏项目,我想在Unity3d中完成,但任何方法(脚本或免费的3d图形工具)都会有所帮助


我已经研究了柏拉图式物体的几何学,并试图找出如何画五边形,然后将它们适当地倾斜,或者只是找到一个现成的解决方案,但到目前为止,我还没有找到任何方法。

经过进一步的摸索,我确实找到了一个答案:

步骤1:在搅拌机中创建五角大楼

这其实非常简单。创建一个圆并将顶点数减少到5。实际上,我使用了一个尺寸为X=1,Y=1,Z=0.1的圆柱体,但是对于一个扁平的五边形,整体解决方案是相同的

第二步:进入Unity3d

Unity3d自然导入.blend文件,所以我只是将五角大楼保存为.blend文件,并将其作为资源导入Unity3d

步骤3:将五角大楼放在一根棍子上。

为了方便地围绕后面的十二面体的中心旋转五边形,我在Unity3d中创建了一个尺寸为X=0.1、Y=2、Z=0.1的圆柱体。然后我将五角大楼作为子对象放在圆柱体的精确末端(对于我的3d五角大楼,变换Y=9,75,如果使用平面五角大楼,则为10,旋转X=90)。我在另一端也做了同样的事情,五角大楼掉头了。(变换=-9,75并旋转X=90,Z=180)以同时进行两个半部分

第3步:旋转和缩放

现在我可以复制并旋转圆柱体(带有附加的五边形)X=63.435(十二面体侧面之间的角度)和Y=180(使边彼此面对),以使其处于正确的位置。现在,我必须找到五边形的正确比例来缩小这个差距,这个差距恰好接近15.275。用相应的角度重复五次(y=180+/-72的倍数,五边形两侧之间的角度)


完成。首先创建一些数学助手:

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()
        };
    }
}
该脚本基于多边形边上的数量和多面体的二面角生成顶点和三角形。为此,它使用呼吸优先搜索策略在面上构建多面体


希望这能有所帮助。

听起来你想要的是3D建模程序,而不是3D游戏引擎。看看Blender(免费)和这个关于的问题。柏拉图式的身体插件似乎已经不存在了,斜面解决方案已经超出了我微薄的Blender技能。。但你的回答为我指明了正确的方向。。。
var polyhedronGameObject = PolyhedronManager.CreatePolyhedron("dodecahedron");