本文章由cartzhang编写,转载请注明出处。 所有权利保留。

文章链接:http://blog.csdn.net/cartzhang/article/details/53013843

作者:cartzhang

上次我们只做了一个快速的实现,实现了一个可爱的Unity酱的谷歌盒子的安卓版本。

说明:图片编号为了与github对应,所以保留了原来的编号。

图片地址: https://github.com/cartzhang/UnitySay/tree/master/GooglVR_2/img



只将简单的场景搭建和应用技巧,没有任何分析,这不是耍流氓吗。

当然是。



看代码从开始入手呢?

先看场景上,我们只挂载了一个googleVR的预制体,那就从它开始。



图1



这家伙只有一个脚本GvrViewer.cs,是不是让你大喜过望啊。一个脚本就搞定了,是不是很简单呢,这说简单也不简单。



粗略浏览一下代码,代码不到550行。

不关心后面的50行左右的,编辑器操作和游戏的暂停,退出等操作,还有500行,这个真不少啊。



那怎么说呢?

我们先要从Unity的代码执行顺序开始,

Unity中代码的执行顺序:



官方地址:https://docs.unity3d.com/Manual/ExecutionOrder.html



我们的重点:



图9.1



从Awake–>Start–>Update依次来讲述。

一、 Awake 分析

代码分析

void Awake() {
// 1.0 --
if (instance == null) {
instance = this;
}
if (instance != this) {
Debug.LogError("There must be only one GvrViewer object in a scene.");
UnityEngine.Object.DestroyImmediate(this);
return;
}
// 1.1 --
#if UNITY_IOS
Application.targetFrameRate = 60;
#endif
// Prevent the screen from dimming / sleeping
// 1.2 --
Screen.sleepTimeout = SleepTimeout.NeverSleep;
// 1.3 --
InitDevice();
StereoScreen = null; // Set up stereo pre- and post-render stages only for:
// - Unity without the GVR native integration
// - In-editor emulator when the current platform is Android or iOS.
// Since GVR is the only valid VR SDK on Android or iOS, this prevents it from
// interfering with VR SDKs on other platforms. //1.4 --
#if !UNITY_HAS_GOOGLEVR || (UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS))
AddPrePostRenderStages();
#endif // !UNITY_HAS_GOOGLEVR || UNITY_EDITOR

1.0 –

// 1.0 --
if (instance == null) {
instance = this;
}
if (instance != this) {
Debug.LogError("There must be only one GvrViewer object in a scene.");
UnityEngine.Object.DestroyImmediate(this);
return;
}

初始化,此类是个单列。



1.1 –

// 1.1 --
#if UNITY_IOS
Application.targetFrameRate = 60;
#endif

宏定义,若有UNITY_IOS,则锁帧在60帧。锁帧就是为了让游戏稳定一些 稳定的帧数。



1.2 –

// 1.2 --
Screen.sleepTimeout = SleepTimeout.NeverSleep;

就是为了省电,屏幕长时间没有触发,就触发休眠模式。现在就是从不启用休眠模式。



1.3 –

// 1.3 --
InitDevice();

初始化设备。这个是个函数,以后单说。



1.4 –

//1.4 --
#if !UNITY_HAS_GOOGLEVR || (UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS))
AddPrePostRenderStages();
#endif // !UNITY_HAS_GOOGLEVR || UNITY_EDITOR

没有预渲染,就添加预渲染。若没有后渲染,就添加后渲染。然后分别发送消息,Reset().最后设置他们各自的父节点。



设置当前对象为其父节点,代码就一句:

go.transform.parent = transform;



图2



图3



稍微说下SendMessage 这个函数:

[ExcludeFromDocs]
public void SendMessage(string methodName);

它的功能是调用当前对象上所有的Monobehaviour脚本内的名字为methodName的函数。

这方法效率不高。但是可以用,少用为好。



详细可以参考之前的博文:

http://blog.csdn.net/cartzhang/article/details/50686627



下面说初始化1.3 – 的初始化设备这个函数。



代码中给出了详细注释。

private void InitDevice() {
// 初始化设备
if (device != null) {
device.Destroy();
}
// 获取设备
device = BaseVRDevice.GetDevice();
// 设备初始化,这是继承类,其中override重新了Init。参考下图
device.Init(); // 初始化UI
List<string> diagnostics = new List<string>();
NativeUILayerSupported = device.SupportsNativeUILayer(diagnostics);
if (diagnostics.Count > 0) {
Debug.LogWarning("Built-in UI layer disabled. Causes: ["
+ String.Join("; ", diagnostics.ToArray()) + "]");
} if (DefaultDeviceProfile != null) {
device.SetDefaultDeviceProfile(DefaultDeviceProfile);
} device.SetNeckModelScale(neckModelScale); // 设置是否使用双目渲染。即是否使用VR模式。
#if !UNITY_HAS_GOOGLEVR || UNITY_EDITOR
device.SetVRModeEnabled(vrModeEnabled);
#endif // !UNITY_HAS_GOOGLEVR || UNITY_EDITOR // 更新屏幕数据
device.UpdateScreenData();
}

device.Init() 初始化的继承与BaseVRDevice类。



图7



图4

是否使用双目VR渲染,这个可以在实时修改其作用的。



图5



图6

二、 Start代码

代码只有一句,还在当前Unity 安卓模式和IOS模式下,Unity编辑器模式下才可用。

 void Start() {
// Set up stereo controller only for:
// - Unity without the GVR native integration
// - In-editor emulator when the current platform is Android or iOS.
// Since GVR is the only valid VR SDK on Android or iOS, this prevents it from
// interfering with VR SDKs on other platforms.
#if !UNITY_HAS_GOOGLEVR || (UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS))
AddStereoControllerToCameras();
#endif // !UNITY_HAS_GOOGLEVR || UNITY_EDITOR
}

具体实现了什么呢?

就是添加了手机的陀螺仪控制,可以用陀螺仪来控制相机。

上一讲中的在会后打出来安卓的APK包,在手机中自动的就可以左右移动来看场景中我们可爱的蛮牛酱的跳动,就是这样来控制和实现的。

#if !UNITY_HAS_GOOGLEVR || UNITY_EDITOR
/// Add a StereoController to any camera that does not have a Render Texture (meaning it is
/// rendering to the screen).
public static void AddStereoControllerToCameras() {
for (int i = 0; i < Camera.allCameras.Length; i++) {
Camera camera = Camera.allCameras[i];
if (camera.targetTexture == null &&
camera.cullingMask != 0 &&
camera.GetComponent<StereoController>() == null &&
camera.GetComponent<GvrEye>() == null &&
camera.GetComponent<GvrPreRender>() == null &&
camera.GetComponent<GvrPostRender>() == null) {
camera.gameObject.AddComponent<StereoController>();
}
}
}
#endif // !UNITY_HAS_GOOGLEVR || UNITY_EDITOR



图8



代码也不多。通过搜索,发现当前场景中总共有5个相机,如上图 。功能就是遍历所有相机,然后找到相机中,没有StereoController,GvrEye,GvrPreRender,GvrPostRender的相机,然后给它添加控制StereoController组件。



这样以来符合要的就只有MainCamera满足调节了。



图9

三、 在那里更新画面?

有没有发现在GvrViewer文件中,没有我们常见的Update()函数,只有一个UpdaetState()函数。那游戏画面怎么更新的呢?



注意是preRender()



待会的重点函数标注下:



图9.2

看下与UpdateState相关的调用,除去Demo和Ui调用,发现跟上面的AddStereoControllerToCameras这个函数中提到的类相关。



图10

1 .看下GvrEye.cs文件:

发现里面在渲染层次的函数:OnPreCull 和 OnPostRender。

其中,OnPostRender只有一句就是shder的某个关键字屏蔽。



看下OnPreCull的调用实现过程:



图11



在调用之后,最终还是生成一个RenderTexture.



图12



左右眼根据设置不同,矩阵参数有不同变化。但是结果都是一样的,一个纹理而已。

这都是在为最后一步渲染出左右眼,给所渲染的网格设置材质做准备而已。

2.GvrPreRender.cs文件

这个文件,根据很明显根据渲染顺序是预渲染的处理内容。



只有一个OnPreCull这样的渲染调用。

 void OnPreCull() {
// 更新设备状态
GvrViewer.Instance.UpdateState();
if (GvrViewer.Instance.ProfileChanged) {
// 设置shader,各种矩阵
SetShaderGlobals();
}
// 设置相机类型
cam.clearFlags = GvrViewer.Instance.VRModeEnabled ?
CameraClearFlags.SolidColor : CameraClearFlags.Nothing;
}



图13

3.GvrPostRender.cs文件

在渲染层次有两个函数一个是OnPreCull,一个为OnRenderObject.



其中OnPreCull,实现了根据相机屏幕及其手机屏幕的设置来调节比例,最后得到的是一个相机透视投影的比例参数。



而OnRenderObject则是实现分屏渲染,实现GooleVR的关键一步,渲染出画面。



图14

4. 简单说下 StereoControl.

主要功能就是创建左右眼,并设置其位置。



图15



5. GvrHead.cs



图16



与steroControl在同个相机下,

代码没有多少行:

  void Update() {
updated = false; // OK to recompute head pose.
if (updateEarly) {
UpdateHead();
}
} // Normally, update head pose now.
void LateUpdate() {
UpdateHead();
}

很明显,都调用了UpdateHead().

这个函数里面也很容易看到。

看是否同步跟踪旋转,是否同步跟踪位置,然后也是最后

有一个委托事件就是OnHeadUpdated。

这个就是在看玩家怎么使用的啦,更新玩状态就会通知的事件。



就不多说了。

四、一图千言



图18

五、流程图下载

下载流程图地址github:

https://github.com/cartzhang/UnitySay/blob/master/GooglVR_2/CodeAnylis.docx

这里有所画的流程图,若有需要,可以自行下载。

若有问题,请随时联系!!

非常感谢!!

六、参考

[1]

http://baike.baidu.com/link?url=ZdjIjIyvD_MlE57zVxe6PddyFhQqBXybShXg9NSi0R92EU8vkZHOYevvefg3zk7tVrD127vybwV-9b3HryYlCytg68J3DDmqG4R_YLqPZ53

[2]

https://docs.unity3d.com/Manual/ExecutionOrder.html

—————–THE—–END————————-

《图说VR入门》——googleVR入门代码分析的更多相关文章

  1. 《图说VR入门》——googleVR 他山之玉

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/53125482 作者:car ...

  2. 《图说VR入门》——入门汇总

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/53818922 作者:car ...

  3. 《图说VR入门》——DeepoonVR的大鹏(陀螺仪)枪

    <图说VR入门>--VR大朋的(陀螺仪)枪 本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接: http://blog.csdn.net/cartzhang/ar ...

  4. 《图说VR入门》——360全景视频

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/53674647 作者:car ...

  5. 《图说VR入门》——Unity插件DK2使用教程

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/53339254 作者:car ...

  6. 20155339 Exp4 恶意代码分析

    20155339 Exp4 恶意代码分析 实验后回答问题 (1)如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些,用什么方法来监控 ...

  7. babel从入门到入门

    babel从入门到入门 来源 http://www.cnblogs.com/gg1234/p/7168750.html 博客讲解内容如下: 1.babel是什么 2.javascript制作规范 3. ...

  8. ISD9160学习笔记05_ISD9160语音识别代码分析

    前言 语音识别是特别酷的功能,ISD9160的核心卖点就是这个语音识别,使用了Cybron VR 算法. 很好奇这颗10块钱以内的IC是如何实现人家百来块钱的方案.且听如下分析. 本文作者twowin ...

  9. springboot + kafka 入门实例 入门demo

    springboot + kafka 入门实例 入门demo 版本说明 springboot版本:2.3.3.RELEASE kakfa服务端版本:kafka_2.12-2.6.0.tgz zooke ...

随机推荐

  1. Spark SQL on Yarn-Cluster

    Spark SQL 或者Hive SQL在yarn-client模式下运行正常,但是在yarn-cluster模式下总是报 status failed错误, 需要把$SPARK_HOME/lib/sp ...

  2. URAL-1018 Binary Apple Tree---树形DP

    题目链接: https://cn.vjudge.net/problem/URAL-1018 题目大意: 给你一棵树,每条边有一个边权,求以1为根节点,q条边的子数(q+1个点),边权和至最大. 解题思 ...

  3. BZOJ3573:[HNOI2014]米特运输(树形DP)

    Description 米特是D星球上一种非常神秘的物质,蕴含着巨大的能量.在以米特为主要能源的D星上,这种米特能源的运输和储 存一直是一个大问题.D星上有N个城市,我们将其顺序编号为1到N,1号城市 ...

  4. HTML5本地存储(Local Storage) 的前世今生

    长久以来本地存储能力一直是桌面应用区别于Web应用的一个主要优势.对于桌面应用(或者原生应用),操作系统一般都提供了一个抽象层用来帮助应用程序保存其本地数据 例如(用户配置信息或者运行时状态等). 常 ...

  5. 【原创】纯CSS画黄金梅丽号!

    代码如下 <!DOCTYPE html> <!-- saved from url=(0055)http://jadyoap.bj.bcebos.com/ife%2FcssCatAni ...

  6. 【转】实现Http Server的三种方法

    一.使用SUN公司在JDK6中提供的新包com.sun.net.httpserver JDK6提供了一个简单的Http Server API,据此我们可以构建自己的嵌入式Http Server,它支持 ...

  7. [转]MBTiles 离线地图演示 - 基于 Google Maps JavaScript API v3 + SQLite

    MBTiles 是一种地图瓦片存储的数据规范,它使用SQLite数据库,可大大提高海量地图瓦片的读取速度,比通过瓦片文件方式的读取要快很多,适用于Android.IPhone等智能手机的离线地图存储. ...

  8. 近十年one-to-one最短路算法研究整理

    前言:针对单源最短路算法,目前最经典的思路即标号算法,以Dijkstra算法和Bellman-Ford算法为根本演进了各种优化技术和算法.针对复杂网络,传统的优化思路是在数据结构和双向搜索上做文章,或 ...

  9. [LuoguP2403][SDOI2010]所驼门王的宝藏

    题目描述 在宽广的非洲荒漠中,生活着一群勤劳勇敢的羊驼家族.被族人恭称为"先知"的Alpaca L. Sotomon是这个家族的领袖,外人也称其为"所驼门王". ...

  10. IIS中ASP.NET虚拟目录不继承主站点web.config设置的办法(转载)

    ASP.NET提供了强大的Web.config来配置网站,一般来说一个网站只有一个根目录下的Web.config文件,有时候我们希望子目录有着不同的权限或者参数设置,则可以在相应子目录增加一个Web. ...