原文地址:http://blog.csdn.net/mao_xiao_feng/article/details/52074384
上一章講了Cardboard這個類,做一個總結码倦,這個類總就是給一些私有的變量去提供了共有的接口,以供用戶去修改他們的值捕发。這些量大多都是用戶級別的變量庙楚,多是控制一些功能的使能,例如是否開啟VR模式等哎壳。還有一個重要作用毅待,類實現了自身的單例化,如下:
public class Singleton{ private static Singleton _instance = null; //將構造函數設為private归榕,防止客戶代碼通過new實例化對象 private Singleton() { } public static Singleton CreateInstance() { if(_instance == null) _instance = new Singleton(); return _instance; }}
這就是單件模式一個重要的例子尸红,用戶永遠只能通過自定義的公有方法去實例化或者返回已經實例化的對象。
單件模式蹲坷,有兩個好處:
第一個是資源共享驶乾,例如在這個demo中,我們只希望VR Mode Enabled這個變量只有一個循签,外部共享的調用它级乐。如果它有兩個,這樣就會導致難以處理一些請求和資源的損耗县匠。
第二個是信息交互會更加簡便风科,就像為什么Unity里面永遠只有一個Main Camera,而我們去find它的時候不需要遍歷的去搜索判斷它的名字乞旦,道理是一樣的贼穆。
我們還簡單介紹了以下幾項屬性的功能(其中Editor Mock Settings是Unity編輯器下運行的設置,一般不會做改動的兰粉,也對手機上運行沒什么影響)
/************************************************************分割線****************************************************************/
好了故痊,接下來進入這次的主題,先上圖
Paste_Image.png](http://upload-images.jianshu.io/upload_images/1312008-c2e8a1d51f5f8d10.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
這是VRDevice文件夾下所有類的繼承關系玖姑,可以看到所有類都繼承于同一個基類愕秫,BaseVRDevice
BaseVRDevice的介紹
// Represents a vr device that this plugin interacts with. 代表了與這個插件交互的VR設備
這個類里面應該定義了作為VR設備必須要實現的一些方法慨菱,但我們不必關注是怎樣實現的,這些方法會在子類里面根據不同的平臺(iOS戴甩,Android)重寫符喝,給出詳細的實現步驟。
我們把重要的和不重要的歸個類
重要:
public virtual RenderTexture CreateStereoScreen()
//Creating new default cardboard screen texture.為Cardboard屏幕生成一個新的默認RenderTexture甜孤,RenderTexture是一個實時更新的紋理协饲,動態(tài)的,上節(jié)說過
public Pose3D GetHeadPose()
protected MutablePose3D headPose = new MutablePose3D();
//兩個一起講缴川,headPose是變量茉稠,記錄了頭部的位置信息,注意是protected的二跋,GetHeadPose()得到頭部的位置战惊,返回的是headPose,這個方法是public的
public Pose3D GetEyePose(Cardboard.Eye eye)
protected MutablePose3D leftEyePose = new MutablePose3D();
protected MutablePose3D rightEyePose = new MutablePose3D();
//同理扎即,眼睛位置
public Matrix4x4 GetProjection(Cardboard.Eye eye,Cardboard.Distortion distortion = Cardboard.Distortion.Distorted)
protected Matrix4x4 leftEyeDistortedProjection;
protected Matrix4x4 rightEyeDistortedProjection;
protected Matrix4x4 leftEyeUndistortedProjection;
protected Matrix4x4 rightEyeUndistortedProjection;
//根據眼睛類型(左右眼)和是否應用透鏡彎曲效果來返回一個Projection(投影)吞获,這個投影是Matrix4x4類型的,Unity官方對投影矩陣的解釋是 如果你改變這個矩陣谚鄙,相機的渲染不再基于它的fieldOfView更新各拷,直到調用ResetProjectionMatrix.只有當真正需要一個非標準的投影時,才使用自定義投影闷营。
public Rect GetViewport(Cardboard.Eye eye,Cardboard.Distortion distortion = Cardboard.Distortion.Distorted)
protected Rect leftEyeDistortedViewport;
protected Rect rightEyeDistortedViewport;
protected Rect leftEyeUndistortedViewport;
protected Rect rightEyeUndistortedViewport;
//根據眼睛類型(左右眼)和是否應用透鏡彎曲效果來返回一個Viewport(視口)烤黍,這個視口是Rect 類型的,Rect類型很簡單傻盟,里面存著(x,y,w,h)四個量速蕊,而每個量分別代表的是如下圖,而一個camera呈現的畫面娘赴,它在屏幕上占多大的地规哲,就是以視口決定的。
public abstract void UpdateState();
public abstract void UpdateScreenData();
public abstract void Recenter();
public abstract void PostRender(bool vrMode);
//又來四個抽象方法诽表,從字面意思上看唉锌,是狀態(tài)更新,屏幕數據更新竿奏,重新定位中心袄简,完成渲染后
public virtual void OnPause(bool pause)
//當停止了,就不再UpdateScreenData()
public virtual void OnFocus(bool focus)
public virtual void Reset()
public virtual void OnApplicationQuit()
public virtual void Destroy()
//由字面意思就可以理解
protected void ComputeEyesFromProfile()//這個函數很關鍵7盒ァB逃铩!官方打的注釋是// Compute left eye matrices from screen and device params,意思就是根據設備的參數計算左眼的觀測信息
/****************************************************分割線************************************************************/
這一部分對ComputeEyesFromProfile()函數做一個詳細介紹
protected void ComputeEyesFromProfile() {
// Compute left eye matrices from screen and device params
Matrix4x4 leftEyeView = Matrix4x4.identity;
leftEyeView[0, 3] = -Profile.device.lenses.separation / 2;
leftEyePose.Set(leftEyeView);
float[] rect = new float[4];
Profile.GetLeftEyeVisibleTanAngles(ref rect);
leftEyeDistortedProjection = MakeProjection(rect[0], rect[1], rect[2], rect[3], 1, 1000);
Profile.GetLeftEyeNoLensTanAngles(ref rect);
leftEyeUndistortedProjection = MakeProjection(rect[0], rect[1], rect[2], rect[3], 1, 1000);
leftEyeUndistortedViewport = Profile.GetLeftEyeVisibleScreenRect(rect);
leftEyeDistortedViewport = leftEyeUndistortedViewport;
// Right eye matrices same as left ones but for some sign flippage.
Matrix4x4 rightEyeView = leftEyeView;
rightEyeView[0, 3] *= -1;
rightEyePose.Set(rightEyeView);
rightEyeDistortedProjection = leftEyeDistortedProjection;
rightEyeDistortedProjection[0, 2] *= -1;
rightEyeUndistortedProjection = leftEyeUndistortedProjection;
rightEyeUndistortedProjection[0, 2] *= -1;
rightEyeUndistortedViewport = leftEyeUndistortedViewport;
rightEyeUndistortedViewport.x = 1 - rightEyeUndistortedViewport.xMax;
rightEyeDistortedViewport = rightEyeUndistortedViewport;
}
來自CODE的代碼片BaseVRDevice.cs
首先這個方法中用到的數據都是來源于CardboardProfile這個類汞舱,這個類中記錄了Cardboard設備的各項參數
第一句話建立了Matrix4x4 leftEyeView這個量伍纫,然后把一個4*4的單位矩陣賦給他
第二句話涉及到了CardboardProfile里的Lenses,想要解釋清楚這部分昂芜,需要畫三張圖
Paste_Image.png](http://upload-images.jianshu.io/upload_images/1312008-2edda55bebedac71.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
Lenses里面一些量標注如上圖。
還有MaxFOV這個量
public struct MaxFOV { public float outer; // Towards the side of the screen. public float inner; // Towards the center line of the screen. public float upper; // Towards the top of the screen. public float lower; // Towards the bottom of the screen. }
這個量表示我們視野的最大值赔蒲,是用角度來定義的泌神,如outer這個量就是俯視圖中,∠ABC的大小舞虱,inner就是∠CBD的大小了
接著第二句話leftEyeView[0, 3] = -Profile.device.lenses.separation / 2欢际,這就是一個賦值語句,給第4列的第一個元素賦了值
第三句話leftEyePose.Set(leftEyeView)矾兜,從這句話可以看出了leftEyeView這個矩陣里面是存儲了眼睛的位置信息的损趋,后續(xù)看了Set()函數,矩陣的第四列存了Position椅寺,第二第三列存了Orientation朝向信息浑槽。
再看后面 float[] rect = new float[4];Profile.GetLeftEyeVisibleTanAngles(ref rect);這兩句話,新建了一個數組返帕,在一個方法GetLeftEyeVisibleTanAngles中修改了數組里的元素的值
[csharp] view plain copy
public void GetLeftEyeVisibleTanAngles(ref float[] result) {
// Tan-angles from the max FOV.
float fovLeft = (float) Math.Tan(-device.maxFOV.outer * Math.PI / 180);
float fovTop = (float) Math.Tan(device.maxFOV.upper * Math.PI / 180);
float fovRight = (float) Math.Tan(device.maxFOV.inner * Math.PI / 180);
float fovBottom = (float) Math.Tan(-device.maxFOV.lower * Math.PI / 180);
// Viewport size.
float halfWidth = screen.width / 4;
float halfHeight = screen.height / 2;
// Viewport center, measured from left lens position.
float centerX = device.lenses.separation / 2 - halfWidth;
float centerY = -VerticalLensOffset;
float centerZ = device.lenses.screenDistance;
// Tan-angles of the viewport edges, as seen through the lens.
float screenLeft = device.distortion.distort((centerX - halfWidth) / centerZ);
float screenTop = device.distortion.distort((centerY + halfHeight) / centerZ);
float screenRight = device.distortion.distort((centerX + halfWidth) / centerZ);
float screenBottom = device.distortion.distort((centerY - halfWidth) / centerZ);
// Compare the two sets of tan-angles and take the value closer to zero on each side.
result[0] = Math.Max(fovLeft, screenLeft);
result[1] = Math.Min(fovTop, screenTop);
result[2] = Math.Min(fovRight, screenRight);
result[3] = Math.Max(fovBottom, screenBottom);
}
看一下GetLeftEyeVisibleTanAngles這個函數桐玻,先是把FOV角度轉換成了正切值,再取到了屏幕相對于左眼的正切角荆萤,相比取了一個最小值镊靴,可以這樣理解,如果手機屏幕比正常視野大了链韭,那么我們看不全整個屏幕偏竟,為了有更好的體驗,需要以視野作為標準敞峭,當視野比屏幕大了踊谋,當然是以手機屏幕作為標準更好一些。
以上函數完成了以后儡陨,rect的值產生了變化褪子,接下來就需要應用這些值,leftEyeDistortedProjection = MakeProjection(rect[0], rect[1], rect[2], rect[3], 1, 1000);計算投影矩陣骗村,因為上一步嫌褪,我們做了distort變換,可以把distort理解為經過了透鏡的光線折射胚股,所以投影矩陣的結果應該也是distort的笼痛,camera呈現的畫面就會是這樣
[圖片上傳中。。缨伊。(7)]
當無透鏡的時候Profile.GetLeftEyeNoLensTanAngles(ref rect);leftEyeUndistortedProjection = MakeProjection(rect[0], rect[1], rect[2], rect[3], 1, 1000);會做一個inverse distort摘刑,即distort的逆變換,得到的自然是無透鏡的情況
[圖片上傳中刻坊。枷恕。。(8)]
直到這里谭胚,我們說的都是Camera的Projection徐块,他跟viewport是有區(qū)別的,后面執(zhí)行的
leftEyeUndistortedViewport = Profile.GetLeftEyeVisibleScreenRect(rect);leftEyeDistortedViewport = leftEyeUndistortedViewport;
處理的是camera的viewport灾而,即在屏幕上劃定一個矩形胡控,camera捕捉到的畫面都將在矩形中顯示,這在游戲分屏技術中用的很多(比如兩個玩家對抗旁趟,在一個屏幕中顯示兩個畫面)昼激,當然viewport的劃定與是否需要distort無關,這樣leftEyeDistortedViewport與leftEyeUndistortedViewport 應該是一個值锡搜。
/****************************************************分割線************************************************************/
不重要:
public virtual bool SupportsNativeDistortionCorrection(List<string> diagnostics)
//一個用來判斷是否支持NativeDistortionCorrection的方法橙困,需要滿足兩個條件,支持RenderTexture和Unity4.5版本以上余爆,才能支持透鏡扭曲的效果
public virtual bool SupportsNativeUILayer(List<string> diagnostics)
//同理纷宇,但是這個NativeUILayer僅需要Unity4.5以上版本一個條件
public abstract void SetDistortionCorrectionEnabled(bool enabled);
public abstract void SetVRModeEnabled(bool enabled);
public abstract void SetAlignmentMarkerEnabled(bool enabled);
public abstract void SetSettingsButtonEnabled(bool enabled);
public abstract void SetNeckModelScale(float scale);
public abstract void SetAutoDriftCorrectionEnabled(bool enabled);
public abstract void SetStereoScreen(RenderTexture stereoScreen);
//一堆抽象方法,后面會重寫的蛾方,現在先放著吧
public abstract void UpdateState();
public abstract void UpdateScreenData();
public abstract void Recenter();
public abstract void PostRender(bool vrMode);
//又來四個抽象方法像捶,從字面意思上看,是狀態(tài)更新桩砰,屏幕數據更新拓春,重新定位中心,完成渲染后
public virtual void OnPause(bool pause)
//當停止了亚隅,就不再UpdateScreenData()
public virtual void OnFocus(bool focus)
public virtual void Reset()
public virtual void OnApplicationQuit()
public virtual void Destroy()
//由字面意思就可以理解
OKE鹈А!BaseVRDevice就看到這里煮纵,這個類中還是有比較關鍵的函數的懂鸵,后面會繼續(xù)看子類的代碼,有些地方比如怎樣去計算Projection的44的矩陣行疏,投影為什么要用44矩陣可能涉及到數學的東西了匆光,我也不太明白,只能是看懂了以后再作介紹酿联。