zoukankan      html  css  js  c++  java
  • 使用十二面体画球体

    当做一个地球的时候,可以使用六面体,八面体和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;
        }
    

      

  • 相关阅读:
    Caffe学习系列(18): 绘制网络模型
    Caffe学习系列(17):模型各层数据和参数可视化
    android ------ RecyclerView 模仿淘宝购物车
    android ------- 开发者的 RxJava 详解
    android -------- 压缩图片文件工具类
    android -------- MVP+DataBinding 的使用
    android -------- ConstraintLayout Group和goneMargin(五)
    android -------- ConstraintLayout Guideline和Barrier(四)
    android -------- ConstraintLayout 宽高比和偏移量比(三)
    android -------- ConstraintLayout 约束属性(二)
  • 原文地址:https://www.cnblogs.com/xingyunge/p/10831274.html
Copyright © 2011-2022 走看看