CentOS下用crontab设置自动重启MySQL计划

博客总有机器人发垃圾评论,用了一种验证码插件,不灵,今天换成了CaptchaBank的插件,不知道实际效果如何,测试几天看看结果,帮他们做了下本地化翻译,用wordpress的再用这个插件就有中文版用啦.

服务器上用的MySQL总自动停止工作,没查到原因,干脆建个计划让它自己重生.
是CentOS系统,没有crontab这个计划任务服务,在系统命令行上使用下面这两条命令安装crontabs,第一个vixie-cron主程序包,安装它后,系统一般会自动帮你装好crontabs软件包,即第二条命令可以忽略,具体看是否安装成功再定.
继续阅读

系统唤醒后ReportCrash占用CPU过高

打开本子后感觉系统卡顿,看了下时间机器在更新备份,就没在意,备份好了还是卡顿.就看了下Activity Monitor,发现 ReportCrash占了大量CPU,这崩溃报告说明有进程异常崩溃,查了一下系统日志.

$ tail -F /var/log/system.log
Jun  4 10:28:34 Xiaokes-RMBP com.apple.xpc.launchd[1] (com.apple.auditd[19470]): Endpoint has been activated through legacy launch(3) APIs. Please switch to XPC or bootstrap_check_in(): com.apple.auditd
Jun  4 10:28:43 Xiaokes-RMBP com.apple.xpc.launchd[1] (com.alipay.DispatcherService[19480]): Service exited due to signal: Trace/BPT trap: 5 sent by exc handler[0]
Jun  4 10:28:43 Xiaokes-RMBP com.apple.xpc.launchd[1] (com.alipay.DispatcherService): Service only ran for 2 seconds. Pushing respawn out by 8 seconds.
Jun  4 10:28:53 Xiaokes-RMBP com.apple.xpc.launchd[1] (com.alipay.DispatcherService[19487]): Service exited due to signal: Trace/BPT trap: 5 sent by exc handler[0]
Jun  4 10:28:53 Xiaokes-RMBP com.apple.xpc.launchd[1] (com.alipay.DispatcherService): Service only ran for 2 seconds. Pushing respawn out by 8 seconds.
Jun  4 10:29:03 Xiaokes-RMBP com.apple.xpc.launchd[1] (com.alipay.DispatcherService[19498]): Service exited due to signal: Trace/BPT trap: 5 sent by exc handler[0]
Jun  4 10:29:03 Xiaokes-RMBP com.apple.xpc.launchd[1] (com.alipay.DispatcherService): Service only ran for 2 seconds. Pushing respawn out by 8 seconds.
Jun  4 10:29:13 Xiaokes-RMBP com.apple.xpc.launchd[1] (com.alipay.DispatcherService[19505]): Service exited due to signal: Trace/BPT trap: 5 sent by exc handler[0]
<!--more-->

alipay?支付宝什么鬼…,回忆了一下,昨天在没有网络的情况下唤醒了本子,wangwang在运行,后来退出了,今天唤醒有网络,究竟为什么这样崩溃,不清楚.直接结束退出ReportCrash进程,不管用,因为进程还在崩溃崩溃就会触发它启动,那干掉它吧,反正没什么用.在termainal里执行:

launchctl unload -w /System/Library/LaunchAgents/com.apple.ReportCrash.plist
sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.ReportCrash.Root.plist

注:把unload改为load是重新启用ReportCrash.

搜了一下com.alipay.DispatcherService,网上说是检测新版本什么的,也有说收集用户隐私,把它禁用掉吧,大不了手动检查新版本.同样终端里输入:

sudo launchctl unload /Library/LaunchDaemons/com.alipay.DispatcherService.plist

mac下现在不需要阿里的输入控件了,所以把它全部清除,手动删除下面的这些文件,如果支付宝仍用,再安装也不迟:

sudo rm -rf /Library/Application\ Support/Alipay && rm -rf /Library/LaunchDaemons/com.alipay.DispatcherService.plist && rm -rf ~/Library/LaunchAgents/com.alipay.adaptor.plist && rm -rf ~/Library/LaunchAgents/com.alipay.refresher.plist && rm -rf ~/Library/Internet\ Plug-Ins/aliedit.plugin && rm -rf ~/Library/Internet\ Plug-Ins/npalicdo.plugin

我系统版本是10.12.5,前几天动手给本子换了电池,原来的电池起包了…起包了…

UNITY开发VR眼镜中文入门教程(8)

VR开发阅读列表

 

下面是VR开发的资源阅读列表,我们将定期更新,因为这是一个新的媒介,我们会让你及时的获取到最新的信息.

UNITY 中心

Unite VR 会议

Unity在全世界每年都会举行一次Unite会议(unity3d.com/unite),并且对许多主题进行很深度的讨论,包括虚拟现实.

这里是最近Unite会议有关虚拟现实的议题:

Unite 欧洲 2015

Unite 波士顿 2015

OCULUS

Oculus Connect

Oculus(https://www.oculus.com/en-us/connect/)每年举行一次会议,他们让来自世界各地的创意人员,设计师,工程师了解Oculus平台并推动虚拟现实发展.这是在Youtube上的开发者会议播放链接:

维基百科

其它

 

原文:http://unity3d.com/learn/tutorials/topics/virtual-reality

由 四角钱 (XK) 翻译,转载请注明来自 http://blog.1vr.cn

UNITY开发VR眼镜中文入门教程(7)

优化Unity中的VR

 

简介

 

为确保用户有极棒,无恶心的虚拟现实体验,而达到推荐帧率,优化是很关键的一个部分.因为现在VR硬件刚刚起步,所以要尽可能多的在硬件设备上进行测试.

VR相对于非VR项目的主要不同点就是它要为每只眼睛渲染一次图像,当你了解这一点,创建项目时围绕它进行相关优化将节省大量的开发时间.

手机上的配置远比不上桌面级电脑硬件,所以在移动设备上的VR做优化是至关重要的.

当然不要忘记要尽可能的优化程序代码,查看有关代码优化更详细的指导:”docs.unity3d.com/Manual/MobileOptimizationPracticalScriptingOptimizations.html”.

OCULUS 资源

 

在Oculus网站上有大量的资源文档,非常值得你去看:

https://developer.oculus.com/documentation/

http://static.oculus.com/sdk-downloads/documents/Oculus_Best_Practices_Guide.pdf

https://developer.oculus.com/blog/squeezing-performance-out-of-your-unity-gear-vr-game/

https://developer.oculus.com/blog/squeezing-performance-out-of-your-unity-gear-vr-game-continued/

UNITY 编辑器优化工具

 

在Unity中有一些很有用的工具和技术,有助于您优化VR游戏内容.

Profiler

 

Profiler可以帮你了解每一帧渲染的时间,并且将其拆分为CPU,渲染,内存,音频,物理和网格.通过使用Profiler检查性能消耗从而针对性的优化.更多关于Profiler的使用请参阅这些链接:

http://docs.unity3d.com/Manual/Profiler.html

https://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/profiler-overview

https://unity3d.com/learn/tutorials/modules/intermediate/editor/intro-to-profiler

Frame 调试器

 

Frame调试器步进式的查看每帧Draw Call,看每帧是如何构造出眼前的场景的,确定哪些可以优化,哪些是不需要的东西,这将大大有助于减少Draw Call.

更多Frame 调试器的信息请参阅下列链接:

http://docs.unity3d.com/Manual/FrameDebugger.html

https://unity3d.com/learn/tutorials/modules/intermediate/graphics/frame-debugger

VR优化原理

 

虽然优化是个巨大的门类,每个平台,每个需求都会有不同的优化方法.

现有的优化技术可以很好的用于VR项目开发优化

Geometry

移除VR中任何看不到的三角形,比如如果用户看不到后背,纳闷我们完全可以把角色模型后背的三角面和贴图删除优化掉.另外根据目标平台,试着添加一些细节纹理,比如视差贴图等,虽然这会影响到性能,但是也许它非常适合在特定的目标平台.

Overdraw

Overdraw视图让你可以了解什么对象被绘制在了另一个对象上面,这种无谓的渲染会浪费GPU渲染时间,通过场景视图中(docs.unity3d.com/Manual/ViewModes.html)开启Overdraw模式查看场景中的覆盖情况.

1_overdraw-menu

普通视图模式:

2_normal-shaded

Overdraw 模式:

3_overdraw

Level of Detail

Level Of Detail (LOD) 可以让你根据模型物体与相机的距离动态的切换物体三角形面数,只要你的模型距离相机有一定距离,LOD会显示一个低面数的模型来减少对硬件的负载,提升渲染性能.

4_lod0

 

Simplygon(https://www.assetstore.unity3d.com/en/#!/content/10144) 插件可以自动化处理模型的LOD.

Draw Call batching

尽可能的将Batch Draw Call,使用

Static Batching 和 Dynamic Batching会大大提高性能.详见Unity手册

Draw Call Batching(docs.unity3d.com/Manual/DrawCallBatching.html).

Lightmapping

减少动态光照使用,增加烘焙照明,避免实时光影,详见

avoid realtime shadows(https://twitter.com/ID_AA_Carmack/status/592385473894461441)和  Lighting and Rendering(unity3d.com/es/learn/tutorials/modules/beginner/graphics/lighting-and-rendering) .

Light Probes

Light probes (docs.unity3d.com/Manual/LightProbes.html) 可以让烘焙光照的场景中动态对象的动态光照实现出来,这个运算很快,但是经常会有很大视觉效果提升.

Reflection Probes

Reflection probes (docs.unity3d.com/Manual/class-ReflectionProbe.html) 会根据场景位置将环境贴图存储于Cubemaps中,来增加环境反射贴图的真实性,但是实时反射在VR中会很慢.

Occlusion Culling

Occlusion Culling (docs.unity3d.com/Manual/OcclusionCulling.html)能禁止对看不到的场景渲染,例如一扇门关闭时,我们不想让门那边的另外房间渲染,就可以使用它.使用它可以显著提升性能.

没有进行遮挡裁切的示例:

6_occlusionfrustumculling

使用了遮挡裁切的示例:

7_occlusionfullculling

Anti-Aliasing

Anti-Aliasing 抗锯齿在VR中是很有用的,因为它有助于平滑图像,减少锯齿状边缘.如果你是用了 Forward Rendering, 你可以在画质设置中起启用MSAA(docs.unity3d.com/Manual/class-QualitySettings.html),你也应该在Gear VR中启用它来提升效果.

在Deferred Rendering时,你可以用图像脚本(docs.unity3d.com/420/Documentation/Components/script-AntialiasingAsPostEffect.html)或看论坛上启用SMAA的例子:”https://github.com/Chman/SMAA-Unity”.

Textures

一般情况下,可以用  Texture Atlasing (https://en.wikipedia.org/wiki/Texture_atlas)把场景中的贴图整合起来以尽可能的减少材质球数量.

我们也可以用MeshBaker (https://www.assetstore.unity3d.com/en/#!/content/5017)简化加快这一优化过程.Meshbaker可以用来烘焙纹理,网格,材质来优化游戏性能.

详见下面链接:

用MeshBaker的视频教程(https://www.youtube.com/watch?v=9vZ8SfXOlpI)

Oculus渲染文档:(https://developer.oculus.com/documentation/intro-vr/latest/concepts/bp_app_rendering/)

Shaders

尽量使用Basic着色器,在Gear VR中,推荐使用”Mobile > Unlit (Supports Lightmap) shader”.

Fullscreen Effects

Fullscreen effects(docs.unity3d.com/Manual/comp-ImageEffects.html)是非常消耗资源的,在GearVR上要尽可能避免使用.

Quality Settings

Quality Settings(docs.unity3d.com/Manual/class-QualitySettings.html)决定项目中画质的各个方面,改变这些属性可以提高游戏性能,但是会牺牲视觉效果.

RenderScale

VRSettings.renderScale(docs.unity3d.com/ScriptReference/VR.VRSettings-renderScale.html)渲染比将改变图像锐度,可以用来提高画质或者降低画质提升帧率.

Asynchronous Loading

如果把游戏拆分成若干个单独的场景,在加载时,为了避免画面冻结导致恶心不适感,建议使用异步加载来载入下一个场景数据:SceneManager.LoadSceneAsync(docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadSceneAsync.html)

VR示例中的优化技术

 

我们在示例项目中做了一些列优化确保示例项目在GearVR和DK2上都能有很好的性能.我们选用了一种低面艺术风格,并只使用了几个基本颜色,使得项目能很流畅有很美丽.

我们使用了Forward Rendering,并在Edit > Project Settings > Quality Settings 启用了4x MSAA.

8_msaa-qualitysettings

让我们快速的看一下场景中用到的优化技术:

Menu 场景优化

场景中我们使用低模资源,没有用实时光照,给菜单面板用了名为SeparableAlpha的自定义着色器,它允许单独设置透明通道,避免每一帧都用这个菜单自己的透明通道,减少了贴图文件大小.

Flyer场景优化

我们使用了雾效确保小行星等物体很融合的进入到场景,并缩短了视距,减少了渲染物体数量.小行星用了很少的面,所以它可以用 Dynamic Batching,同样也创建了一个对象池(unity3d.com/es/learn/tutorials/modules/beginner/live-training-archive/object-pooling)处理激光,小行星物体和圆环,减少较耗费资源的实例化(docs.unity3d.com/ScriptReference/Object.Instantiate.html)的使用.

在飞船上用了一个很小的颜色纹理用第二UV通道给Detail Map.这会节省贴图尺寸.

Maze 场景优化

迷宫场景使用了烘焙光照贴图,特别是在移动设备上运行它会有很流畅的效果,否则它将是一个很简单的没有实时光照没有什么效果的场景.

Shooter180和Shooter360场景优化

和其它游戏一样,我们用了低模风格以及对象池(unity3d.com/es/learn/tutorials/modules/beginner/live-training-archive/object-pooling),同时对低顶点数的模型使用Dynamic Batching(docs.unity3d.com/Manual/DrawCallBatching.html).

更多优化细节可以到Oculus网站查看:

https://developer.oculus.com/documentation/

http://static.oculus.com/sdk-downloads/documents/Oculus_Best_Practices_Guide.pdf

https://developer.oculus.com/blog/squeezing-performance-out-of-your-unity-gear-vr-game/

https://developer.oculus.com/blog/squeezing-performance-out-of-your-unity-gear-vr-game-continued/


原文:http://unity3d.com/learn/tutorials/topics/virtual-reality

由 四角钱 (XK) 翻译,转载请注明来自 http://blog.1vr.cn

UNITY开发VR眼镜中文入门教程(6)

部署发布VR项目

 

在这篇教程里我们将讨论部署发布到DK2和Gear VR这两个平台.在将来会有更多的虚拟现实硬件平台,我们会持续的更新教程和支持这些平台部署发布.

部署发布为OCULUS DK2

 

在Unity中可以通过播放很方便的测试项目在DK2设备上的效果,我们也可以随时部署发布项目做更实际的测试.

先确保DK2正常1_buildsettings

连接和工作,将当前发布平台选为Standalone.

 

确保你制作的场景抖包含在Build列表中,单击”Build”创建一个可执行文件和一个内容支持文件夹.

像平时运行其它Unity应用一下执行它,就可以在DK2中看到效果了.如果运行文件有问题,可以试试命令行”-vrmode”的启动VR模式,

像下面这样:

BuildName.exe -vrmode oculus

Oculus网站上有更多关于部署到DK2的信息:”https://developer.oculus.com/documentation/game-engines/latest/concepts/unity-build/#unity-build

部署发布为GEAR VR

 

要部署为Gear VR设备用的VR项目,我们需要把Unity和你的手机建立成安卓开发环境,记住,消费班Gear VR只支持三星 Galaxy S6, S6 Edge, S6 Edge+, Note 5手机:

1设置Unity开发安卓的项目(docs.unity3d.com/Manual/android-sdksetup.html).

2安装手机USB驱动(https://developer.android.com/tools/extras/oem-usb.html).

按照这个方法(developer.android.com/tools/device.html#device-developer-options)激活手机开发模式并启用USB调试.

最后,跟着Oculus网站上”Buliding for GearVR”(https://developer.oculus.com/documentation/game-engines/latest/concepts/unity-build-android/)教程部署项目.

注意,这里我们需要用Assets/Plugins/Android/assets/以及里面的OSIG(https://developer.oculus.com/osig/)文件,在VR示例中包含了这个目录和文件,请查看Readme.txt.

如果你不把发布的GearVR内容发布到Oculus商店,而又要在真实的设备上审视,你需要为每台设备进行OSIG.

发布到Oculus Store

 

要把你的项目发布到Oculus Store,请看Oculus网站上的这篇文档:”https://developer.oculus.com/documentation/publish/latest/

发布到Oculus Share

 

2_oculusshare

Oculus Share 可以让你分享你的DK2游戏到论坛社区,让全世界的玩家试玩并得到反馈,这是一个伟大的分发方式和获得宝贵建议的渠道.

 

要发布到Oculus Share,请阅读他们的提交文档:”https://share.oculus.com/”


 

原文:http://unity3d.com/learn/tutorials/topics/virtual-reality

由 四角钱 (XK) 翻译,转载请注明来自 http://blog.1vr.cn

UNITY开发VR眼镜中文入门教程(5)

VR中的运动

 

除了达到帧率的要求外,在VR中运动也是个要素,在策划游戏的阶段就要好好思考这个问题,如果选择的运动解决方案会引起眩晕甚至恶心,将严重影响你的项目.

VR中的恶心和舒适

 

玩游戏感觉恶心,也被称为VR病(https://en.wikipedia.org/wiki/Virtual_reality_sickness),这是因为在真实的世界中玩家的身体是固定的,当他们以虚拟的视角去查看移动的虚拟环境,就很可能让身体感受到不适.

一般情况下,应避免移动相机,除非是跟随用户运动而动,简单来说头戴式显示设备把虚拟的信号从眼睛或者耳朵传递给玩家,使得玩家认为它是真实的,比如场景中不停的旋转,玩家的大脑会认为身体真的在旋转,这是人的神经系统就会做出排斥反应,最后导致眩晕,恶心等不舒适的情况.不过也有例外,所以要多实验和测试,尽可能的让多样的玩家来感受,找到一个权衡的舒适的操控方案.如果玩家的身体能实际跟随相机的移动,那么会极大的减弱不适感,比如有空间跟踪技术的HTC Vive.但这仍然依赖我们要为用户开发没有真实的移动玩家环境,迷惑视觉听觉找一个平衡点.

目前位置静止的VR体验是最舒适的,通常只需要用户原地不动,通过旋转或者转头来操作游戏,VR示例中的180度射击及360度射击就是这种风格的游戏.

VR中的第一人称射击游戏

传统的鼠标和WSAD或游戏手柄控制的第一人称游戏经常引起恶心不适感,所以最好避免这种操作.如果你决定要开发第一人称控制的游戏,要请尽可能多的人试玩游戏并反馈给你改进的建议,绝对要禁用使用点头等快速移动视角的动作.我们捕捉头部的旋转赋给相机(https://twitter.com/id_aa_carmack/status/553238861267353600).可以看CameraOrbit组件学习相机淡出渐入及捕捉旋转.

如果要执行运动操作,我们建议给玩家一个恒定的静态视觉参考体,比如驾驶舱,客舱,汽车内部,可以参考这几个游戏:Radial-G(radial-g.com/), Lunar Flight(www.shovsoft.com/lunarflight/), and Titans of Space(www.titansofspacevr.com/).

在VR中用淡出/闪烁转换场景

在虚拟场景快速跳转相机位置较流行的方法是用淡出,即要跳转位置前渐渐的将画面黑掉,然后将相机移动到所需的位置或场景再快速的淡出黑色显示出虚拟场景.另外一种方法稍复杂一些,有点想相机快门,用两个黑色的挡板开合作为遮挡来快速跳转相机位置,Tom Forsyth在Oculus2014大会视频上有介绍这个方式,可以翻墙看看这个视频:https://www.youtube.com/watch?v=addUnJpjjv4&feature=youtu.be&t=40m5s

在VR示例场景中运动

 

正如我们上面说过的,我们不要直接在Unity中移动相机位置,相反我们必须给相机设定一个父对象,并把对相机的移动或旋转应用到父对象.

2_cameracontainer

我们想确保用户有一个舒适的VR体验,在我们提供的VR示例中,大多数场景都不包含运动的相机,而只去让迷宫的沙盒及飞行器运动.早VR这一新媒介早期阶段我们希望给用户一个积极向好的期望,才能有利于VR事业的发展.

Flyer游戏中的运动

 

Flyer示例中的相机从菜单消失后直接以恒定的速度运动着,玩家并不经历从静止到加速的过程,静止到加速的过程通畅会引起恶心不适感.

3_flyervideo01

随着从飞机旁边略过的圆圈以及移动的小行星等效果,可以给人一种移动的感觉.同时也允许环视周围,因为能看到周围所以能减少恶心不适感.

可以用类似的效果实现固定相机,并移动一切相对于相机的对象.

Maze – VR中的桌游

 

迷宫这个例子提供了俯视风格的桌游效果,看起来就像把相机位置固定,但是让迷宫沙盘旋转起来.

4_mazerotatevideo

然而我们用了光照贴图和导航网格,它们被标记成了静态,所以我们不能去旋转迷宫沙盘,相反,我们要改变成如下的层级:

5_maze-camera-hierarchy

VROrbitCamera 对象被放置在迷宫沙盘的中心,MazeUnityLogo 物体在迷宫沙盘的一边,MainCamera在另一边.

6_mazerotatesceneview

我们旋转VROrbitCamera对象,因为它的旋转中心在迷宫中心,静止的Unity Logo作为标识参考,让我们认为是沙盘在旋转.

完成这个旋转,VROrbitCamera有两个组件:

CameraOrbit处理旋转

Rigidbody让我们用来改变质量和阻尼等参数

7_cameraorbit

CameraOrbit 组件有三种旋转样式选项:

8_cameraorbit-enum

Smooth – 我们用了Smooth这个选项来让旋转变得顺畅,慢慢降低滑动速度,改变旋转增量和刚体的特性实现对相机运动速度,阻尼的调整. Step – 有时候我们需要立刻旋转相机,去掉中间插值过程,也就是我们滑动多少,相机就转多少,完全同步的旋转.

Step With Fade – 和Step类似,但它用了一个非常快的淡出,当滑动触摸板时,画面黑掉,相机在后面快速的移动到对应的位置,这样会减少恶心不适感.改变Rotation Fade Duration会改变淡出持续的时间.

9_stepwithfadevideo

考虑到VR正在快速发展中,要移动,又要避免恶心不适感,我们强烈建议您认真阅读Oculus的手册关于”Simulator Sickness(https://developer.oculus.com/documentation/intro-vr/latest/concepts/bp_app_simulator_sickness/)” 和”Motion(https://developer.oculus.com/documentation/intro-vr/latest/concepts/bp_app_motion/)”等深入这些知识的文章.

在180/360度射击游戏中的运动

我们另外两个示例场景演示了简单的使用跟踪旋转头部控制相机运动以及简单的射击输入.周围环境是静止的,玩家的目标就是简单的凝视要射击的物体并射击.

这些场景可以说是舒适的,是最不宜引起恶心不适感的.

现在你应该有了一个基本了解为什么要这么处理场景中的运动,也可以阅读这些主题进一步学习:


原文:http://unity3d.com/learn/tutorials/topics/virtual-reality

由 四角钱 (XK) 翻译,转载请注明来自 http://blog.1vr.cn

UNITY开发VR眼镜中文入门教程(4)

VR的用户界面

 

在设计VR的用户界面时,传统的UI设计方案可能会出现一些问题,现在我们来讨论和解决VR中制作用户界面的问题.

UI的分辨率和外观

DK2的分辨率是1920 x 1080 (960 x 1080 每只眼), Gear VR 是 2560 x 1440 (1280 x 1440 每只眼),这意味着在屏幕上能看得清任何元素的像素.

特别要注意的是用户界面元素在屏幕上的大小,我们推荐使用更大的字体或者加粗字体以及避免用很细的线设计界面.

UI类型

 

非故事类

在非VR项目中,UI通常覆盖在屏幕上显示如血条等信息,我们称之为HUD(抬头显示器).这就是所谓的非故事类界面,它不真实存在,但它有利于玩家查看游戏中的信息.

这个词同样用在电影中作为非故事的声音,如电影或电视的背景音乐.

在Unity中添加HUD样式的非故事类UI是更改相机的UI Canvas渲染模式为Screen Space – Overlay或 Screen Space实现的.

 

1_screenspacecamera

2_screenspaceoverlay

而VR中通常不用这种方法,我们眼睛无法集中在很近的一个点上,而且Screen Space-Overlay是不支持的.

空间UI

相反我们通常需要在场景中呈现我们的UI,把相机改成World Space Canvas渲染模式.这将让我们的眼睛能聚焦到UI上,被称为空间界面(Spatial UI)

3_worldspace

在场景空间中放置UI也需要一些思考设计.太靠近用户会引起视觉疲劳,太远又会让用户觉得视点聚焦在地平线上,不过放置远一些是适合在户外场景中,小房间中就不适合了.还需要根据需求动态的缩放用户界面的大小.

最好在一个相对舒适的阅读距离上显示用户界面,并相应的调整它的尺寸.在Menu场景中可以看这个例子:它在面前几米远的距离,文字和图像都很大,很易于查看.

如果在某些特定距离上进行空间用户界面显示,可能会发现界面与游戏对象发生了穿插,那么请看我们前面将的如何避免穿插或直接使用VR示例中的着色器.或者使用Text的着色器.

许多开发者最初会将用户界面附加到相机上,所以当用户移动视角时,界面会始终保持在视野中的一个固定位置,这如果用来做准心是很有用的,但如果是其他较大的界面元素就会影响到玩家的观察视线,并可能导致用户恶心不适感.在360度射击游戏示例中,界面会在视图中做短暂的停留,便于用户熟悉场景环境,避免遮挡用户视野.

4_360menu

VR技术为我们提供了一个模拟360度真实环境的机会,有时我们可以需要显示给用户让用户去寻找一个特定的方向.在示例场景中,我们在场景中使用了一些箭头来提示用户找到正确的方向,如果方向在正常范围内,这淡出箭头提醒.

可以用GUIArrows预置,它们的用途就是比较头部的角度,如果头部角度超过预设角度(GUIArrows脚本里Show Angle)时变会淡入提醒用户往正确的方向看.

5_guiarrows-component

6_180shooter01

 

故事界面

空间界面的另一种实现方式就是将场景中的元素现实给用户.这可能是墙上的一个挂钟,电视机,显示器,手机,或者一个带有全息显示的未来科技枪.这就是故事UI,我们可以看下示例Flyer场景的飞船界面或者射击游戏的枪的界面.

7_diegetic-ship

8_diegetic-gun

虽然这不是严格意义上的故事界面,但在能让用户能很直观的得到游戏中想要了解的信息.

用户界面开发的深入阅读

深入分析这些类型的界面可以阅读本文Gamasutra(www.gamasutra.com/view/feature/4286/game_ui_discoveries_what_players_.php).

用户界面交互

 

利用前面VR交互中的VREyeRaycasterVRInput, 和VRInteractiveItem我们可以创建一个类来处理用户界面的交互.

在Maze场景中有一个特定的开关作为用户界面交互,在每个游戏开始前都有个阅读说明界面,可查看Oculus博客上的“Unity’s UI System in VR”,那里还提供了示例代码.

VR示例中的用户界面

 

让我们看看VR示例中用到了哪些技术制作用户界面

Menu

9_mainmenu

在场景中自定义了弯曲网格来作为用户界面.

Flyer

游戏介绍和游戏结束界面都是在世界空间里的静态界面.

10_flyer-intro-ui

然而,我们把一些重要信息放在在了飞船上,作为故事界面能让玩家随时查看到是很有意义的.

11_flyer-ui-facing_camera

这个UI会始终旋转面向镜头,这样可以避免较大的倾斜角度影响用户观看阅读界面.

Maze

在Maze场景,我们同样用世界空间里的静态界面做了游戏介绍和游戏结束画面.:

12_maze-intro

当触控滑动可用时,场景中的用户界面也被用来提示玩家进行交互.

13_maze-lookandhold

Shooter 180 (Target Gallery)

用世界空间里的静态界面做了游戏介绍和游戏结束画面:

14_target_gallery_intro

正如上面所说的,在枪上用了故事界面来显示分数和时间:

15_diegetic-gun

Shooter 360 (Target Arena)

最后,在这场景中用了空间用户界面,但有轻微扭动,当玩家环顾四周时,我们在移动用户界面中做了个短暂延迟,以满足玩家自由的环顾四周.

16_targetarena-title

同样,枪上使用了固定的用户界面:

17_targetarena-gunui

VR中为文字做抗锯齿

在场景中使用Canvas Scaler,UI就会有 “Reference Pixels Per Unit”设置项,默认为1,然后改变“Dynamic Pixels Per Unit”,知道看到文本略微柔化的边缘.在这里可以看到”Dynamic Pixels Per Unit”被设置为1.75和设置为3时的差异.设置为3时,边缘较硬,设置为1.75时,边缘会有点柔化.

18_ppu-3

19_ppu-1.75

我们现在应该可以使用 VREyeRaycasterVRInput, 和  VRInteractiveItem来创建基本的交互界面了.


 

原文:http://unity3d.com/learn/tutorials/topics/virtual-reality

由 四角钱 (XK) 翻译,转载请注明来自 http://blog.1vr.cn

UNITY开发VR眼镜中文入门教程(3)

VR中的交互

 

概述

 

在VR中我们经常需要激活用户正在看的对象,比如VRSamples中,我们内建了一个简单的可扩展的,轻量级用户交互系统框架.它包括了三个主要脚本::VREyeRaycaster, VRInput, 和 VRInteractiveItem,下面对它们进行简要的说明.

VREyeRaycaster

 

1_vreyeraycaster

这个脚本需要放置在Main Camera.在每个Update()中脚本会用 Physics.Raycast去射线给任何看到的碰撞器.当然也可以通过层(docs.unity3d.com/Manual/Layers.html)的设置做排除.也可以将所有需要互动的对象放到一个单独的层中来优化性能.

如果射线投射到了一个碰撞器,这个脚本将去找这个游戏对象上的VRInteractiveItem组件.

VRInteractiveItem interactible = hit.collider.GetComponent<VRInteractiveItem>();    //试图获得被射对象上的VRInteractiveItem组件

因此我们可以判断用户是否在看一个物体或者不再看这个物体,通过这个状态的获取再去做相应的动作.

VRInput

 

2_vrinput

VRInput 是一个简单的判断在GearVR设备中发生的单击,双击,滑动的类或DK2在PC做同样的输入.我们可以直接从VRInput中获取输入事件:

public event Action<SwipeDirection> OnSwipe;                //在每一帧中滑动或没有滑动事件时调用
public event Action OnClick;                                // 当Fire1键被触发且不是双击时调用.
public event Action OnDown;                                 // 在Fire1被按下时调用
public event Action OnUp;                                   // 在Fire1被松开时调用.
public event Action OnDoubleClick;                          // 当检测到双击事件时被调用.
public event Action OnCancel;                               // 当Cancel被触发时调用.

更多输入事件的信息请查阅(unity3d.com/ru/learn/tutorials/modules/intermediate/scripting/events).

VRInteractiveItem

 

这个组件可以添加到VR中任何希望用户交互的游戏物体上.它需要物体上附加一个碰撞器组件.

在物体上我们可以获得六种事件:

public event Action OnOver;             //当目光移到这个物体上时触发.
public event Action OnOut;              //当目光已到这个物体上时触发.
public event Action OnClick;            //当这个物体被凝视并且有点击事件时触发.
public event Action OnDoubleClick;      //当这个物体被凝视并且有双击事件时被触发.
public event Action OnUp;               //当这个物体被凝视并且松开Fire1键时被触发.
public event Action OnDown;             // 当这个物体被凝视并且按下Fire1键时被触发.

以及一个布尔值来获得当前物体是否被凝视:

public bool IsOver
{
get{ return m_IsOver;} //当前这个物体被凝视吗?
}

 

我们可以创建自己的脚本来对这些事件做出相应的反应.下面这个简单的例子演示这些事件的使用:

using UnityEngine;
using VRStandardAssets.Utils;
namespace VRStandardAssets.Examples
{
// 这是一个与物体交互的简单例子
// 被用来处理物体响应输入事件
public class ExampleInteractiveItem : MonoBehaviour
{
[SerializeField] private Material m_NormalMaterial;
[SerializeField] private Material m_OverMaterial;
[SerializeField] private Material m_ClickedMaterial;
[SerializeField] private Material m_DoubleClickedMaterial;
[SerializeField] private VRInteractiveItem m_InteractiveItem;
[SerializeField] private Renderer m_Renderer;
private void Awake ()
{
m_Renderer.material = m_NormalMaterial;
}
private void OnEnable()
{
m_InteractiveItem.OnOver += HandleOver;
m_InteractiveItem.OnOut += HandleOut;
m_InteractiveItem.OnClick += HandleClick;
m_InteractiveItem.OnDoubleClick += HandleDoubleClick;
}
private void OnDisable()
{
m_InteractiveItem.OnOver -= HandleOver;
m_InteractiveItem.OnOut -= HandleOut;
m_InteractiveItem.OnClick -= HandleClick;
m_InteractiveItem.OnDoubleClick -= HandleDoubleClick;
}
//处理当前物体
private void HandleOver()
{
Debug.Log("Show over state");
m_Renderer.material = m_OverMaterial;
}
//处理非当前物体
private void HandleOut()
{
Debug.Log("Show out state");
m_Renderer.material = m_NormalMaterial;
}
//处理单击事件
private void HandleClick()
{
Debug.Log("Show click state");
m_Renderer.material = m_ClickedMaterial;
}
//处理双击事件
private void HandleDoubleClick()
{
Debug.Log("Show double click");
m_Renderer.material = m_DoubleClickedMaterial;
}
}
}

 

关于这段脚本的完整示例请查看VR示例的VRSampleScenes/Scenes/Examples/InteractiveItem场景

环状选择框(SelectionRadial) 和 滑块选择条(SelectionSlider)

 

我们做个环状选择框及滑块选择条,让用户凝视物体并按住Fire1键实现”确定”命令的交互:

3_selectionradial

4_selectionslider

 

随着输入的持续,选择栏进行填充,并产生OnSelectionComplete 或 被填满时OnBarFilled 事件,相关代码可以在 electionRadial.cs 和SelectionSlider.cs中找到,有很详尽的注释.从用户体验上来讲让用户知道他们在做什么,能准确的确定或取消与虚拟世界的交互.

VR示例中的交互

 

现在让我们来看VR示例中包含的交互功能,了解它们是如何实现的.

Menu场景的交互

5_menu

每项菜单都有好几个组件,这里我们重点看 MenuButtonVRInteractiveItem, 和 Mesh Collider.

 

MenuButton组件用来获得在VRInteractiveItem 组件上的OnOver 和 OnOut事件.所以当视野在菜单项时,选择条将填充出现,目光不在菜单项时,选择条减小填充.当选择条完全填满并按住Fire1时将出现环状选择框开始填充:

6_selectionradial

同样的在环状选择条填满时也有OnSelectionComplete 事件,然后HandleSelectionComplete被调用,接着相机镜头淡出后载入选择的关卡.

private void OnEnable ()
{
m_InteractiveItem.OnOver += HandleOver;
m_InteractiveItem.OnOut += HandleOut;
m_SelectionRadial.OnSelectionComplete += HandleSelectionComplete;
}
private void OnDisable ()
{
m_InteractiveItem.OnOver -= HandleOver;
m_InteractiveItem.OnOut -= HandleOut;
m_SelectionRadial.OnSelectionComplete -= HandleSelectionComplete;
}
private void HandleOver()
{
// 当用户正在凝视场景菜单项时,显示环状选择条.
m_SelectionRadial.Show();
m_GazeOver = true;
}
private void HandleOut()
{
// 当用户不在凝视场景菜单项时,隐藏环状选择条.
m_SelectionRadial.Hide();
m_GazeOver = false;
}
private void HandleSelectionComplete()
{
// 当用户凝视凝视菜单项并且环状选择条填充满时激活按钮.
if(m_GazeOver)
StartCoroutine (ActivateButton());
}
private IEnumerator ActivateButton()
{
// 如果相机已经淡出则忽略
if (m_CameraFade.IsFading)
yield break;
// 在有任何按钮选择事件发生时调去它
if (OnButtonSelected != null)
OnButtonSelected(this);
// 等待相机的淡出
yield return StartCoroutine(m_CameraFade.BeginFadeOut(true));
// 载入关卡
SceneManager.LoadScene(m_SceneToLoad, LoadSceneMode.Single);
}

让我们看看环状选择框的示例,注意视野截图中心的粉红圆点.

7_radial-off

当用户凝视菜单项时可以看到还未开始填充的环状选择框.

8_radial-on

当用户继续凝视这个菜单项并且按下Fire1键,会看到环状选择框开始填充

9_radial-filling

我们建议让环状选择框和滑块选择条的时间一致,提升用户体验,以帮助用户更快的使用VR这种新媒介.

Maze场景中的交互

 

Maze游戏提供了一个桌游形式互动的例子,通过引导角色到出口再通过开关阻止炮塔的攻击(剧透了!!).

当选择一个角色,这个角色会出现一条即将行走的路线,我们可以通过滑动触控板,按下光标键或用游戏手柄的左摇杆来旋转视图.

10_maze-scene-overview

MazeFloor 物体用一个MeshCollider 和VRInteractiveItem 组件来实现交互:

11_mazefloor

MazeCourse 游戏物体作为父物体,包含了 MazeFloor 和 MazeWalls游戏对象,用于构成迷宫的布局.

12_mazecourse

有一个MazeTargetSetting 脚本在MazeCourse上并引用了MazeFloor上的VRInteractiveItem 组件.

13_mazetargetsetting

MazeTargetSetting 获取到VRInteractiveItem上的OnDoubleClick事件, 然后将调用OnTargetSet 事件,通过转换作为Transform的参数:

public event Action<Transform> OnTargetSet;                     // 当目的地设定后触发
private void OnEnable()
{
m_InteractiveItem.OnDoubleClick += HandleDoubleClick;
}
private void OnDisable()
{
m_InteractiveItem.OnDoubleClick -= HandleDoubleClick;
}
private void HandleDoubleClick()
{
// 一旦目标设定启用及获取了OnTargetSet事件就执行这个方法.
if (m_Active && OnTargetSet != null)
OnTargetSet (m_Reticle.ReticleTransform);
}

无论MazeCharacter游戏对象上的Player组件还是在MazeDestinationMarkerGUI游戏对象上的DestinationMarker组件获取到这个事件,都会做出相应的反应.

角色用导航网个系统去在迷宫中寻路.Player组件中HandleSetTarget函数被设置成 Nav Mesh Agent(docs.unity3d.com/Manual/nav-CreateNavMeshAgent.html)去响应变换位置,并更新绘制Agent的路线,让角色路径可视化:

private void HandleSetTarget(Transform target)
{
// 如果游戏没有结束则设定角色的AI和路径线
if (m_IsGameOver)
return;
m_AiCharacter.SetTarget(target.position);
m_AgentTrail.SetDestination();
}

DestinationMarker 移动标识物到准星的Transform位置.

private void HandleTargetSet(Transform target)
{
// 当目标被设定就显示标识物
Show();
// 把准星目标位置赋予标识物的位置
transform.position = target.position;
// 播放音效.
m_MarkerMoveAudio.Play();
// 播放标识物的动画
m_Animator.Play(m_HashMazeNavMarkerAnimState, -1, 0.0f);
}

可以看到被标识物目的地的准星及所选角色的行动轨迹.

14_mazevideo02

迷宫中的触发开关也是VR中常用的交互例子.本文使用碰撞器以及VRInteractiveItemSelectionSlider类来实现.

15_selectionslider-inspector

如上图所示的要接受交互对象的脚本,SelectionSlider 脚本监听来自VRInteractiveItem 和 VRInput的事件:

private void OnEnable ()
{
m_VRInput.OnDown += HandleDown;
m_VRInput.OnUp += HandleUp;
m_InteractiveItem.OnOver += HandleOver;
m_InteractiveItem.OnOut += HandleOut;
}

Flyer场景中的交互

Flyer场景是一个有时间限制游戏,玩家引导太空中的飞船躲避小行星,用Fire1键射击小行星,穿越积分圈获得积分等等.这游戏有点像飞行俱乐部和星际火狐.

在互动方面,Flyer是非常简单的;使用FlyerLaserController获取VRInput中的OnDown事件发射激光射击:

private void OnEnable()
{
m_VRInput.OnDown += HandleDown;
}
private void HandleDown()
{
//如果游戏没有运行终止执行
if (!m_GameController.IsGameRunning)
return;
// 从任意位置发射激光束
SpawnLaser(m_LaserSpawnPosLeft);
SpawnLaser(m_LaserSpawnPosRight);
}

Shooter180 和 Shooter360场景中的交互(180度第一人称射击和360度守堡式射击)

 

VR示例中有两个目标射击游戏,有点近似X战警的场景画面,一个是180度的沿着隧道行走的第一视角射击游戏,另一个是原地360度守堡式的射击游戏.

射击游戏中每个生成的靶子都有个碰撞器,VRInteractiveItem 和 ShootingTarget.

16_shootingtargetobject

17_shootingtarget

 

ShootingTarget自己获取VRInteractiveItem上的OnDown事件来判断目标是否被击中.这种方法适合用与点射,如果是连发射击,我们需要用其它方案.

我们对游戏里的基本交互做了概述以及它们在VR示例中如何用的.现在我们来讨论如何用凝视作为准星.

凝视

 

在VR中监测用户视线是非常重要的,无论是允许用户与对象进行触发动画的交互还是向目标射击.请注意”凝视(GAZE)”这个术语,后面我们会经常提到.

大多数的头戴显示设备还不支持眼球跟踪,所以我们只能用头部的朝向来估计用户的目光朝向.如前面概述中说的,我们只需在相机中心发射条射线用射线检测目光凝视什么对象就可以了.当然,这意味着任何被检测的物体都必须有个碰撞器组件.

准星

 

一个准星用来显示用户视野中心,准星的样式可以是一个简单的点或者一个十字线,这取决于你项目的风格.

传统游戏中往往会使用十字线作为准星,在VR中做准星定位是有点复杂的:用户会将眼睛的焦点放在接近于相机的物体上,那么用户会看到两个准星,我们可以把手指放在眼前模拟聚焦效果,手指离眼睛越近,背景越模糊,反之亦然,这就是所谓的自愿复视(voluntary Diplopia(https://en.wikipedia.org/wiki/Diplopia#Voluntary)).

为了避免玩家看场景时由于焦点不同出现两个准星,我们需要将准星放在玩家看的对象的表面上.

如果单单去移动准星的位置,当距离远时,准星会变得很小,为了保证准星大小不变,我们需要根据它距离相机的距离去做缩放.

为了说明这个缩放,可以查看Examples/Reticle场景,它包含了不同距离和准星缩放的示例.

准星位于相机所观察到较近的一个物体上:

18_reticle-close

准星在一个较远的物体上

19_reticle-far

准星位于更远距离的位置:

20_reticle-distance

由于定位和缩放准星,所以用户会觉得准星无论距离多远都是相同的大小,当准星没有处于场景的某个对象上时,我们只需将准星放在预订的一个距离,这个距离取决于场景大小,比如一个室外环境,我们可以把准星放置在相机远一些,而在室内场景,可能让准星距离相机更近一些.

在游戏对象上绘制准星

 

如果在物体相同位置绘制准星,那么准星可能会与游戏对象发生穿插问题:

21_unity-reticle-clipped

要解决这个问题,我们要确保准星渲染于场景中所有物体之上,这里我们用到基于Unity内置着色器”UI/Unlit/Text”改写名为UIOverlay.shader着色器.为材质选择着色器时会在”UI/Overlay”下看到它.

本场景中有两个UI控件和文本,将把它画在场景中其它物体之上:

22_unity-reticle-noclipped

对齐准星到场景中的物体

最后,我们想实现准星的旋转匹配到被附加的对象法线,我们可以用 RaycastHit.normal(docs.unity3d.com/ScriptReference/RaycastHit-normal.html),看下面的代码:

public void SetPosition (RaycastHit hit)
{
m_ReticleTransform.position = hit.point;
m_ReticleTransform.localScale = m_OriginalScale * hit.distance;
// 如果物体表面的法线可以被准星使用
if (m_UseNormal)
// ... 设定它的正向向量旋转,使其沿着法线方向
m_ReticleTransform.rotation = Quaternion.FromToRotation (Vector3.forward, hit.normal);
else
// 然后如果没有正确的法向方向可用的话就让它保持本来的朝向.
m_ReticleTransform.localRotation = m_OriginalRotation;
}

我们可以在迷宫场景中看到准星叠加到了墙体表面

23_unity-reticle-wall

这里能看到准星叠加到了地板上:

24_unity-reticle-floor

我们同样提供了完整的示例脚本来说明通过VREyeRaycaster定位准星到凝视到的物体表面.

25_reticle-inspector

以上所有内容均可在VRSampleScenes/Scenes/Examples/找到

VR中头部的旋转和位置

 

通过旋转头部,头戴式显示设备可以看周围的环境,有时候我们需要访问这个视角值.我们就需要用到 VR.InputTracking(docs.unity3d.com/ScriptReference/VR.InputTracking.html)类,并指定需要得到哪些VRNode(docs.unity3d.com/ScriptReference/VR.VRNode.html)数据.比如我们要获得头部的旋转,就要用VRNode.Head,而不是取眼睛的节点.

在示例项目中可以找到一个基于头部旋转作为菜单选择的例子,可以看VRSampleScenes/Examples/Rotation场景及ExampleRotation脚本:

// 存储游戏对象的旋转欧拉角
var eulerRotation = transform.rotation.eulerAngles;
//根据用户头部的y轴值设定对象的旋转
eulerRotation.x = 0;
eulerRotation.z = 0;
eulerRotation.y = InputTracking.GetLocalRotation(VRNode.Head).eulerAngles.y;

运行后我们就可以看到游戏对象是如何旋转的:

26_rotation-left

27_rotation-right

在Flyer游戏,我们用头部动作来控制飞船的位,线看FlyerMovementController这个脚本:

Quaternion headRotation = InputTracking.GetLocalRotation (VRNode.Head);
m_TargetMarker.position = m_Camera.position + (headRotation * Vector3.forward) * m_DistanceFromCamera;

28_flyervideo01

在VR游戏中用触控板和键盘交互

 

Gear VR的设备侧面有一块触控板,在Unity中相当于鼠标,我们可以用如下的命令:

Input.mousePosition(docs.unity3d.com/ScriptReference/Input-mousePosition.html)

Input.GetMouseButtonDown(docs.unity3d.com/ScriptReference/Input.GetMouseButtonDown.html)

Input.GetMouseButtonUp(docs.unity3d.com/ScriptReference/Input.GetMouseButtonUp.html)

在GearVR我们也可以获得滑动输入.在示例脚本VRInput中写好了关于滑动,单机,双击的输入获取.也同样支持按键盘上的左Ctrl键(Unity默认输入术语叫Fire1)或鼠标左键的鼠标滑动或鼠标单击.

而在Unity编辑器中,我们如果用DK2设备还没有很好的办法来测试Unity开发到GearVR的项目.不过我们可以用鼠标模拟触控板,配合键盘来实现测试.

左Ctrel(Fire1)作为单击,滑动鼠标模拟触控板的滑动旋转物体.

可以查看VRSampleScenes/Scenes/Examples/Touchpad场景了解上面说到的输入操作.

下面是ExampleTouchpad脚本,它依照滑动的方向给物体上的Rigidbody

以AddTorque实现旋转.

using UnityEngine;
using VRStandardAssets.Utils;
namespace VRStandardAssets.Examples
{
// 处理滑动控制的简单脚本例子
public class ExampleTouchpad : MonoBehaviour
{
[SerializeField] private float m_Torque = 10f;
[SerializeField] private VRInput m_VRInput;
[SerializeField] private Rigidbody m_Rigidbody;
private void OnEnable()
{
m_VRInput.OnSwipe += HandleSwipe;
}
private void OnDisable()
{
m_VRInput.OnSwipe -= HandleSwipe;
}
//给Ridigbody施加AddTorque来处理滑动事件
private void HandleSwipe(VRInput.SwipeDirection swipeDirection)
{
switch (swipeDirection)
{
case VRInput.SwipeDirection.NONE:
break;
case VRInput.SwipeDirection.UP:
m_Rigidbody.AddTorque(Vector3.right * m_Torque);
break;
case VRInput.SwipeDirection.DOWN:
m_Rigidbody.AddTorque(-Vector3.right * m_Torque);
break;
case VRInput.SwipeDirection.LEFT:
m_Rigidbody.AddTorque(Vector3.up * m_Torque);
break;
case VRInput.SwipeDirection.RIGHT:
m_Rigidbody.AddTorque(-Vector3.up * m_Torque);
break;
}
}
}
}

VR示例中的VRInput示例

 

如上所述,我们在示例游戏中使用VRInput处理触摸板和键盘的输入.

在迷宫游戏中,CameraOrbit监听滑动事件来响应视图的旋转.

private void OnEnable ()
{
m_VrInput.OnSwipe += HandleSwipe;
}
private void HandleSwipe(VRInput.SwipeDirection swipeDirection)
{
// 如果游戏没有开始或者正在播放相机淡出效果,不处理滑动输入.
if (!m_MazeGameController.Playing)
return;
if (m_CameraFade.IsFading)
return;
//否则根据滑动的进行相应的正转或负转.
switch (swipeDirection)
{
case VRInput.SwipeDirection.LEFT:
StartCoroutine(RotateCamera(m_RotationIncrement));
break;
case VRInput.SwipeDirection.RIGHT:
StartCoroutine(RotateCamera(-m_RotationIncrement));
break;
}
}


原文:http://unity3d.com/learn/tutorials/topics/virtual-reality

由 四角钱 (XK) 翻译,转载请注明来自 http://blog.1vr.cn