转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持!
开篇废话:
由于这篇文章是本系列最后一篇,有必要进行简单的回顾和思路整理。
这个程序是由两部分组成,Android端和Unity端:
1.Unity端负责3D球的创建,显示和旋转:3D语音天气球(源码分享)——创建可旋转的3D球
2.通过天气服务动态创建3D球:3D语音天气球(源码分享)——通过天气服务动态创建3D球
3.Android端使用第三方的语音服务来进行语音识别:3D语音天气球(源码分享)——在Unity中使用Android语音服务
4.Unity中加入Android项目:Unity中加入Android项目的Build步骤
5.Android端和Unity端通信交互:ANDROID应用中嵌入Unity3D视图(展示3D模型)
6.将Android端4个按钮和语音指令传入Unity中进行相应操作。
本文将介绍最后的第6部分:从Android端传入“指令”,并在Unity中处理。
效果图:
左边是Unity做出后在电脑上运行效果图,仅支持鼠标拖动。
右边是Unity结合Android和语音控制之后在手机运行的效果图,我们可以通过这4个按钮和触屏滑动来操作这个程序。下面来简单介绍一下这4个按钮的实现方法:
4个按钮:
Android端的4个按钮其实就是一个非常普通的布局。布局有两层,里面一层用来显示Unity视图,外面一层用来显示4个按钮(4个按钮也可以做到Unity端):
下面是Android代码中4个按钮的点击触发事件:
// 语音点击监听
public class voiceListener implements OnClickListener { @Override
public void onClick(View arg0) {
voiceResult = "";
// 设置参数
setParam();
mVoice.startListening(voiceListener);
}
} // 返回点击监听
public class returnListener implements OnClickListener { @Override
public void onClick(View arg0) {
UnityPlayer.UnitySendMessage("Main Camera", "back", "");
}
} // 详细点击监听
public class detailListener implements OnClickListener { @Override
public void onClick(View arg0) {
UnityPlayer.UnitySendMessage("Main Camera", "detail", "");
}
} // 退出点击监听
public class quitListener implements OnClickListener { @Override
public void onClick(View arg0) {
System.exit(0);
}
}
下面以详细(detail)为例简单介绍下:
UnityPlayer.UnitySendMessage("Main Camera", "detail", "");
这段代码就是用来和Unity通讯的方法。这个函数中接收三个参数:接收的Unity对象,调用的方法,方法接收的参数。
本例中4个按键的接收对象都是Main Camera,就是我们程序的主摄像机。
再来看看用来接收detail方法的Main Camera脚本中的代码:
// 详细
void detail(string str) { string currentCity = mySphere.currentCity;
string currentCityID = mySphere.currentCityID;
bool isCity = mySphere.isCity;
Hashtable allCityID = mySphere.allCityID; if (isCity)
{
mySphere.getDetail(currentCityID);
}
else
{
mySphere.setNewCity((string[])allCityID[currentCity],true,"");
} }
这段代码的作用就是加载详细的省市信息。
先拿到当前小球的省市名称和编号,然后根据现在是省,还是城市来做不同操作。
如果当前是省,在点击“详细”按钮后将显示当前省下所有城市的信息。
如果当前是市,则显示详细天气信息。
mySphere就是主摄像机中对于“3D”大球的一个引用对象。因为摄像机只有一个,所以这里我将它当作一个控制器(controller),来控制小球(model),和UI的显示(view)。也算是一个简单的MVC模式的实现。
四个按钮中“退出”,“后退”,“详细”都很简单,下面讲解一下比较重要的功能——“语音”:
语音:
Android端:
点击“语音”按钮后会触发相应监听,然后调用语音服务解析语音命令,将其转化为文字,根据这些文字(本例中就是省市名称)查询数据,之后传递到Unity端。
Android端代码我在上篇文章介绍过,就不多说了。
Unity端:
接收传递过来的信息(就是省市编号),根据省市编号在3D球中查找对应的小球。然后将小球转到正对着我们的主摄像机,这样就完成了语音查询。
实现很简单,其实只有两部分:
1.查找
2.旋转
如下图所示,为了方便截图我设置了一个按钮来模拟语音点击。
当点击它时会查找“北京”,然后自动将“北京”小球旋转到正*(会有一个速度减缓效果slerp插值)
查找:
查找很简单,就是循环所有的小球,然后找到名字相匹配的。
foreach (Transform child in gameObject.transform)
{
if (child.GetComponent<TextMesh> ().text.Equals(findName)) { // rotation logic
}
}
旋转:
旋转是本文的重点,也是当初困扰我好久的一个问题,因为我对Unity不是很熟,数学知识也忘光光了。
Unity中提供很多关于旋转方面的函数,想详细了解的话官方文档是个好东西。
下面简单介绍一下我计算角度的方法,过几天等我把旋转角度的相关内容研究明白后,我计划写一篇关于旋转方面的总结。
先看下面的图,我用Debug.DrawLine方法将大球圆心到摄像机,和大球圆心到查找小球标记为两条红色的射线。
Debug.DrawLine(gameObject.transform.position, cameraTarget.position, Color.red);
Debug.DrawLine(child.transform.position, gameObject.transform.position, Color.red);
如图,假设大球圆心为O,圆心O到查找球的射线为OA,圆心O到摄像机的射线为OB。
第一种方法:
方法一的核心就是Quaternion.Euler(x : float, y : float, z : float)这个函数,简单理解就是该函数会返回一个旋转角度。3个参数为绕x轴旋转x度,绕y轴旋转y度,绕z轴旋转z度。
所以第一种方法的思路就是求出目标球需要绕多少度可以转到屏幕正中间。因为两次旋转就可以确定,所以euler(x,y,z)这个方法中随便算出两个值就行。
计算绕Y轴的角度:取A点在XOZ平面的投影A'点绕Y轴方向所形成的夹角。
计算绕Z轴的角度:取A点在XOY平面的投影A'点绕X轴负方向所形成的夹角。
// 重置大球的角度
gameObject.transform.rotation = new Quaternion(0,0,0,0); // 测试辅助射线
Debug.DrawLine(gameObject.transform.position, cameraTarget.position, Color.red);
Debug.DrawLine(child.transform.position, gameObject.transform.position, Color.red); // 小球到大球的向量
Vector3 targetDir = child.position - transform.position; // X轴负方向的向量
Vector3 dirR = -Vector3.right;
// Z轴负方向的向量
Vector3 dirF = -Vector3.forward; // 计算绕Y轴的旋转角度
float angleY = Vector3.Angle(new Vector3(targetDir.x, 0, targetDir.z), dirF);
// 计算绕Z轴的旋转角度
float angleZ = Vector3.Angle(new Vector3(targetDir.x, targetDir.y, 0), dirR); // 旋转大球
gameObject.transform.localRotation = Quaternion.Euler (0, angleY, angleZ);
Vector3.Angle (from : Vector3, to : Vector3)函数 的作用是返回from和to之间的夹角。
第二种方法:
第二种方法就简单太多了,核心是Quaternion.FromToRotation (fromDirection : Vector3, toDirection : Vector3)方法,它的作用就是返回从向量fromDirection到toDirection所需的旋转角度。
所以思路是通过求出圆心到小球的向量OA,和圆心到摄像机的向量OB,然后计算两个夹角的角度。在将大球旋转这个角度就ok了,代码如下:
// 圆心到目标球的向量
Vector3 targetDir = child.position - transform.position;
// 圆心到摄像机的向量
Vector3 cameraDir = -Vector3.forward;
// 求出两个向量的旋转角度
Quaternion rotation = Quaternion.FromToRotation(targetDir, cameraDir) * transform.rotation;
// 大球旋转插值旋转这个角度
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * 3f);
上面的代码中应用了Quaternion.Slerp (from : Quaternion, to : Quaternion, t : float)方法,它会将刚刚计算的Quaternion旋转值以插值进行旋转(也就是类似与球面曲线那种先快后慢的效果)。
Slerp翻译为球形插值,我个人觉得就像Android动画中设置Interpolator差不多的感觉。
写在最后:
3D语音天气球的所有内容终于介绍完了。说实话,当写完第二篇就不爱写了,因为这个demo写的很早,思路和Unity的相关知识点也忘差不多了。最近工作也忙,加上要过年了也越来越懒。。。不过最终还是坚持下来并给这个算不上项目的项目画上了一个句号。
当初要做它就是为了参加一个比赛,虽然天气查询这个功能有点鸡肋,不过创意还是有的,所以还是抱着要获奖的心态去的。结果很不幸,连个名次都没有,当时肯定有点小郁闷,毕竟熬夜熬了一个月。不过现在回头再来看这个东西确实比较屎,也就一个毕设的水平,现在也就坦然了。。。
不过在做它的过程中收获还是很大的,最直接的体现就是对于“驱动学习”的理解,比如当时对Unity的向量,角度旋转等等都不会时,一点点去看文档,看帖子论坛,查Google。这样学习比直接看书看视频来的深刻的多。
扯了好多废话。。。最后想说的就是谢谢大家的支持!
Android端和Unity端代码都放在Github上了:https://github.com/a396901990/3D_Sphere/tree/feature/Voice_Weather_3D_Sphere
3D语音天气球(源码分享)——完结篇的更多相关文章
-
3D语音天气球(源代码分享)——通过天气服务动态创建3D球
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 这个项目准备分四部分介绍: 一:创建可旋转的"3D球":3 ...
-
3D语音天气球(源码分享)——在Unity中使用Android语音服务
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 这个项目准备分四部分介绍: 一:创建可旋转的"3D球":3 ...
-
3D语音天气球(源码分享)——通过天气服务动态创建3D球
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 这个项目准备分四部分介绍: 一:创建可旋转的"3D球":3 ...
-
3D语音天气球(源码分享)——创建可旋转的3D球
开篇废话: 在9月份时参加了一个网站的比赛,比赛的题目是需要使用第三方平台提供的服务做出创意的作品. 于是我选择使用语音服务,天气服务,Unity3D,Android来制作一个3D语音天气预报,我给它 ...
-
微信小程序——智能小秘“遥知之”源码分享(语义理解基于olami)
微信小程序智能生活小秘书开发详解 >>>>>>>>>>>>>>>>>>>>> ...
-
支持语音识别、自然语言理解的微信小程序(“遥知之”智能小秘)完整源码分享
记录自己搭建https的silk录音文件语音识别服务的调用过程,所有代码可在文中找链接打包下载 >>>>>>>>>>>>> ...
-
推荐!Html5精品效果源码分享
一直在看别人的汇总,看到了一些不错的关于 HTML5内容的源码,我也汇总下分享出来,好东西需要共享!希望可以帮到需要的朋友. 1.劲爆分享:HTML5动感的火焰燃烧动画特效 这又是一款基于HTML5的 ...
-
全方位深度剖析PHP7底层源码(已完结)
第1章 课程介绍本章主要介绍课程要讲的知识点,以及课程要求等. 第2章 PHP7的新特性本章主要介绍PHP7的新特性,做基准测试,与PHP5对比验证PHP7的性能提升程度,引出对PHP7源码学习的必要 ...
-
BAT资深工程师 由浅入深分析 Tp5&;Tp6底层源码 - 分享
BAT资深工程师由浅入深分析Tp5&Tp6底层源码 第1章 课程简介 本章主要让大家知道本套课程的主线, 导学内容,如何学习源码等,看完本章要让小伙伴觉得这个是必须要掌握的,并且对加薪有很大的 ...
随机推荐
-
GOAndroid的安装和配置
android环境的配置还是比较复杂的,特别对于我这样一直使用mfc的程序员来说,有很多观念上需要转变.好在配置成功后就能够不断复用,那么这样的问题值得整理出来 一.安装jdk 二.解压adt-bun ...
-
BFC与CFC
1.在创建了 Block Formatting Context 的元素中,其子元素按文档流一个接一个地放置.垂直方向上他们的起点是一个包含块的顶部,两个相邻的元素之间的垂直距离取决于 ‘margin’ ...
-
sqlite锁的机制
 reserved state 进入reserved state以后,sqlite可以修改数据库中的内容,不过把修改以后的内容写到pager的缓存里,大小由page cache指定. 进入这个状态以 ...
-
php 文件和表单内容一起上传
<?php $filename = $_POST['filename']; $explain = $_POST['explain']; $upfile = $_FILES['upfile']; ...
-
LeetCode Number of Islands 岛的数量(DFS,BFS)
题意:0代表水,1代表陆地,那么被水围起来的就是岛了,给一个01矩阵,问有多少个岛? 思路:DFS还是比较短,实现了一下.如果一个点已经被遍历过了,那就将其置为0就行了,不要去搜0的. class S ...
-
[转]Erlang不能错过的盛宴
Erlang不能错过的盛宴 (快步进入Erlang的世界) 作者:成立涛 (litaocheng@gmail.com) 作为程序员,我们曾经闻听很多“业界动态”,“技术革新”,曾经接触很多“高手箴言” ...
-
js判断用户进入设备代码
var system ={ win : false, mac : false, xll : false }; //检测平台 var p = navigator.platform; system.win ...
-
python 解析 配置文件
资料: https://docs.python.org/3/library/configparser.html 环境 python 3.4.4 RawConfigParser方式 example.cf ...
-
centos 6.4从源码安装mysql 5.6笔记
上周在安装mysql时遇到了些许麻烦,今天整理下. 在代码目录建立obj文件夹. 在obj目录下,执行cmake .. -DXXX // XXX表示一些参数,详见http://dev.mysql.c ...
-
凡客副总裁被曝离职:或因IPO受阻|凡客|王春焕|离职_互联网_新浪科技_新浪网
凡客副总裁被曝离职:或因IPO受阻|凡客|王春焕|离职_互联网_新浪科技_新浪网 凡客副总裁被曝离职:或因IPO受阻 2013年05月07日 00:56 每日经济新闻 我有话说 每经 ...