原文地址:http://blog.csdn.net/mao_xiao_feng/article/details/52599298
上篇為大家介紹了如何實現虛擬視覺,鏈接如下:
寫給VR手游開發小白的教程:(六)Cardboard如何實現沉浸式VR體驗之構造雙眼
本篇分為五部分,為大家講述虛擬視覺的引入帶來的兩個基本問題以及Cardboard的解決方案
一、VR設備透鏡的作用
上篇已經說過,要實現FOV的外部匹配,需要使得我們雙眼的視野正好覆蓋手機屏幕,這意味著手機會離我們的眼睛很近,當我們長時間注視一個近距離物體時無疑會產生視覺上的疲勞,久而久之,產生近視或者是對身體更大的危害。
這是虛擬視覺帶來的很顯而易見的問題,如何解決?目前所有的VR設備都采用了一個方法:增加鏡頭。
關于VR透鏡的設計涉及到了光學方面的原理,提供兩篇好的文章:
http://www.elecfans.com/vr/433366_3.html
http://ivr.baidu.com/js/573d9236814e2.html
綜上所述,透鏡的作用大約可以概括為2個:1、防止視覺疲勞2、增大視場角(FOV)
現在多數的VR眼鏡,都采用了菲涅爾透鏡,它與普通的透鏡其實沒什么區別,只不過它將內部的材質移去,使得整個鏡片更加輕薄。
二、畸變問題的產生
畸變是因為相機鏡頭在成像時,視場不同區域的放大率不同而產生的變形。
下圖所示,畸變分為桶形畸變和枕形畸變。
桶形畸變的產生原因實際上是因為中間部分的放大率比邊緣部分大,導致圖像產生了向內彎曲的現象(如下圖中黑色圈中的線明顯比綠色圈中的線要長)。
反之枕形畸變則是中間部分的放大率比邊緣部分小而導致的。
光學上可以通過改進透鏡的工藝來改善畸變,比如采用非球面鏡片,但是我們的VR設備的價格注定了我們觀察的圖像必然會發生畸變(果然是便宜沒好貨-.-),所以處理圖像畸變也是我們面臨的一個難題。
三、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.
應用了透鏡扭曲的反效果。圖像是“反扭曲”的以至于當我們透過透鏡觀察的時候(經過了扭曲),圖像會看起來正常一些。在Cardboard里,透鏡產生了枕形畸變,因此可以使用一個桶形畸變的圖像效果來消除畸變的影響。
這句注釋很清楚的告訴了我們如何去消除畸變,那就是產生一個已經畸變了的圖像去抵消透鏡產生的畸變,如果透鏡產生了枕形畸變,那我們直接生成已經桶形畸變了的圖像,反之也同理。
如何產生桶形畸變的圖像?這主要涉及到Unity中shader的概念,shader主要用于生成一系列圖像效果,稱作著色器程序,它主要運行在GPU上,編寫這樣的代碼段,需要一定的功力,也需要對Unity和其渲染機制有很高的理解。(博主沒有編寫過shader,沒法去解釋其實現了。。)
最后,通過該函數Graphics.Blit(source, dest, material);將我們的源RenderTexture經過material處理后轉換成目標RenderTexture。
可以做一個實驗,在運行的時候,如果將腳本RadialUndistortionEffect.cs關閉,則會出現下圖的現象。
注意!!!這種方式只適用于Unity Editor,如果要在手機當中產生失真矯正效果,需要調用的是手機對應的圖形處理程序。
可惜的是所有Android或者iOS的方法在Unity中只能以庫的形式調用,以android為例,我們通常會在eclipse或者Android Studio中打包成類庫,然后在Unity當中去做引用,基于這一點,我們并不能看到Android產生畸變的圖像的具體實現過程,因為它們已經被封裝起來了。
四、FOV的內部匹配問題
我們在上篇已經說過了FOV的外部匹配,通常人的視場角為60度左右,在60度的范圍內我們要做到正好覆蓋圖像輸出的viewport位置,任何圖像小于視場或者大于視場的現象均會導致沉浸感降低。這是FOV的外部匹配問題。
現在我們不僅有現實中的視覺,別忘了在虛擬世界中,我們也有視覺,對應的當然也有FOV。這里所說的FOV內部匹配,就是現實視覺的FOV與虛擬視覺的FOV之間的匹配。
換言之,就是保證虛擬視覺的視場角保持在一個對于人來說舒適的范圍,60度左右。
那么為什么要做匹配呢?我們完全可以在虛擬世界中獲得更大或者是更窄的FOV,從實現的角度考慮,這沒有問題,但是人體習慣于以60度左右的FOV觀察世界,并且我們想要觀察超出人體視場的物體時,會習慣性的轉頭,這就像是一種本能,大腦已經習慣于這樣的FOV,現在當我們被迫接受不匹配的FOV時,大腦對于新的改變表現出不適,從而產生強烈的眩暈感。
從某些方面來看,FOV內部匹配甚至比外部匹配更加重要。
五、FOV內部匹配的解決方案(StereoController.cs)
StereoController這個類主要用來對雙眼(Cardboard Eye)進行控制和調整,它綁定在mono Camera上,對兩個子物體stereo Camera進行控制。
Controls a pair of CardboardEye objects that will render the stereo view of the camera this script is attached to.
這個腳本控制一對用來產生立體畫面的攝像機物體。
這個腳本下有幾個重要的屬性:
/***********************************************************************************************************************************/
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.
通過本控制器調整立體度等級。注意這個參數不是虛擬頭部的大小--使用scale來調整頭部物體,而是對眼睛離散度的控制,這個離散度也可以理解為視線怎樣傾斜。設置為0的時候,關閉立體效果。
上兩張圖大家就能發現這個參數的功能了:
這是一張stereoMultiplier設置為1時候的圖
這是stereoMultiplier設置為0時候的圖
兩者的差別,大家可以仔細的觀察一下(必須要很仔細很仔細的觀察,才能發現不同 :-D)
如果還是找不到不同,好吧,我們用兩張圖來表達差異:
平常,我們的眼睛觀察物體,是這樣的。
現在,stereoMultiplier設為0,是這樣的。
第一種方式,同時考慮了視線的傾斜,而第二種方式只是將畫面平視輸出,很顯然,如果想要更高的立體感,這個參數設為1更好。
/***********************************************************************************************************************************/
matchMonoFOV:
這個參數,就是上述的FOV內部匹配
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.
立體攝像機默認使用Cardboard設備實際的FOV,不然會導致頭部運動和場景運動的匹配關系破裂(這會影響沉浸感),然而,在一定情況下,也可以調整FOV(為了特效或者藝術感),但是長時間使用與實際視覺FOV不同的FOV是不允許的,這會讓用戶不舒服。這個值決定了mono Camera獲得的FOV的匹配度。0意味著不匹配,1意味著完全匹配,中間的值折中。不進行100%匹配的原因包括,保留VR的特性,VR模式下圖像的邊緣不易被非VR模式看到,不同類型的Cardboard進行兼容等。這個值通常讓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進行匹配的方式(前提是matchMonoFOV不是0)。默認是移動stereocameras(matchByZoom = 0),還有一種方式是簡單的對camera的視野進行縮放(matchByZoom = 1),中間的值,表示兩種方式的混合,不建議使用簡單縮放,因為它和頭部移動與場景移動的匹配相沖突。同樣縮放效果可以被保留用作特效,比如玩家通過望遠鏡觀看場景。注意移動匹配需要興趣中心點物體非空,否則會無效。
/***********************************************************************************************************************************/
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,我們需要一個被設計好的“興趣中心點”。這可以是一個空物體,也可以是非空物體,甚至是場景中玩家可能會關注的實際物體,FOV調整根據距離興趣中心點的距離以至于看起來與在mono camera中有同樣的尺寸。
radiusOfInterest:
在興趣中心為非空物體時,可以定義半徑大小。
綜上,可以看出Cardboard使用基于mono camera來調整每個stereo camera的方法,并且設置了興趣中心點,這個點相當于我們雙眼視線的中心交點,除了作為基準外,一些游戲為了吸引玩家注意也會在這個點上放置重要的物體。