Unity制作简单3D图表

开篇废话:

在大学时稍微自学过一段时间Unity3D,虽然现在在做安卓,但一直对游戏开发很感兴趣,所以平时偶尔有空也会稍微看看,不过水平还是未入门菜鸟级的。

下面这个demo是看了雨松MOMO大神所写的几篇基础文章后,写的一个练习demo,用来展示简易的3D图表。

这个Demo非常初级,纯粹是为了练习知识点,但是所应用到的知识点非常基础,非常重要,适合初学者学习。截图如下:

 

 

简介:

这个Demo可以分为4个部分

第一部分——建立3D坐标系:

外框首先由四个平面所围成的一个“3D坐标系”,和X、Y、Z三个“坐标”组成。

1.四个平面

这四个平面所用的就是系统自带的cube,创建并调整cube的大小和方向组成上面的形状。

2.创建坐标系prefab

创建一个预设,并将左平面,右平面和后平面添加到下平面中最后添加到预设里,这样他们就变成了一个整体。如下图所示:

3.调整prefab在世界中的位置和他的scale

由于要设立坐标点,所以需要使刚才建立的坐标系的零点对应世界坐标的零点。

在本例中:假设每个单位长度为1,X坐标需要分成12份(12个月)坐标系scale的x值为24(每两份代表一个刻度)。Y轴代表百分比,分为5份(每份一个刻度)。Z轴同理。

通过上面的3个步骤,3D坐标系的样子已经出来了,下面开始为这个坐标系添加“刻度名称”。

第二部分——为坐标添加刻度名称:

刻度名称使用两个知识点:

1.世界坐标转换为屏幕坐标:

添加刻度名称其实就是将世界坐标的坐标值(因为我们已经在上一步中将坐标系和世界坐标同步了)转换为屏幕坐标值。

2.使用GUI.Label写出坐标名称:

通过刚才算出的屏幕坐标处使用GUI.Label函数写出当前坐标点的名称。

下面是本例中这个方法的代码:

[csharp] view
plain
copyprint?

  1. // isY代表是不是Y轴
  2. void drawCoordinate (Vector3 point, string name, bool isY) {
  3. // 将世界坐标转换为屏幕坐标
  4. Vector2 position = camera.WorldToScreenPoint (point);
  5. position = new Vector2 (position.x, position.y);
  6. // 设置刻度的大小和颜色
  7. Vector2 nameSize = GUI.skin.label.CalcSize (new GUIContent(name));
  8. GUI.color  = Color.yellow;
  9. // 根据X,Y轴的不同加上适当偏移量画出刻度
  10. if (isY) {
  11. GUI.Label(new Rect(position.x-nameSize.x-coordOffset ,Screen.height-position.y,nameSize.x,nameSize.y), name);
  12. }
  13. else {
  14. GUI.Label(new Rect(position.x-nameSize.x ,Screen.height-position.y,nameSize.x,nameSize.y), name);
  15. }
  16. }

调用方法如下:

[csharp] view
plain
copyprint?

  1. void OnGUI()
  2. {
  3. drawCoordinate (new Vector3 (0 , 0, 0), "0.00%", true);
  4. drawCoordinate (new Vector3 (2 , 0, 0), "Jan", false);

最后我贴上从网上找的关于Unity中坐标系的知识点(原文实在找不到了我就不贴连接了):

【Unity中四种坐标系】

1、World Space(世界坐标):

我们在场景中添加物体(如:Cube),他们都是以世界坐标显示在场景中的。

transform.position可以获得该位置坐标。

2、Screen Space(屏幕坐标):

以像素来定义的,以屏幕的左下角为(0,0)点,右上角为(Screen.width,Screen.height),Z的位置是以相机的世界单位来衡量的。

Screen.width = Camera.pixelWidth

Screen.height = Camera.pixelHeigth

鼠标位置坐标属于屏幕坐标,Input.mousePosition可以获得该位置坐标,

手指触摸屏幕也为屏幕坐标,Input.GetTouch(0).position可以获得单个手指触摸屏幕坐标。

3、ViewPort Space(视口坐标):

视口坐标是标准的和相对于相机的。相机的左下角为(0,0)点,右上角为(1,1)点,Z的位置是以相机的世界单位来衡量的。

4、绘制GUI界面的坐标系:

这个坐标系与屏幕坐标系相似,不同的是该坐标系以屏幕的左上角为(0,0)点,右下角为(Screen.width,Screen.height)。

【四种坐标系的转换】

1、世界坐标→屏幕坐标:

camera.WorldToScreenPoint(transform.position);

这样可以将世界坐标转换为屏幕坐标。其中camera为场景中的camera对象。

2、屏幕坐标→视口坐标:

camera.ScreenToViewportPoint(Input.GetTouch(0).position);

这样可以将屏幕坐标转换为视口坐标。其中camera为场景中的camera对象。

3、视口坐标→屏幕坐标:

camera.ViewportToScreenPoint();

4、视口坐标→世界坐标:

camera.ViewportToWorldPoint();

第三部分——在3D坐标系中画折线

坐标系建立好以后我们就可以在这个坐标系中画折线来啦。

坐标系已经和世界坐标系同步,所以每个坐标的坐标点我们已经知道,下面的问题就是如何将点连成线。

Unity提供了LineRenderer来画线,可以通过如下两种方法创建它:

一.Unity编辑器的方式:

1.Unity -> GameObject -> Create Empty 创建一个空的对象,我命名为line。

2.然后点击 Component -> Effects-> Line Renderer 给line添加一个线渲染器的属性

二.脚本的方式:

下面是本例的使用代码:

[csharp] view
plain
copyprint?

  1. public class lineScript1 : MonoBehaviour {
  2. private Color c1 = Color.red;
  3. private Color c2 = Color.red;
  4. private LineRenderer lineRenderer;
  5. private Vector3 v0 = new Vector3(0.0f,0.0f,3.0f);
  6. private Vector3 v1 = new Vector3(2.0f,2.0f,0.0f);
  7. private Vector3 v2 = new Vector3(4.0f,3.0f,1.0f);
  8. private Vector3 v3 = new Vector3(10.0f,4.0f,0.0f);
  9. private Vector3 v4 = new Vector3(15.0f,6.0f,2.0f);
  10. private Vector3 v5 = new Vector3(20.0f,8.6f,0.0f);
  11. void Start () {
  12. lineRenderer = lineRenderer = gameObject.AddComponent<LineRenderer>();
  13. lineRenderer.SetColors(c1, c2);
  14. lineRenderer.SetWidth(0.2f,0.2f);
  15. lineRenderer.SetVertexCount(6);
  16. }
  17. void Update () {
  18. lineRenderer.SetPosition (0, v0);
  19. lineRenderer.SetPosition (1, v1);
  20. lineRenderer.SetPosition (2, v2);
  21. lineRenderer.SetPosition (3, v3);
  22. lineRenderer.SetPosition (4, v4);
  23. lineRenderer.SetPosition (5, v5);
  24. }
  25. }

LineRenderer的详细使用请参考雨松momo的文章:Unity3D研究院之游戏对象的访问绘制线与绘制面详解(十七)

第四部分——通过手势/鼠标来放大、缩小、旋转坐标系

简单概括为两个要点:

1.手势和鼠标的识别

在Unity中手势识别有一个插件:FingerGestures

在本例中当然不需要做的这么复杂,只需要判断触摸点来进行一些简单计算就可以。

无论是Android应用还是Unity手势判断最常用的就是简单的通过记录之前的触摸点位置和之后的触摸点位置然后再进行计算。

计算触摸点Unity提供如下几个方法:

Input.touchCount可以判断当前触摸点的数量,所以可以通过这个方法来判断是单点触摸还是多点触摸

Input.GetTouch(0).phase方法会返回一个表示当前触摸类型的枚举(TouchPhase)。

TouchPhase有如下几种类型:

  • Began

    手指已触摸屏幕。

  • Moved

    手指在屏幕上移动。

  • Stationary

    手指触摸屏幕,但并没有移动。

  • Ended

    手指从屏幕上移开。这是一个触摸的最后状态。

  • Canceled

    系统取消跟踪触摸,如用户把屏幕放到他脸上或超过五个接触同时发生。这是一个触摸的最后状态。

更多关于Input的内容强烈建议去看Unity的脚本手册,英文不好的可以去Unity圣典看中文的。

2.控制物体的放大,缩小,旋转

在Unity中放大,缩小,旋转某个物体其实是通过拉近,拉远,旋摄像机来实现的(自动脑补)。

对于如何将触摸判断和对物体控制的结合我推荐看雨松momo的这篇文章——Unity3D研究院之IOS触摸屏手势控制镜头旋转与缩放(八)

最后附上本例的这段代码,雨松文章里用的是js的我这里给改成c#并且加上了鼠标滚轮的放大缩小:

[csharp] view
plain
copyprint?

  1. public class controll : MonoBehaviour {
  2. public Transform target;
  3. private float distance = 50.0f;
  4. private float xSpeed = 250.0f;
  5. private float ySpeed = 120.0f;
  6. private int yMinLimit = -20;
  7. private int yMaxLimit = 80;
  8. private float x = 0.0f;
  9. private float y = 0.0f;
  10. private int MouseWheelSensitivity = 5;
  11. private int zoomMin = 10;
  12. private int zoomMax = 50;
  13. private Vector2 oldPosition1;
  14. private Vector2 oldPosition2;
  15. void Start () {
  16. Vector3 angles = transform.eulerAngles;
  17. x = angles.y;
  18. y = angles.x;
  19. }
  20. void Update () {
  21. // 由于要支持鼠标和触摸,所以还需要加一个鼠标的计算
  22. if (Input.GetMouseButton (0)) {
  23. //根据触摸点计算X与Y位置
  24. if (Mathf.Abs(Input.GetAxis("Mouse X") * xSpeed * 0.02f) < 50) {
  25. x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
  26. }
  27. if (Mathf.Abs(Input.GetAxis("Mouse Y") * ySpeed * 0.02f) < 50) {
  28. y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
  29. }
  30. }
  31. if(Input.touchCount == 1)
  32. {
  33. //触摸类型为移动触摸
  34. if(Input.GetTouch(0).phase==TouchPhase.Moved)
  35. {
  36. //根据触摸点计算X与Y位置
  37. if (Mathf.Abs(Input.GetAxis("Mouse X") * xSpeed * 0.02f) < 50) {
  38. x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
  39. }
  40. if (Mathf.Abs(Input.GetAxis("Mouse Y") * ySpeed * 0.02f) < 50) {
  41. y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
  42. }
  43. }
  44. }
  45. //判断触摸数量为多点触摸
  46. if(Input.touchCount >1 )
  47. {
  48. //前两只手指触摸类型都为移动触摸
  49. if(Input.GetTouch(0).phase==TouchPhase.Moved||Input.GetTouch(1).phase==TouchPhase.Moved)
  50. {
  51. //计算出当前两点触摸点的位置
  52. Vector2 tempPosition1 = Input.GetTouch(0).position;
  53. Vector2 tempPosition2 = Input.GetTouch(1).position;
  54. //函数返回真为放大,返回假为缩小
  55. if(isEnlarge(oldPosition1,oldPosition2,tempPosition1,tempPosition2))
  56. {
  57. //放大系数超过3以后不允许继续放大
  58. //这里的数据是根据我项目中的模型而调节的,大家可以自己任意修改
  59. if(distance > zoomMin)
  60. {
  61. distance -= 0.5f;
  62. }
  63. }else
  64. {
  65. //缩小洗漱返回18.5后不允许继续缩小
  66. //这里的数据是根据我项目中的模型而调节的,大家可以自己任意修改
  67. if(distance < zoomMax)
  68. {
  69. distance += 0.5f;
  70. }
  71. }
  72. //备份上一次触摸点的位置,用于对比
  73. oldPosition1=tempPosition1;
  74. oldPosition2=tempPosition2;
  75. }
  76. }
  77. // 鼠标滚轮
  78. if (Input.GetAxis("Mouse ScrollWheel") != 0)
  79. {
  80. if (distance >= zoomMin && distance <= zoomMax)
  81. {
  82. distance -= Input.GetAxis("Mouse ScrollWheel") * MouseWheelSensitivity;
  83. }
  84. if (distance < zoomMin)
  85. {
  86. distance = zoomMin;
  87. }
  88. if (distance > zoomMax)
  89. {
  90. distance = zoomMax;
  91. }
  92. }
  93. }
  94. public bool isEnlarge(Vector2 oP1, Vector2 oP2, Vector2 nP1, Vector2 nP2) {
  95. //函数传入上一次触摸两点的位置与本次触摸两点的位置计算出用户的手势
  96. float leng1 =Mathf.Sqrt((oP1.x-oP2.x)*(oP1.x-oP2.x)+(oP1.y-oP2.y)*(oP1.y-oP2.y));
  97. float leng2 =Mathf.Sqrt((nP1.x-nP2.x)*(nP1.x-nP2.x)+(nP1.y-nP2.y)*(nP1.y-nP2.y));
  98. if(leng1<leng2)
  99. {
  100. //放大手势
  101. return true;
  102. }else
  103. {
  104. //缩小手势
  105. return false;
  106. }
  107. }
  108. void LateUpdate(){
  109. if (target) {
  110. //重置摄像机的位置
  111. y = ClampAngle(y, yMinLimit, yMaxLimit);
  112. Quaternion rotation = Quaternion.Euler(y, x, 0);
  113. Vector3 position = rotation * new Vector3(0.0f, 0.0f, -distance) + target.position;
  114. transform.rotation = rotation;
  115. transform.position = position;
  116. }
  117. }
  118. public float ClampAngle (float angle, float min,float max ) {
  119. if (angle < -360)
  120. angle += 360f;
  121. if (angle > 360)
  122. angle -= 360f;
  123. return Mathf.Clamp (angle, min, max);
  124. }
  125. }

写在最后:

这篇文章由于十分简单,而且我觉得逻辑讲的也算清楚,代码也贴了几段,所以源码我就不上传了。

写这个Demo的目的其实是为了下一篇文章,我在9月份的时候参加了一个网站的比赛,做了一个Unity和Android结合的3D语音的天气预报(可惜没获奖),过几天准备给它分享出来。因为我本来就是Unity菜鸟,而且好几个月没看了所以就拿这个demo先热热身。。。

PS:我Unity就会一点基础,挺怕写相关文章的,有错请见谅并恳请指正。。。

时间: 2024-09-22 18:00:05

Unity制作简单3D图表的相关文章

unity制作简单血条

学习Unity已经10天了,也没发现有什么长进,真的急.昨天仿着官方Demo做了个射击游戏轮廓,其中需要给每个怪做一个血条. 搜了一些,挺复杂的,用NGUI或者UGUI,外加很长的代码...不过还是找到了一篇简单的. 但是那一篇把所有的东西都放一起了,不太好,我在这整理分离一下. 背景: 官方Demo恶魔射手.其中每个怪都有一个EnemyHealth脚本,该脚本主要有怪物的血量等,然后有个TakeDamage()函数来计算伤害后的血量. 开始: 1.制作图片: PS一张细长的红色图片作为血量:

如何制作简单的 3D 打印模型

Hi 大家好! 了解一个方兴未艾,但极为有趣的话题 - 3D 打印 . 为了帮助大家对3D打印有一个初步的感性认识,我在线制作了一款可用于3D打印的model, 大家可以先通过体验这个在线 model 的3D 效果,体验一下让我们耳目为之一新的感觉 J ~ 首先打开URL : http://www.123dapp.com/Catch/2014-4-1-21-5-35/2258051 .首次进入时先看到的是一张2维的平面图片,然后请点选左下 3D VIEW . 待图像加载结束,就可以通过鼠标的拖曳

Unity 进度条3D制作(3D版)

昨天我们一起学习了2D进度跳的制作,那么趁着我们脑海中还残存昨日的记忆,今天继续学习另一种方法: 实现思路:当鼠标悬浮Start按钮->实例化物体并显示进度->100/100->进入游戏场景:   鼠标离开按钮进度还原为 0/100    直接点击Start按钮也可完成. 1,首先我们导入NGUI资源包,在当前工程的场景下创建UI. 2,在Herarchy下添加平行光,在Panel下添Button. 此处Background没有选择背景图片,即背景色为默认值,此处label设置字体显示S

ZAM 3D 制作简单的3D字幕 流程(二)

原地址:http://www.cnblogs.com/yk250/p/5663907.html 接着 ZAM 3D 制作简单的3D字幕 流程(一) .本篇将是ZAM 3D制作动画的一些关键点. 我们可以将各个字体工具自己的喜好填充好Materials,当然,也可以采用默认,一般默认灯光下是偏金黄色的,这个可以在左下角进行调节.左下第一个是当前选中的灯光设置,第二个则是全局的灯光设置.(如果你拖动了布局那就另当别论了.)比如我这里将字体染成了葫芦娃的红橙黄绿蓝靛紫以及葫芦小金刚的白色(注意,字体分

如何在ASP.Net创建各种3D图表

我们都知道,图表在ASP.NET技术中是一种特别受欢迎而又很重要的工具.图表是表示数据的图形,一般含有X和Y两个坐标轴.我们可以用折线,柱状,块状来表示数据.通过图表控件,我们即能表示数据又能比较各种图表的数据,例如比较去年和今年的收入.图表的类型也有很多,如柱状图.折线图.条形图.组合图等等. 这篇文章将阐述如何在ASP.NET中如何制作3D图表.首先,我将展示如何绘制出一个简单的图表. 简单图表的步骤 步骤1 新建一个"ASP.NET Empty Web Site". 步骤2 在S

制作简单钟表

利用css+原生js制作简单的钟表.效果如下所示 实现该效果,分三大块:html.javascript.css html部分 html部分比较简单,定义一个clock的div,内部有原点.时分秒针.日期以及时间,至于钟表上的刻度.数字等元素,因为量比较多,采用jvascript生成 1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <link rel='st

JSP制作简单登陆

JSP制作简单登陆界面 运行环境 eclipse+tomcat+MySQL 不知道的可以参考Jsp运行环境--Tomcat 项目列表 这里我先把jsp文件先放在Web-INF外面访问 需要建立的几个文件在图上.jsp 还要导入MySQL的jar包mysql-5.0.5.jar,导到WEB-INF中的lib文件夹就可以不需要Bulid Path 开始编写代码: 代码演示: index.jsp就好像一般网站的首页一样感觉,将header.jsp和footer.jsp引入其中 <%@ page lan

ArcGIS利用DEM制作简单三维

利用DEM数据镶嵌后,矢量数据裁剪得到研究范围的DEM数据,在ARCScene中进行三维制作 ArcGIS利用DEM制作简单三维 点击学习我的系统教程哦

利用replaceChild制作简单的吞噬效果【jsDEMO】

[功能说明] 利用replaceChild制作简单的吞噬效果 [HTML代码说明] <ul class="list" id="list"> <li class="in">1</li> <li class="in">2</li> <li class="in">3</li> <li class="in"