3D语音天气球(源码分享)——创建可旋转的3D球
开篇废话:
在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球的更多相关文章
- 3D语音天气球(源代码分享)——通过天气服务动态创建3D球
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 这个项目准备分四部分介绍: 一:创建可旋转的"3D球":3 ...
- 3D语音天气球(源码分享)——通过天气服务动态创建3D球
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 这个项目准备分四部分介绍: 一:创建可旋转的"3D球":3 ...
- 3D语音天气球(源码分享)——完结篇
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 由于这篇文章是本系列最后一篇,有必要进行简单的回顾和思路整理. 这个程序是由两 ...
- 3D语音天气球(源码分享)——在Unity中使用Android语音服务
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 这个项目准备分四部分介绍: 一:创建可旋转的"3D球":3 ...
- 推荐!Html5精品效果源码分享
一直在看别人的汇总,看到了一些不错的关于 HTML5内容的源码,我也汇总下分享出来,好东西需要共享!希望可以帮到需要的朋友. 1.劲爆分享:HTML5动感的火焰燃烧动画特效 这又是一款基于HTML5的 ...
- 微信小程序——智能小秘“遥知之”源码分享(语义理解基于olami)
微信小程序智能生活小秘书开发详解 >>>>>>>>>>>>>>>>>>>>> ...
- 支持语音识别、自然语言理解的微信小程序(“遥知之”智能小秘)完整源码分享
记录自己搭建https的silk录音文件语音识别服务的调用过程,所有代码可在文中找链接打包下载 >>>>>>>>>>>>> ...
- TCP/IP以及Socket聊天室带类库源码分享
TCP/IP以及Socket聊天室带类库源码分享 最近遇到个设备,需要去和客户的软件做一个网络通信交互,一般的我们的上位机都是作为客户端来和设备通信的,这次要作为服务端来监听客户端,在这个背景下,我查 ...
- [DeviceOne开发]-土地销售项目源码分享
一.简介 这个是一个真实项目开源,虽然不是很花哨,但是中规中矩,小细节处理的也很好,非常值得参考和借鉴.里面的数据都缓存到本地,可以离线运行,但是调整一下代码,马上就可以和服务端完全对接.后续会有详细 ...
随机推荐
- Java 并发:Executors 和线程池
让我们开始来从入门了解一下 Java 的并发编程. 本文主要介绍如何开始创建线程以及管理线程池,在 Java 语言中,一个最简单的线程如下代码所示: Runnable runnable = new R ...
- Activity初步,初学者必看
Activity是什么? Activity是一个可与用户交互并呈现组件的视图.通俗说就是运行的程序当前的这个显示界面. 如果你还不明白,那么你写过HTML吗,它就好比一个网页.我们程序中的用户视图,都 ...
- fprintf与fwrite函数用法与差异
在C语言中有两个常见的保存文件的函数:fprintf 与 fwrite.其主要用法与差异归纳如下: 一.fprintf函数. 1.以文本的形式保存文件.函数原型为 int fprintf(FILE* ...
- php--linux环境下的主从复制
1.编辑数据库配置文件my.cnf,一般在/etc/目录下. #vi /etc/my.cnf 在[mysqld]的下面加入下面代码:[第一步查看本文件夹中代码是否已经存在,存在不需要进行添加] 只是修 ...
- ArcGIS API for Silverlight 调用GP服务绘制等值面
原文:ArcGIS API for Silverlight 调用GP服务绘制等值面 GP服务模型如下图: 示例效果图片如下:
- js保留n位小数
1.功能:将浮点数四舍五入,取小数点后2位 function toDecimal(num) { var f = parseFloat(num); if (isNaN(f)) { return; } f ...
- myscroll
<!DOCTYPE html> <head><meta http-equiv="Content-Type" content="text/ht ...
- Java控制语句——while语句
while循环 在循环刚开始时,会计算一次“布尔表达式”的值,若条件为真,执行循环体,而对于后来每一次额外的循环,都会在开始前重新计算一次. 注意:语句中应有使循环趋向于结束的语句,否则会出现无限循环 ...
- VMWare虚拟机下为Ubuntu 12.04.1配置静态IP_转
转自:http://www.cnblogs.com/objectorl/archive/2012/09/27/vmware-ubuntu-nat-static-ip-settings.html 背景在 ...
- linux input输入子系统应用分析
输入设备(如按键.键盘.触摸屏.鼠标等)是典型的字符设备,其一般的工作机理是底层在按键.触摸等动作发送时产生一个中断(或驱动通过timer定时查询),然后CPU通过SPI.I2 C或外部存储器总线读取 ...