欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

WPF 3D足球导览

程序员文章站 2022-04-14 19:40:14
获取足球的3D坐标后,在每一个坐标位置创建一个ModelVisual3D元素,既能实现炫酷的3D界面。同样根据这些点也能获取到足球的每一个面。 ......

      根据博文:获取足球的3d坐标后,在每一个坐标位置创建一个modelvisual3d元素,既能实现炫酷的3d界面。在此基础上我基于这些点构建了3d足球。

动态效果图:

WPF 3D足球导览

WPF 3D足球导览

每一个足球的块上,我贴上了不同的图,点击图获取对应的信息在右侧显示。

 

实现原理:

  首先对所有顶点根据y值进行分层,第一层的顶点见下图:

     WPF 3D足球导览

所有与第一层相互连接的点为第二层:

    WPF 3D足球导览

以此类推,总共可获得八层顶点。

 

然后,拿到第一层(第一组)的顶点(5个),第一组五个顶点组成了正五边型,正五边形每一条边对应两个顶点,根据距离计算,可以从第二层中找到与第一层顶点距离最近的点,如下图第一层的正五边形的其中一条边ab,在第二层中可以通过计算拿到与a、b两个点距离最近的c、d两个点。然后以c、d作为基点从第三层中又可以得到同时距离c、d 两个点距离最近的两个点e、f。  

WPF 3D足球导览 WPF 3D足球导览

 从上面两个图你可以直观的看见,在第二层中分别与a、b距离最近的点只能是c、d。 在第三层中同时距离c点和d点最近的点只能是e、f。  abcdef六个点即构成了足球的一个面。 

按照这种以层级和距离的方式即可计算得到足球的每一面所包含的3d坐标。

循环计算实现逻辑代码:

// get bucky ball all blocks
private void getbuckyballblocks()
{
    // buckyballpoints -> list<list<point3d>>
    int nlevelcount = buckyballpoints.count; // 总层数 - 8
    for (int i = 0; i < nlevelcount; i++) // 
    {
        int ncurlevel = i;  //当前层
        //  下一层
        int nsecondlevelbasecur = ncurlevel + 1;
        //  第三层
        int nthirdlevelbasecur = ncurlevel + 2;

        //  three levels as a group, and every group defined five blocks
        //(1,2,3)(2,3,4)(3,4,5)(4,5,6)(5,6,7)(6,7,8)
        if (nthirdlevelbasecur < nlevelcount)
        {
            // 计算距离,根据距离判断是否属于同一个面
            this.calculatebuckyballblocks(buckyballpoints[ncurlevel], 
                buckyballpoints[nsecondlevelbasecur],
                buckyballpoints[nthirdlevelbasecur]);
        }
    }
    // 第一层(现成的正五边形)
    this.buckyballblocks.add(buckyballpoints[0]);
    // bottom block points  第八层(现成的正五边形)
    this.buckyballblocks.add(buckyballpoints[buckyballpoints.count - 1]);
}

通过以上方式获得每一个面对应的顶点坐标后,即可通过坐标构建平面。 

关键代码:

// 根据顶面创建3d平面
private meshgeometry3d createblockmeshgeometry3d(list<point3d> ltpoints)
{
    point3d[] point3ds = new point3d[ltpoints.count];
    for (int i = 0; i < ltpoints.count; i++)
        point3ds[i] = ltpoints[i];

    meshgeometry3d ogeometry = new meshgeometry3d()
    {
        positions = new point3dcollection(point3ds)
    };

    if (ltpoints.count == 6)
        ogeometry.triangleindices = new int32collection(new int[] { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5 });
    else if (ltpoints.count == 5)
        ogeometry.triangleindices = new int32collection(new int[] { 0, 1, 2, 0, 2, 3, 0, 3, 4 });
    else
        showerrorandexit();

    pointcollection texcoords = new pointcollection();
    for (int i = ltpoints.count -1; i >= 0; i--)
        texcoords.add(new point(ltpoints[i].x, ltpoints[i].y));
    ogeometry.texturecoordinates = texcoords;

    return ogeometry;
}

最后给每一个构建的平面的visual属性附上加载的图片和点击事件既能实现我demo中的效果。

最后附上demo整体效果图:

WPF 3D足球导览

    工具:visual studio 2017

    工程:wpf c#

    源代码下载

              WPF 3D足球导览