使用十二面体画球体

 

当做一个地球的时候,可以使用六面体,八面体和20面体来画一个球体,它们的算法都是相同的,下面是20面体画球体的代码

欧拉定理(欧拉公式) V + F- E = 2 (简单多面体的顶点数 V,棱数 E 和面数 F).

1、这种方法的原理是:

  对每一个三角面进行一次

 public GameObject GetSphere(int subdivision = 5, float radius = 1.0f)
    {
        GameObject go = new GameObject ("Pentagon");
        MeshFilter filter = go.AddComponent<MeshFilter> ();
        
        Mesh mesh = new Mesh();
        filter.mesh = mesh;
        List<Vector3> vertices = new List<Vector3>()
        {
            new Vector3(0.000000f, -1.000000f, 0.000000f),
            new Vector3(0.723600f, -0.447215f, 0.525720f),
            new Vector3(-0.276385f, -0.447215f, 0.850640f),
            new Vector3(-0.894425f, -0.447215f, 0.000000f),
            new Vector3(-0.276385f, -0.447215f, -0.850640f),
            new Vector3(0.723600f, -0.447215f, -0.525720f),
            new Vector3(0.276385f, 0.447215f, 0.850640f),
            new Vector3(-0.723600f, 0.447215f, 0.525720f),
            new Vector3(-0.723600f, 0.447215f, -0.525720f),
            new Vector3(0.276385f, 0.447215f, -0.850640f),
            new Vector3(0.894425f, 0.447215f, 0.000000f),
            new Vector3(0.000000f, 1.000000f, 0.000000f),
        };
        int[] triangles =
        {
            0, 1, 2,
            1, 0, 5,
            0, 2, 3,
            0, 3, 4,
            0, 4, 5,
            1, 5, 10,
            2, 1, 6,
            3, 2, 7,
            4, 3, 8,
            5, 4, 9,
            1, 10, 6,
            2, 6, 7,
            3, 7, 8,
            4, 8, 9,
            5, 9, 10,
            6, 10, 11,
            7, 6, 11,
            8, 7, 11,
            9, 8, 11,
            10, 9, 11
        };

        for (int s = 0; s < subdivision; s++)
        {
            
            //这将存储连接中已经存在的所有顶点,因此不存在重复/重叠的顶点
            List<VertOnEdge> connected = new List<VertOnEdge>();

            //细分后的面数
            int[] newTriangles = new int[triangles.Length * 4];
            //遍历三角形面数
            for (int i = 0; i < triangles.Length / 3; i++)
            {
                //获取一个面的三个顶点
                int A = triangles[i * 3];
                int B = triangles[i * 3 + 1];
                int C = triangles[i * 3 + 2];

                int ab = -1;
                int bc = -1;
                int ca = -1;
                List<int> connectionToBeRemoved = new List<int>(); //需要删除的连接

                for (int j = 0; j < connected.Count; j++)
                {
                    VertOnEdge voe = connected[j];
                    if (voe.A == A)
                    {
                        if (voe.B == B)
                        {
                            ab = voe.vertIndex;
                            connectionToBeRemoved.Add(j);
                        }
                        else if (voe.B == C)
                        {
                            ca = voe.vertIndex;
                            connectionToBeRemoved.Add(j);
                        }
                    }
                    else if (voe.A == B)
                    {
                        //check if there is a connection between B and A or C
                        if (voe.B == A)
                        {
                            ab = voe.vertIndex;
                            connectionToBeRemoved.Add(j);
                        }
                        else if (voe.B == C)
                        {
                            bc = voe.vertIndex;
                            connectionToBeRemoved.Add(j);
                        }
                    }
                    else if (voe.A == C)
                    {
                        //check if there is a connection between C and A or B
                        if (voe.B == A)
                        {
                            ca = voe.vertIndex;
                            connectionToBeRemoved.Add(j);
                        }
                        else if (voe.B == B)
                        {
                            bc = voe.vertIndex;
                            connectionToBeRemoved.Add(j);
                        }
                    }
                }

                connectionToBeRemoved.Sort();
                connectionToBeRemoved.Reverse();
               
                for (int k = 0; k < connectionToBeRemoved.Count; k++)
                {
                    connected.RemoveAt(connectionToBeRemoved[k]);
                }
            

            //create new vertices and connections that don't exist
                if (ab == -1)
                {
                    vertices.Add((vertices[A] + vertices[B]) / 2);
                    ab = vertices.Count - 1;
                    connected.Add(new VertOnEdge(ab, A, B));
                }

                if (bc == -1)
                {
                    vertices.Add((vertices[B] + vertices[C]) / 2);
                    bc = vertices.Count - 1;
                    connected.Add(new VertOnEdge(bc, B, C));
                }

                if (ca == -1)
                {
                    vertices.Add((vertices[C] + vertices[A]) / 2);
                    ca = vertices.Count - 1;
                    connected.Add(new VertOnEdge(ca, C, A));
                }
                //4个三角形 12个顶点
                int triangleStartingIndex = i * 12;
                //在写入三角形的时候注意要顺时针写(opengl标准),逆时针写的时候面是反的
                newTriangles[triangleStartingIndex] = A;
                newTriangles[triangleStartingIndex + 1] = ab;
                newTriangles[triangleStartingIndex + 2] = ca;

                newTriangles[triangleStartingIndex + 3] = ab;
                newTriangles[triangleStartingIndex + 4] = B;
                newTriangles[triangleStartingIndex + 5] = bc;

                newTriangles[triangleStartingIndex + 6] = bc;
                newTriangles[triangleStartingIndex + 7] = C;
                newTriangles[triangleStartingIndex + 8] = ca;

                newTriangles[triangleStartingIndex + 9] = ab;
                newTriangles[triangleStartingIndex + 10] = bc;
                newTriangles[triangleStartingIndex + 11] = ca;
            }
            for (int i = 0; i < vertices.Count; i++)
            {
                vertices[i] = vertices[i].normalized;
            }
            triangles = null;
            triangles = newTriangles;
        }

        mesh.vertices = vertices.ToArray();
        mesh.triangles = triangles;
        mesh.RecalculateNormals();
        Material material = new Material (Shader.Find ("Diffuse"));
        material.SetColor ("_Color", Color.yellow);
 
        MeshRenderer renderer = go.AddComponent<MeshRenderer> ();
        renderer.sharedMaterial = material;

        return go;



    }

2、原理:

  先对AB和BC这两个面进行N次切分,然后按照顺序获取所有的切分后的顶点,相对于上面的算法优化了切分时的算法,比较推荐

 public GameObject GetSphere(int subdivision = 5)
    {
        GameObject go = new GameObject("Planet");

        MeshFilter filter = go.AddComponent<MeshFilter>();
        
        Mesh mesh = new Mesh();
        filter.mesh = mesh;
        
        List<Vector3> vertices = new List<Vector3>()
        {
            new Vector3(0.000000f, -1.000000f, 0.000000f),
            new Vector3(0.723600f, -0.447215f, 0.525720f),
            new Vector3(-0.276385f, -0.447215f, 0.850640f),
            new Vector3(-0.894425f, -0.447215f, 0.000000f),
            new Vector3(-0.276385f, -0.447215f, -0.850640f),
            new Vector3(0.723600f, -0.447215f, -0.525720f),
            new Vector3(0.276385f, 0.447215f, 0.850640f),
            new Vector3(-0.723600f, 0.447215f, 0.525720f),
            new Vector3(-0.723600f, 0.447215f, -0.525720f),
            new Vector3(0.276385f, 0.447215f, -0.850640f),
            new Vector3(0.894425f, 0.447215f, 0.000000f),
            new Vector3(0.000000f, 1.000000f, 0.000000f)
        };
        int[] triangles =
        {
            0, 1, 2,
            1, 0, 5,
            0, 2, 3,
            0, 3, 4,
            0, 4, 5,
            1, 5, 10,
            2, 1, 6,
            3, 2, 7,
            4, 3, 8,
            5, 4, 9,
            1, 10, 6,
            2, 6, 7,
            3, 7, 8,
            4, 8, 9,
            5, 9, 10,
            6, 10, 11,
            7, 6, 11,
            8, 7, 11,
            9, 8, 11,
            10, 9, 11
        };

          if (subdivision <= 0)
            {
                subdivision = 0;
            }
    
            int cut = (subdivision + 1);
    
            List<Vector3> newvertices  =  new List<Vector3>();
            List<int> trangles = new List<int>();
            
            Dictionary<Vector3,int> verticeidxs = new Dictionary<Vector3, int>();
            
            //对每个三角面进行遍历
            for (int i = 0; i < (triangles.Length/3); i++)
            {
                //获取三角面的顶点
                int index = i * 3;
                var a = vertices[triangles[index]];
                var b = vertices[triangles[index+1]];
                var c = vertices[triangles[index+2]];
                var ab = (b - a) / cut;//
                var ac = (c - a) / cut;
                
                List<int> newpsindex = new List<int>();
                //进行切分的次数
                for (int j = 0; j <= cut; j++)
                {
                    //切分后AB上的向量长度
                    var abcut = ab * j;
                    //
                    for (int k = 0; k <= (cut- j); k++)
                    {
                        //获取三角形上所有的顶点位置
                        var pos = a + (abcut + ac * k);
                        //新的顶点的个数
                        int newindex = newvertices.Count;
                        //如果顶点在三条边上
                        if (j == 0 || k == 0 || ((j + k) == cut))
                        {
                            //如果顶点字典中不存在该顶点
                            if (!verticeidxs.ContainsKey(pos))
                            {
                                //将该顶点添加到字典和新顶点列表中
                                newindex = newvertices.Count;
                                newvertices.Add(pos);  
                                verticeidxs.Add(pos,newindex);
                            }
                            else
                            {
                                //将字典中的该顶点的下标赋
                                newindex = verticeidxs[pos];
                            }
                        }
                        else
                        {
                            newindex = newvertices.Count;
                            newvertices.Add(pos);
                            verticeidxs.Add(pos,newindex);
                            
                        }
                        //添加新的顶点的下标
                        newpsindex.Add(newindex);
                    }
                }
    
                var s0 = 0;//下标最小数
                //组成三角面,对切分次数进行遍历,j代表第几行
                for (int j = 0; j < cut; j++)
                {
                    //下一行的第一个顶点的下标
                    var s1 = s0 + cut + 1 - j ;
                    //k代表第J行的第K个点
                    for (int k = 0; k < (cut - j); k++)
                    {
                        //添加每一行的正三角
                        trangles.Add(newpsindex[s0 + k]);
                        trangles.Add(newpsindex[s1 + k]);
                        trangles.Add(newpsindex[s0 + k + 1]);
                        //添加每一行的倒立的三角
                        if (j < cut - 1 && k<(cut - j - 1))
                        {
                            trangles.Add(newpsindex[s0 + k + 1]);
                            trangles.Add(newpsindex[s1 + k]);
                            trangles.Add(newpsindex[s1 + k + 1]);
                        }
                    }
                    s0 = s1;
                }
            }
            //将顶点归一化
            for (int i = 0; i < newvertices.Count; i++)
            {
                newvertices[i] = newvertices[i].normalized * 1;
            }
            
            vertices = newvertices;
            MeshRenderer renderer = go.AddComponent<MeshRenderer>();
            renderer.material.shader = Shader.Find("Diffuse");
            renderer.material.SetColor("_Color",Color.yellow);
            mesh.vertices = newvertices.ToArray();
            mesh.triangles = trangles.ToArray();
        

        return go;
    }

  

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 使用matplotlib可以通过绘制一系列垂直于x轴的线段来画出一个半球体。 首先,我们导入需要的库: ```python import matplotlib.pyplot as plt import numpy as np ``` 接下来,我们定义一个theta变量,表示在0到π之间的角度,以及一个phi变量,表示在0到2π之间的角度: ```python theta = np.linspace(0, np.pi, 100) phi = np.linspace(0, 2 * np.pi, 100) ``` 然后,我们使用meshgrid函数根据theta和phi生成theta-phi网格: ```python theta, phi = np.meshgrid(theta, phi) ``` 接下来,我们通过三角函数计算出x、y、z坐标: ```python x = np.sin(theta) * np.cos(phi) y = np.sin(theta) * np.sin(phi) z = np.cos(theta) ``` 最后,我们使用plot_surface函数绘制球体: ```python fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.plot_surface(x, y, z) plt.show() ``` 这段代码将绘制一个半球体,并通过3D投影显示在图像中。 注意:上述代码仅为示例,具体情况下需要根据实际需求进行相应的调整。 ### 回答2: 使用Matplotlib库可以很方便地绘制球体。下面是一个简单的示例代码: ```python import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # 生成半球体上的点坐标 theta = np.linspace(0, np.pi, 100) # 从0到π均匀分布的角度 phi = np.linspace(0, np.pi, 100)[:, np.newaxis] # 从0到π均匀分布的角度,并转为列向量 x = np.sin(theta) * np.cos(phi) y = np.sin(theta) * np.sin(phi) z = np.cos(theta) # 创建3D坐标轴 fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # 绘制球体 ax.plot_surface(x, y, z, color='b') # 设置坐标范围 ax.set_xlim(-1, 1) ax.set_ylim(-1, 1) ax.set_zlim(0, 1) # 设置坐标轴名称 ax.set_xlabel('X轴') ax.set_ylabel('Y轴') ax.set_zlabel('Z轴') # 显示图形 plt.show() ``` 这段代码首先使用`np.linspace()`函数生成从0到π等间距的角度,然后使用`np.sin()`和`np.cos()`函数根据角度计算出对应的半球体上的点的坐标。最后使用`plot_surface()`函数绘制球体,并为图形设置好坐标刻度和名称。 运行以上代码后,就可以得到一个绘制好的半球体图形。 ### 回答3: 要使用matplotlib绘制球体,我们可以使用mpl_toolkits.mplot3d模块中的Axes3D类。以下是一个简单的示例代码: ```python import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import numpy as np fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # 生成半球体的数据 u = np.linspace(0, np.pi, 30) # theta角度范围 v = np.linspace(0, np.pi/2, 30) # phi角度范围 u, v = np.meshgrid(u, v) x = np.sin(u) * np.cos(v) y = np.sin(u) * np.sin(v) z = np.cos(u) # 绘制球体 ax.plot_surface(x, y, z, color='b', alpha=0.7) # 设置坐标轴范围 ax.set_xlim([-1, 1]) ax.set_ylim([-1, 1]) ax.set_zlim([0, 1]) # 设置坐标轴标签 ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') # 显示图形 plt.show() ``` 上述代码首先创建了一个三维图形对象,并定义了用于绘制球体的参数u和v。然后,通过计算x、y和z坐标,得到了半球体的数据。最后,使用ax.plot_surface()函数绘制了半球体。 注意,在绘制球体之前,我们还需要设置坐标轴范围,并添加坐标轴标签。最后,使用plt.show()函数显示图形。 希望这个回答能帮助你绘制球体
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值