开篇废话:

在9月份时参加了一个网站的比赛,比赛的题目是需要使用第三方平台提供的服务做出创意的作品。

于是我选择使用语音服务,天气服务,Unity3D,Android来制作一个3D语音天气预报,我给它起名叫做3D语音天气球(好土。。。)

虽然没获奖但我觉得这个项目中还是有些东西比较有创意的,所以打算分享出来,或许有人会用到。

下面简单看下效果图:

左边是Unity做出后在电脑上运行效果图

右边是Unity结合Android和语音控制之后在手机运行的效果图(手机不会做GIF):

    

瞅着还不错吧。。。

项目简介:

项目结构:

首先这个项目的开发分为Android端和Unity3D端:

Android端:

Android端主要负责的是语音控制模块和4个按钮,并将语音处理后的结果传递到Unity端中做处理

Unity3D端:

Unity端负责接收Android端语音处理后传递过来的信息,和4个按键的反馈。

并根据不同的省市情况实时的从网上获取天气信息,解析后显示在我们制作的3D球上。

Build:

最后将Android端的代码以插件的形式放入Unity端中,然后在Unity端Build成apk文件在手机中运行。

业务简介:

初始界面:

在初始界面最上方有个简易的动态栏可以显示一些提示信息。

动态栏之下是一个省市的名称标题和平均气温。

最中间的“动态球”显示全国各省份的分布。并且会根据该省市的平均气温设置不同的颜色来大体反映出全国天气情况(越红表示温度越高,越蓝表示越低)。

详细页面:

在选中一个省后(可以鼠标或手势选中,如果在手机上可以语音选中),点击详细可以进入到详细页面。

在详细页面中显示当前省内所有城市的天气信息,并且“动态球”上会显示出天气趋势的小图片。

如果选中某个城市后再次点击详细则会在屏幕中上方显示该城市的详细天气信息,包括风速紫外线等等信息。

功能划分:

这个项目虽然功能比较简单,但是代码也写了不少,关键好多地方都是为了快速完成功能,也并没有考虑一些框架和结构,因此逻辑看起来特别乱。

为了思路清晰,我准备分几篇文章把这个项目详细介绍一下。因为我觉得这样分块进行不仅思路清晰,还可以按需求观看,而且也避免都写在一篇文章中导致又臭又长逻辑混乱。

我准备分四篇文章来介绍这个项目:

一:创建可旋转的“3D球”:3D语音天气球(源码分享)——创建可旋转的3D球

二:通过天气服务,从网络获取时实天气信息并动态生成“3D球”:3D语音天气球(源码分享)——通过天气服务动态创建3D球

三:Android语音服务和Unity的消息传递:3D语音天气球(源码分享)——在Unity中使用Android语音服务

四:Unity3D端和Android端的结合3D语音天气球(源码分享)——完结篇

今天就先来介绍一下如何创建这个可旋转的“3D球”:

3D球的创建

下面是我将其他所有模块的代码都去掉后,一个纯净版的效果图,而今天的任务就是完成它:

如图可示,

在这个“3D”球中平均分布这很多“小块”。

本例中每一块显示的是一个标题和一行详细信息。

当然也可以在每块中显示图片,显示3D模型。而且还可以有更多创意,比如3D球中的每个小块又是一个3D球,如此递归循环下去这样是不是就是我们的宇宙了(想多了,赶紧跑回来。。。)

原理构成:

先来看下面3个图示:

    

相信通过上面的图示,大家就应该差不多知道这个3D球和球面上的"小块"是如何构成的了。

没错,这个3D球是由一个大球和若干个小球组成的,小球附着在大球上,大球负责控制转动,小球也就相应的转动了。

再稍微详细些:

大球是一个“透明/隐形”的一个物体,他有物理碰撞器属性,所以可以转动。

所有的小球均匀分布在大球之上,小球同样是“透明/隐形”,但小球上会附着文字和图片等,小球永远随着大球转动且文字方向永远面向摄像机。

把上面这些弄明白之后配合Unity最简单的几个基础语法和知识点就可以完成这个可动态旋转的3D球了!

代码详解:

下面的内容解需要一定Unity基础,Unity入门很容易。我的习惯是先看最基本的视频教程(一定要国人出的,一定要简单无脑),之后看书看官网文档,再去搜几个大神的blog看看。

这里强烈推荐两个大神的Blog:雨松MOMO研究院墨半成霜的博客

1.创建大球

首先需要建立大球

通过:菜单-GameObject-create other-sphere来创建一个球体(sphere)

调整大球的大小,位置。点掉他的Mash Renderer,这样大球就“隐身”了。

3. 创建小球预设

小球是由代码动态生成的,但是我们需要先做一个小球的预设。

方法和制作大球相同,不过需要给小球增加一个Text Mesh来显示文字,如果除了显示文字还需要在小球身上显示一些其他东西,可以建一个空的GameObject添加相应的组件,然后将这个GameObject加入到小球组成一个整体(prefab预设)。

这个例子中是显示城市名和简单的天气信息,城市名直接加在小球上,简单的天气信息放在另一个GameObject上,调整大小后放入小球中组成一个整体。

4.动态生成小球

这个我认为是这个步骤是整个项目里最难的地方,他的难度在于要根据小球数量计算出分布在大球身上的坐标。

简单来说就是在球体表面平均分割点,并求出每个点的三维坐标。

如果我能算出来就是大神了。。。还好有Google,我在Google中搜到了一个算法如下:

				float inc = Mathf.PI * (3 - Mathf.Sqrt (5));
float off = 2 / N;
for (int k = 0; k < (N); k++) {
float y = k * off - 1 + (off / 2);
float r = Mathf.Sqrt (1 - y * y);
float phi = k * inc;
Vector3 pos = new Vector3 ((Mathf.Cos (phi) * r * size), y * size, Mathf.Sin (phi) * r * size);
}

N为需要平均分为多少份。size为分割小球的大小,r为大球半径。

for循环中的Vector3类型的pos就是计算所得的三维坐标。我也不知道这个算法是什么原理,数学好的希望给讲解一下。

更多的在球体上分割点的算法可以在Google上试着搜下关键词:distributed points on sphere

通过算法求出每个点的坐标后,通过下面代码就可以创建出小球:

GameObject text = (GameObject)Instantiate (textObject, pos, Quaternion.identity);

textObject是我们之前做的小球预设, pos是刚刚求出的小球坐标。最后循环创建所有小球的效果如下:

5. 设置小球文字和颜色

上面创建好名为text的GameObject对象就是我们的小球。下面就要为每个小球设置父亲,颜色,大小,中心文字,详细信息。

						// 将大球设置为小球的父亲(将小球放在大球身上)
text.transform.parent = gameObject.transform;
// 获取小球的TextMesh组件
TextMesh tm = (TextMesh)text.GetComponent<TextMesh> ();
// 设置文字
tm.text = city.getName ();
// 设置颜色
tm.color = city.getWeatherColor ();
// 设置大小
text.transform.localScale = city.getSize ();
// 循环获取小球的孩子(也就是小球里面添加的GameObject,这里只有一个显示详细信息)
foreach (Transform child in text.transform) {
TextMesh tm2 = (TextMesh)child.GetComponent<TextMesh> ();
tm2.text = city.getTempture ();
tm2.color = city.getWeatherColor ();
}

6. 设置小球朝向,透明度,颜色

因为整个大球是不停在旋转,所以大球上的小球们的朝向,透明度,和颜色都会不停的变化。所以需要实时的调整小球的各种属性。

在update()函数中:

				// 遍历大球中的小球,设置小球的朝向,透明度,颜色
foreach (Transform child in gameObject.transform) {
// 小球永远朝向摄像机
child.LookAt (new Vector3 (cameraTarget.position.x, cameraTarget.position.y, -cameraTarget.position.z));
// 通过距离设置小球的透明度,产生越远越透明的效果
float dis = Vector3.Distance (child.position, cameraTarget.transform.position);
Color c = child.renderer.material.color;
float alpha = Mathf.Abs (dis - r) / 5f + 0.1f; // 设置小球和它子gameobject的颜色
child.renderer.material.color = new Color (c.r, c.g, c.b, alpha);
foreach (Transform cc in child.transform) {
cc.renderer.material.color = new Color (c.r, c.g, c.b, alpha);
}
}

3D球的旋转:

上面我们已经基本设置后大球和其身上的小球们(现在他们是一个整体)。

下面我们就需要让他们旋转起来,这时我们需要为大球添加碰撞器,这样我们才能点击它并旋转它。

Component-Physics-Sphere Collider

通过下面代码可以进行手势/鼠标旋转(如果快速转动会有一个逐渐变慢到最终停止的效果)

初始化:

		//是否被拖拽//
private bool onDrag = false;
//旋转速度//
private float speed = 3f;
//阻尼速度//
private float tempSpeed;
//鼠标沿水平方向移动的增量//
private float axisX;
//鼠标沿竖直方向移动的增量//
private float axisY;
//滑动距离(鼠标)
private float cXY;

重写鼠标按下和拖拽函数:

		//鼠标移动的距离
void OnMouseDown ()
{
//接受鼠标按下的事件//
axisX = 0f;
axisY = 0f;
} //鼠标拖拽时的操作
void OnMouseDrag ()
{
onDrag = true;
axisX = -Input.GetAxis ("Mouse X");
axisY = Input.GetAxis ("Mouse Y"); cXY = Mathf.Sqrt (axisX * axisX + axisY * axisY);
//计算鼠标移动的长度//
if (cXY == 0f) {
cXY = 1f;
}
}

计算阻尼(为了实现上面提到的越转越慢效果)

		//计算阻尼速度
float Rigid ()
{
if (onDrag) {
tempSpeed = speed;
} else {
if (tempSpeed > 0) {
//通过除以鼠标移动长度实现拖拽越长速度减缓越慢
if (cXY != 0) {
tempSpeed -= speed * 2 * Time.deltaTime / cXY;
}
} else {
tempSpeed = 0;
}
}
return tempSpeed;
}

最后在Update函数中判断:

				// 根据计算出的阻尼和X,Y轴的偏移来旋转大球
gameObject.transform.Rotate (new Vector3 (axisY, axisX, 0) * Rigid (), Space.World); // 如果鼠标离开屏幕则标记为已经不再拖拽
if (!Input.GetMouseButton (0)) {
onDrag = false;
}

写在最后:

上面所有的代码都只是一个思路和一些必要的步骤。如果大家有兴趣,可以下载它的源码来看看。

GitHub地址:https://github.com/a396901990/3D_Sphere

一:创建可旋转的“3D球”:3D语音天气球(源码分享)——创建可旋转的3D球

二:通过天气服务,从网络获取时实天气信息并动态生成“3D球”:3D语音天气球(源码分享)——通过天气服务动态创建3D球

三:Android语音服务和Unity的消息传递:3D语音天气球(源码分享)——在Unity中使用Android语音服务

四:Unity3D端和Android端的结合3D语音天气球(源码分享)——完结篇

3D语音天气球(源码分享)——创建可旋转的3D球的更多相关文章

  1. 3D语音天气球(源代码分享)——通过天气服务动态创建3D球

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 这个项目准备分四部分介绍: 一:创建可旋转的"3D球":3 ...

  2. 3D语音天气球(源码分享)——通过天气服务动态创建3D球

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 这个项目准备分四部分介绍: 一:创建可旋转的"3D球":3 ...

  3. 3D语音天气球(源码分享)——完结篇

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 由于这篇文章是本系列最后一篇,有必要进行简单的回顾和思路整理. 这个程序是由两 ...

  4. 3D语音天气球(源码分享)——在Unity中使用Android语音服务

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 这个项目准备分四部分介绍: 一:创建可旋转的"3D球":3 ...

  5. 推荐!Html5精品效果源码分享

    一直在看别人的汇总,看到了一些不错的关于 HTML5内容的源码,我也汇总下分享出来,好东西需要共享!希望可以帮到需要的朋友. 1.劲爆分享:HTML5动感的火焰燃烧动画特效 这又是一款基于HTML5的 ...

  6. 微信小程序——智能小秘“遥知之”源码分享(语义理解基于olami)

    微信小程序智能生活小秘书开发详解 >>>>>>>>>>>>>>>>>>>>> ...

  7. 支持语音识别、自然语言理解的微信小程序(“遥知之”智能小秘)完整源码分享

    记录自己搭建https的silk录音文件语音识别服务的调用过程,所有代码可在文中找链接打包下载 >>>>>>>>>>>>> ...

  8. TCP/IP以及Socket聊天室带类库源码分享

    TCP/IP以及Socket聊天室带类库源码分享 最近遇到个设备,需要去和客户的软件做一个网络通信交互,一般的我们的上位机都是作为客户端来和设备通信的,这次要作为服务端来监听客户端,在这个背景下,我查 ...

  9. [DeviceOne开发]-土地销售项目源码分享

    一.简介 这个是一个真实项目开源,虽然不是很花哨,但是中规中矩,小细节处理的也很好,非常值得参考和借鉴.里面的数据都缓存到本地,可以离线运行,但是调整一下代码,马上就可以和服务端完全对接.后续会有详细 ...

随机推荐

  1. hitTest:WithEvent 和Responder Chain

    这个方法是找到那个View被touch,当找到后就成为响应链的第一个了,如果他不能处理这个Event,那么就找nextResponder 直至application 如果不能处理,那就会丢弃掉. ht ...

  2. Qt 动画快速入门(一)

    Qt-4.6动画Animation快速入门三字决 Qt-4.6新增了Animation Framework(动画框架),让我们能够方便的写一些生动的程序.不必像以前的版本一样,所有的控件都枯燥的呆在伟 ...

  3. angularJS推荐显示注入写法

    使用js压缩工具时发现压缩之后的控制器注入参数由原来的$scope变成了a,b...这样的字母而导致js失效,那么我们推荐使用完整的显示注入方式来解决此问题! //隐式注入的写法 angular.mo ...

  4. Android开发笔记:SQLite导入导出数据

    SQLite是Android中最方便使用的数据库了,现在看下如何快速的在SQLite中导入导出数据. 首先由于是.NET项目转Android,原有数据库使用的是SQLSERVER,由于项目相同部分结构 ...

  5. Web:AJAX的详解

    Web中的AJAX技术: 1.介绍:全称:Asnchronous JavaScript and XML,即异步的JavaScript和XML功能:它不是某种编程语言,是一种无需加载整个网页的情况下能够 ...

  6. 不连数据库List分页

    package com.jpsycn.kfwggl.common.crawl; import java.util.ArrayList; import java.util.List; public cl ...

  7. LIB和DLL的区别与使用

    转这篇文章是因为以前有个误区,以为lib为静态库,dll为动态库,这理解并不错,但不全面.lib分两种的:(1) lib包含所有内容的静态库,应用程序用它即可,这是我理解的一种(2) lib只包含头部 ...

  8. C# Albert工程阅读关键字解析

    // 摘要: // 为强类型集合提供 abstract 基类. [Serializable] [ComVisible(true)] public abstract class CollectionBa ...

  9. Java遇见HTML——JSP篇之JSP指令与动作元素

    一.include指令(如:<%@include file="..."%> ) 示例: Date.jsp <%@page import="java.te ...

  10. 维护计划生成的SSIS包存储在哪

    首先理解导入导出包的基本概念:http://technet.microsoft.com/zh-cn/library/ms141772(v=SQL.110).aspx包既可以保存在SQL Server ...