說明
The Parallax View
The Parallax View是個國外開發者開發的好玩的軟體,它利用iPhoneX實現了裸眼3D的效果.
其實它是利用了iPhone X的ARKit面部追蹤介面和TrueDepth感測器。 通過追蹤使用者的頭部運動,確定眼睛在三維空間中的確切位置。 然後生成實時響應使用者位置的影像,從而為使用者帶來一種3D影像的錯覺。原理特點
通過使用ARKit和iPhone X進行3D頭部追蹤來獲得深度幻象。
為獲得最佳效果,應該只開啟一隻眼睛(該應用允許選擇要追蹤的眼睛,或者可以嘗試自動選擇眼睛)
通過跟蹤使用者頭部方向和位置,可以找到3D中的眼睛位置。
應用可以在該顯示器上呈現從該位置看到的正確檢視。
為了呈現該檢視,使用離軸投影(非對稱相機平截頭體)。
這給人一種錯覺,即物體出現在螢幕的前面和後面。
模仿
受此啟發,我嘗試在非iPhoneX裝置上用人臉識別框架來實現低精度的裸眼3D效果. 原理是:
- 利用人臉識別,檢測人臉位置;
- 將人臉的二維位置轉換到3維空間中(z軸固定,xy按比例轉換);
- 將轉換後的3D座標賦值給攝像機;
原本打算,用識別出人臉的大小,做為依據來判斷攝像機在z軸上的位置,但測試中發現,人臉識別出的大小變化很大,無規律可轉換.
建立模型
自己用SceneKit的編輯器搭建了一個場景,裡面有多根高度不同的柱子.人臉識別
原來以為蘋果的新框架Vision會更好,結果在我的iPhone SE上非常卡,而且Vision框架在識別人臉時對方向有要求,需要指定方向.所有最後還是使用了AVFoundation中的metadataObjectTypes來識別.
if session.canAddOutput(metaDataOutput) {
session.addOutput(metaDataOutput)
}
//7.AVFoundation框架識別型別
metaDataOutput.metadataObjectTypes = [.face]
複製程式碼
在代理方法中處理識別到的人臉:
//AV框架人臉識別
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
for obj in metadataObjects {
if obj.type == .face {
print("face---\(obj.bounds)")
// 座標轉換
let oldRect = obj.bounds;
let w = oldRect.size.height * self.previewView.bounds.size.width;
let h = oldRect.size.width * self.previewView.bounds.size.height;
let x = oldRect.origin.y * self.previewView.bounds.size.width;
let y = oldRect.origin.x * self.previewView.bounds.size.height;
// 新增矩形
rectLayer.frame = CGRect(x: x, y: y, width: w, height: h)
rectLayer.isHidden = false
//湊出合理的資料
let cameraX = (oldRect.origin.y - 0.3) * 2
let cameraY = (0.4 - oldRect.origin.x) * 2
// 移動攝像機
self.cameraNode.position = SCNVector3(cameraX, cameraY, 20)
}else {
rectLayer.isHidden = true
}
}
}
複製程式碼
效果初步有了:
但是我們還應該看到,我們的3D效果是通過直接移動攝像機的位置來實現,攝像機的視野範圍並沒有改變,所以看上去像是透過窗戶看後面的景物,而不是像The Parallax View那樣,3D物體像是與手機螢幕綁在一起.
最主要原因是:The Parallax View使用了離軸投影(非對稱相機平截頭體)處理攝像機看到的物體範圍,如下圖,不論如何移動,FOV(Field Of View)都始終對齊了底座的四個角:
投影變換
在SceneKit中,是可以給camera設定自定義的投影變換矩陣的
self.cameraNode.camera?.projectionTransform
蘋果也給出了說明,一旦設定該項,則對攝像機設定的 zFar
,zNear
, 和fieldOfView
都會失效,原因是這些值無法從矩陣中得到(數學上不可逆).
另外需要注意的是:ARKit中的ARSCNView類會重寫這個投影變換,所以不要在AR應用中修改.
如果有深厚的3D數學功底,只要重寫這個投影變換矩陣,就可以得到離軸投影效果,可惜我現在不會,相關配置還需要研究,以後更新.
程式碼
程式碼地址NakedEye3D