原文地址:http://blog.csdn.net/mao_xiao_feng/article/details/52599298
上篇為大家介紹了如何實現(xiàn)虛擬視覺级乍,鏈接如下:
寫給VR手游開發(fā)小白的教程:(六)Cardboard如何實現(xiàn)沉浸式VR體驗之構(gòu)造雙眼
本篇分為五部分盛霎,為大家講述虛擬視覺的引入帶來的兩個基本問題以及Cardboard的解決方案
一碍论、VR設(shè)備透鏡的作用
上篇已經(jīng)說過,要實現(xiàn)FOV的外部匹配镰惦,需要使得我們雙眼的視野正好覆蓋手機(jī)屏幕九榔,這意味著手機(jī)會離我們的眼睛很近板丽,當(dāng)我們長時間注視一個近距離物體時無疑會產(chǎn)生視覺上的疲勞,久而久之刹勃,產(chǎn)生近視或者是對身體更大的危害堪侯。
這是虛擬視覺帶來的很顯而易見的問題,如何解決荔仁?目前所有的VR設(shè)備都采用了一個方法:增加鏡頭伍宦。
關(guān)于VR透鏡的設(shè)計涉及到了光學(xué)方面的原理,提供兩篇好的文章:
http://www.elecfans.com/vr/433366_3.html
http://ivr.baidu.com/js/573d9236814e2.html
綜上所述乏梁,透鏡的作用大約可以概括為2個:1次洼、防止視覺疲勞2、增大視場角(FOV)
現(xiàn)在多數(shù)的VR眼鏡掌呜,都采用了菲涅爾透鏡滓玖,它與普通的透鏡其實沒什么區(qū)別,只不過它將內(nèi)部的材質(zhì)移去质蕉,使得整個鏡片更加輕薄势篡。
二、畸變問題的產(chǎn)生
畸變是因為相機(jī)鏡頭在成像時模暗,視場不同區(qū)域的放大率不同而產(chǎn)生的變形禁悠。
下圖所示,畸變分為桶形畸變和枕形畸變兑宇。
桶形畸變的產(chǎn)生原因?qū)嶋H上是因為中間部分的放大率比邊緣部分大碍侦,導(dǎo)致圖像產(chǎn)生了向內(nèi)彎曲的現(xiàn)象(如下圖中黑色圈中的線明顯比綠色圈中的線要長)。
反之枕形畸變則是中間部分的放大率比邊緣部分小而導(dǎo)致的隶糕。
光學(xué)上可以通過改進(jìn)透鏡的工藝來改善畸變瓷产,比如采用非球面鏡片,但是我們的VR設(shè)備的價格注定了我們觀察的圖像必然會發(fā)生畸變(果然是便宜沒好貨-.-)枚驻,所以處理圖像畸變也是我們面臨的一個難題濒旦。
三、Unity中的扭曲矯正(RadialUndistortionEffect.cs)
Cardboard使用了RadialUndistortionEffect.cs這個腳本來做扭曲矯正:
using UnityEngine;
using System.Collections;
// Applies the inverse of the lens distortion to the image. The image is "undistorted" so
// that when viewed through the lenses (which redistort), the image looks normal. In the case
// of Cardboard, the lenses apply a pincushion distortion, so this effect applies a barrel
// distortion to counteract that.
[RequireComponent(typeof(Camera))]
public class RadialUndistortionEffect : MonoBehaviour {
#if UNITY_EDITOR
private StereoController controller;
#endif
private Material material;
void Awake() {
if (!SystemInfo.supportsRenderTextures) {
Debug.Log("Radial Undistortion disabled: render textures not supported.");
return;
}
Shader shader = Shader.Find("Cardboard/Radial Undistortion");
if (shader == null) {
Debug.Log("Radial Undistortion disabled: shader not found.");
return;
}
material = new Material(shader);
}
#if UNITY_EDITOR
void Start() {
var eye = GetComponent<CardboardEye>();
if (eye != null) {
controller = eye.Controller;
}
}
#endif
void OnRenderImage(RenderTexture source, RenderTexture dest) {
// Check if we found our shader, and that native distortion correction is OFF (except maybe in
// the editor, since native is not available here).
bool disabled = material == null || !Cardboard.SDK.UseDistortionEffect;
#if UNITY_EDITOR
bool mainCamera = controller != null && controller.GetComponent<Camera>().tag == "MainCamera";
disabled |= !mainCamera || !Cardboard.SDK.simulateDistortionCorrection;
#endif
if (disabled) {
// Pass through, no effect.
Graphics.Blit(source, dest);
} else {
// Undistort the image.
Graphics.Blit(source, dest, material);
}
}
}
來自CODE的代碼片RadialUndistortionEffect.cs
Applies the inverse of the lens distortion to the image. The image is "undistorted" so that when viewed through the lenses (which redistort), the image looks normal. In the case of Cardboard, the lenses apply a pincushion distortion, so this effect applies a barrel distortion to counteract that.
應(yīng)用了透鏡扭曲的反效果再登。圖像是“反扭曲”的以至于當(dāng)我們透過透鏡觀察的時候(經(jīng)過了扭曲)尔邓,圖像會看起來正常一些晾剖。在Cardboard里,透鏡產(chǎn)生了枕形畸變梯嗽,因此可以使用一個桶形畸變的圖像效果來消除畸變的影響齿尽。
這句注釋很清楚的告訴了我們?nèi)绾稳ハ儯蔷褪钱a(chǎn)生一個已經(jīng)畸變了的圖像去抵消透鏡產(chǎn)生的畸變灯节,如果透鏡產(chǎn)生了枕形畸變循头,那我們直接生成已經(jīng)桶形畸變了的圖像,反之也同理显晶。
如何產(chǎn)生桶形畸變的圖像贷岸?這主要涉及到Unity中shader的概念,shader主要用于生成一系列圖像效果磷雇,稱作著色器程序偿警,它主要運行在GPU上,編寫這樣的代碼段唯笙,需要一定的功力螟蒸,也需要對Unity和其渲染機(jī)制有很高的理解。(博主沒有編寫過shader崩掘,沒法去解釋其實現(xiàn)了七嫌。。)
最后苞慢,通過該函數(shù)Graphics.Blit(source, dest, material);將我們的源RenderTexture經(jīng)過material處理后轉(zhuǎn)換成目標(biāo)RenderTexture诵原。
可以做一個實驗,在運行的時候挽放,如果將腳本RadialUndistortionEffect.cs關(guān)閉绍赛,則會出現(xiàn)下圖的現(xiàn)象。
注意<琛B鸢觥!這種方式只適用于Unity Editor纯出,如果要在手機(jī)當(dāng)中產(chǎn)生失真矯正效果蚯妇,需要調(diào)用的是手機(jī)對應(yīng)的圖形處理程序。
可惜的是所有Android或者iOS的方法在Unity中只能以庫的形式調(diào)用暂筝,以android為例箩言,我們通常會在eclipse或者Android Studio中打包成類庫,然后在Unity當(dāng)中去做引用焕襟,基于這一點分扎,我們并不能看到Android產(chǎn)生畸變的圖像的具體實現(xiàn)過程,因為它們已經(jīng)被封裝起來了胧洒。
四畏吓、FOV的內(nèi)部匹配問題
我們在上篇已經(jīng)說過了FOV的外部匹配,通常人的視場角為60度左右卫漫,在60度的范圍內(nèi)我們要做到正好覆蓋圖像輸出的viewport位置菲饼,任何圖像小于視場或者大于視場的現(xiàn)象均會導(dǎo)致沉浸感降低。這是FOV的外部匹配問題列赎。
現(xiàn)在我們不僅有現(xiàn)實中的視覺宏悦,別忘了在虛擬世界中,我們也有視覺包吝,對應(yīng)的當(dāng)然也有FOV饼煞。這里所說的FOV內(nèi)部匹配,就是現(xiàn)實視覺的FOV與虛擬視覺的FOV之間的匹配诗越。
換言之砖瞧,就是保證虛擬視覺的視場角保持在一個對于人來說舒適的范圍,60度左右嚷狞。
那么為什么要做匹配呢块促?我們完全可以在虛擬世界中獲得更大或者是更窄的FOV,從實現(xiàn)的角度考慮床未,這沒有問題竭翠,但是人體習(xí)慣于以60度左右的FOV觀察世界,并且我們想要觀察超出人體視場的物體時薇搁,會習(xí)慣性的轉(zhuǎn)頭斋扰,這就像是一種本能,大腦已經(jīng)習(xí)慣于這樣的FOV啃洋,現(xiàn)在當(dāng)我們被迫接受不匹配的FOV時传货,大腦對于新的改變表現(xiàn)出不適,從而產(chǎn)生強(qiáng)烈的眩暈感裂允。
從某些方面來看损离,F(xiàn)OV內(nèi)部匹配甚至比外部匹配更加重要。
五绝编、FOV內(nèi)部匹配的解決方案(StereoController.cs)
StereoController這個類主要用來對雙眼(Cardboard Eye)進(jìn)行控制和調(diào)整僻澎,它綁定在mono Camera上,對兩個子物體stereo Camera進(jìn)行控制十饥。
Controls a pair of CardboardEye objects that will render the stereo view of the camera this script is attached to.
這個腳本控制一對用來產(chǎn)生立體畫面的攝像機(jī)物體窟勃。
這個腳本下有幾個重要的屬性:
/***********************************************************************************************************************************/
stereoMultiplier:
Adjusts the level of stereopsis for this stereo rig. Note that this parameter is not the virtual size of the head -- use a scale on the head game object for that. Instead, it is a control on eye vergence, or rather, how cross-eyed or not the stereo rig is. Set to 0 to turn off stereo in this rig independently of any others.
通過本控制器調(diào)整立體度等級。注意這個參數(shù)不是虛擬頭部的大小--使用scale來調(diào)整頭部物體逗堵,而是對眼睛離散度的控制秉氧,這個離散度也可以理解為視線怎樣傾斜。設(shè)置為0的時候蜒秤,關(guān)閉立體效果汁咏。
上兩張圖大家就能發(fā)現(xiàn)這個參數(shù)的功能了:
這是一張stereoMultiplier設(shè)置為1時候的圖
這是stereoMultiplier設(shè)置為0時候的圖
兩者的差別亚斋,大家可以仔細(xì)的觀察一下(必須要很仔細(xì)很仔細(xì)的觀察,才能發(fā)現(xiàn)不同 :-D)
如果還是找不到不同攘滩,好吧帅刊,我們用兩張圖來表達(dá)差異:
平常,我們的眼睛觀察物體漂问,是這樣的赖瞒。
現(xiàn)在,stereoMultiplier設(shè)為0蚤假,是這樣的栏饮。
第一種方式,同時考慮了視線的傾斜磷仰,而第二種方式只是將畫面平視輸出袍嬉,很顯然,如果想要更高的立體感芒划,這個參數(shù)設(shè)為1更好冬竟。
/***********************************************************************************************************************************/
matchMonoFOV:
這個參數(shù),就是上述的FOV內(nèi)部匹配
The stereo cameras by default use the actual optical FOV of the Cardboard device,because otherwise the match between head motion and scene motion is broken, which impacts the virtual reality effect. However, in some cases it is desirable to adjust the FOV anyway, for special effects or artistic reasons. But in no case should the FOV be allowed to remain very different from the true optical FOV for very long, or users will experience discomfort.This value determines how much to match the mono camera's field of view. This is a fraction: 0 means no matching, 1 means full matching, and values in between are compromises. Reasons for not matching 100% would include preserving some VR-ness,and that due to the lens distortion the edges of the view are not as easily seen as when the phone is not in VR-mode.Another use for this variable is to preserve scene composition against differences in the optical FOV of various Cardboard models. In all cases, this value simply lets the mono camera have some control over the scene in VR mode, like it does in non-VR mode.
立體攝像機(jī)默認(rèn)使用Cardboard設(shè)備實際的FOV民逼,不然會導(dǎo)致頭部運動和場景運動的匹配關(guān)系破裂(這會影響沉浸感)泵殴,然而,在一定情況下拼苍,也可以調(diào)整FOV(為了特效或者藝術(shù)感)笑诅,但是長時間使用與實際視覺FOV不同的FOV是不允許的,這會讓用戶不舒服疮鲫。這個值決定了mono Camera獲得的FOV的匹配度吆你。0意味著不匹配,1意味著完全匹配俊犯,中間的值折中妇多。不進(jìn)行100%匹配的原因包括,保留VR的特性燕侠,VR模式下圖像的邊緣不易被非VR模式看到者祖,不同類型的Cardboard進(jìn)行兼容等。這個值通常讓mono Camera在VR模式下對于場景有一些控制绢彤。
/***********************************************************************************************************************************/
matchByZoom:
Determines the method by which the stereo cameras' FOVs are matched to the mono camera's FOV (assuming matchMonoFOV is not 0). The default is to move the stereo cameras (matchByZoom = 0), with the option to instead do a simple camera zoom (matchByZoom = 1). In-between values yield a mix of the two behaviors.It is not recommended to use simple zooming for typical scene composition, as it conflicts with the VR need to match the user's head motion with the corresponding scene motion. This should be reserved for special effects such as when the player views the scene through a telescope or other magnifier (and thus the player knows that VR is going to be affected), or similar situations.Note that matching by moving the eyes requires that the centerOfInterest object be non-null, or there will be no effect.
決定stereo cameras的FOV和mono camera的FOV進(jìn)行匹配的方式(前提是matchMonoFOV不是0)七问。默認(rèn)是移動stereocameras(matchByZoom = 0),還有一種方式是簡單的對camera的視野進(jìn)行縮放(matchByZoom = 1)茫舶,中間的值械巡,表示兩種方式的混合,不建議使用簡單縮放,因為它和頭部移動與場景移動的匹配相沖突讥耗。同樣縮放效果可以被保留用作特效有勾,比如玩家通過望遠(yuǎn)鏡觀看場景。注意移動匹配需要興趣中心點物體非空葛账,否則會無效柠衅。
/***********************************************************************************************************************************/
centerOfInterest:
Matching the mono camera's field of view in stereo by moving the eyes requires a designated "center of interest". This is either a point in space (an empty gameobject) you place in the scene as a sort of "3D cursor", or an actual scene entity which the player is likely to be focussed on.The FOV adjustment is done by moving the eyes toward or away from the COI so that it appears to have the same size on screen as it would in the mono camera. This is disabled if the COI is null.
為了移動stereo camera匹配FOV,我們需要一個被設(shè)計好的“興趣中心點”籍琳。這可以是一個空物體,也可以是非空物體贷祈,甚至是場景中玩家可能會關(guān)注的實際物體趋急,F(xiàn)OV調(diào)整根據(jù)距離興趣中心點的距離以至于看起來與在mono camera中有同樣的尺寸。
radiusOfInterest:
在興趣中心為非空物體時势誊,可以定義半徑大小呜达。
綜上,可以看出Cardboard使用基于mono camera來調(diào)整每個stereo camera的方法粟耻,并且設(shè)置了興趣中心點查近,這個點相當(dāng)于我們雙眼視線的中心交點,除了作為基準(zhǔn)外挤忙,一些游戲為了吸引玩家注意也會在這個點上放置重要的物體霜威。