有一段时间没有玩过unity了,还是忙里偷闲捡起来折腾一下。最近升级到了4.6,新的版本加入了unity自带的unity系统,看起来清爽多了。在没有UGUI的日子里,有NGUI用用自然也是不错的,但好与坏都是相对的吧,相信unity官方做出来来的新的UI系统可以更加出色,方便易用。
对于新的UI系统,网上好多大牛都相继出了系列教程了,我暂时还没有太多精力来琢磨透。希望之后能够深入的研究一些东西,而不是浮于表面。总而言之,自己离大牛还有好几个身位,革命尚未成功,同志任需努力。
之前呢,就有用unity开发各种稀奇古怪小工具的想法,比如说制作3D图表之类的玩意,看起来就酷酷的哈。虽然说自我感觉执行力不差,但是有时候还是有点懒惰,无奈的研究生生活~~~昨天看到一哥们发了一篇制作3D图表的博客,利用LineRenderer绘制折线图,感觉还不错。于是就坚定了我写这篇博客的动力。
/*************************************分割线*************************************/
好吧,下面开始说正事。
先上图
首先呢,饼图其实就是将一个圆柱体按照比例分成若干个部分。每个部分都是一个扇形区域。
然后呢,我就把整个圆柱大致分成了100个如下图所示的三角形区域(实际上是立体的,这里姑且称这些三角形区域为一个基元)。
为什么说是大致100个部分呢,因为我们可能遇到某个扇页的占比有小数的情况,那么这种情况下,我会把有小数的区域分割成两块,各自计算占比,然后依据占比缩放。
之后,我们依据统计的数据,计算出这些数据之和,以及各扇页的占比,求得需要的的基元数目,以及各个基元的旋转角度,并对同一扇页内的基元加上相同的颜色。
最后,在各个扇页上方显示出占比。
基元:
若干扇区:
前面呢,说了实现的大致流程。整体实现起来是比较简单的,但是也遇到一些小问题。
1.unity自带的3D gameobject中是没有类似于基元的三明治形状的模型的。但我又不想去从外面倒入一个模型进来,于是干脆用代码生成一个好了。使用的方法比较笨,要自己设置网格的顶点和三角形。关键代码如下。
/// <summary> /// 初始化网格 /// </summary> void initMesh() { float y = Mathf.PI * Config.R / Config.NUM; float x = Mathf.Sqrt(Config.R * Config.R - y * y); Vector3 origin1 = new Vector3(0, 0, 0); Vector3 origin2 = new Vector3(x, 0, y); Vector3 origin3 = new Vector3(x, 0, -y); Vector3 offset = new Vector3(0, Config.HEIGHT, 0); mesh = new Mesh(); mesh.vertices = new Vector3[6] { origin1 + offset, origin2 + offset, origin3 + offset, origin1 - offset, origin2 - offset, origin3 - offset }; mesh.triangles = new int[24] { 0,1,2,3,5,4, 0,3,2,2,3,5, 0,1,3,4,3,1, 2,1,4,2,4,5}; meshFilter = gameObject.AddComponent<MeshFilter>(); meshFilter.mesh = mesh; meshRenderer = gameObject.AddComponent<MeshRenderer>(); meshRenderer.material.shader = Shader.Find("Diffuse"); }
2.因为我们这里每个基元都是1%,但有的扇页占据的比例可能会出现20.5%这样的数据,这样就需要做特殊处理。
/// <summary> /// 创建一组fanbase /// 起始部分和结束部分特殊处理 /// 因为可能不是整数,所以会有缩放 /// </summary> private void initFanBaseList() { float beginCeil = Mathf.Ceil(begin); float endFloor = Mathf.Floor(end); createFanBase((beginCeil + begin) / 2-0.5f, beginCeil - begin); for (int i = (int)Mathf.Ceil(begin); i < (int)Mathf.Floor(end); i++) { createFanBase(i, 1f); } createFanBase((end + endFloor) / 2 - 0.5f, end - endFloor); }
3.最后一个小问题是,立体的文字显示,新版本的unity中,我已经找不到3D text了。
于是像下面这样,自己另外创建一个gameobject,加上TextMesh和MeshRenderer组件就可以显示立体的文字了。
总之,实现起来还是比较简单的。源代码保存在云盘中了,需要的朋友可以看看。(可能对旧版本有兼容问题)