ARkit 實戰教程(Xcode開發)
ARKit 最近在開發圈實在是火,ios 開發者可以快速的進行增強現實的開發,簡化了許多步驟,之前了,我們AR醬也出了相應的ARKit 系列教程,今天了算是ARKit 的實戰教程番外篇,我們實現一些網上比較流行的一些AR功能。
ps:代碼地址:http://www.arparticles.com/portal.php?mod=view&aid=107
基礎:現實模型
基礎效果演示:
打開Xcode,新建一個AR項目
這次我們用SceneKit 來渲染3D內容。
進入項目之后會有個smaple project,我們可以嘗試著運行:
我們使用SceneKit繪制一個3D立方體。SceneKit有幾個基本類,SCNScene是所有3D模型的容器。要向場景添加內容,你首先創建幾何,幾何可以是復雜的形狀,或簡單的像球體,多維數據集,平面等。然后,將幾何模型放在在場景節點中,并將其添加到場景中。然后,SceneKit將遍歷場景圖并呈現內容。
- (void)viewDidLoad {
[super viewDidLoad];
SCNScene *scene = [SCNScene new];
SCNBox *boxGeometry = [SCNBox
boxWithWidth:0.1
height:0.1
length:0.1
chamferRadius:0.0];
SCNNode *boxNode = [SCNNode nodeWithGeometry:boxGeometry];
boxNode.position = SCNVector3Make(0, 0, -0.5);
[scene.rootNode addChildNode: boxNode];
self.sceneView.scene = scene;
}
ARKit和SceneKit的坐標系如下所示:
當ARSession啟動時,計算出的相機位置最初設置為X = 0,Y = 0,Z = 0。
們可以看到立方體的兩面,我們可以稍后添加一些更高級的照明,但現在我們可以在SCNScene實例上設置autoenablesDefaultLighting :
self.sceneView.autoenablesDefaultLighting = YES;
進階:平面檢測+可視化
效果演示:
在我們開始之前,將一些調試信息添加到程序中,即渲染ARKit檢測到的功能點,我們可以打開我們的ARSCNView:
self.sceneView.debugOptions =
ARSCNDebugOptionShowWorldOrigin |
ARSCNDebugOptionShowFeaturePoints;
我們來檢測平面幾何,在ARKit中,可以通過設置planeDetection屬性來檢測水平平面。此值可以設置為ARPlaneDetectionHorizontal或ARPlaneDetectionNone。
- (void)renderer:(id )renderer
didAddNode:(SCNNode *)node
forAnchor:(ARAnchor *)anchor {
SCNNode實例是ARKit創建的一個SceneKit節點,它具有一些類似于方向和位置的屬性,然后我們獲得一個錨實例,這將告訴我們使用已找到的特定錨點的更多信息,如大小和中心位置的plane。錨實例實際上是一個ARPlaneAnchor類型,比如我們可以得到plane的范圍和中心信息。
我們進行渲染plane,可以在虛擬世界中繪制一個SceneKit 3D平面。為此,我們創建一個繼承自SCNNode的Plane類。在構造方法中,我們創建平面并相應地調整它的大小:
self.planeGeometry = [SCNPlane planeWithWidth:anchor.extent.x height:anchor.extent.z];
SCNNode *planeNode = [SCNNode nodeWithGeometry:self.planeGeometry];
planeNode.position = SCNVector3Make(anchor.center.x, 0, anchor.center.z);
planeNode.transform = SCNMatrix4MakeRotation(-M_PI / 2.0, 1.0, 0.0, 0.0);
[self addChildNode:planeNode];
現在我們有我們的Plane類,回到ARSCNViewDelegate回調方法中,當ARKit找到一個新的錨點時,我們可以創建我們的新plane:
if (![anchor isKindOfClass:[ARPlaneAnchor class]]) {
return;
Plane *plane = [[Plane alloc] initWithAnchor: (ARPlaneAnchor *)anchor];
[node addChildNode:plane];
更新Plane SceneKit,使得我們在移動時有更穩定的效果。
didUpdateNode:(SCNNode *)node
// See if this is a plane we are currently rendering
Plane *plane = [self.planes objectForKey:anchor.identifier];
if (plane == nil) {
[plane update:(ARPlaneAnchor *)anchor];
更新plane的寬度和高度。
- (void)update:(ARPlaneAnchor *)anchor {
self.planeGeometry.width = anchor.extent.x;
self.planeGeometry.height = anchor.extent.z;
self.position = SCNVector3Make(anchor.center.x, 0, anchor.center.z);
運行,會發現如下一些效果。
添加物理效果
效果預覽:
在這個演示中,當用戶在屏幕上單擊時,我們執行一段代碼,這個代碼很簡單,ARSCNView包含一個hitTest方法,可以通過獲得的屏幕坐標點,從相機中心通過該點投射一條射線,并返回結果:
- (void)handleTapFrom: (UITapGestureRecognizer *)recognizer {
CGPoint tapPoint = [recognizer locationInView:self.sceneView];
NSArray *result = [self.sceneView hitTest:tapPoint types:ARHitTestResultTypeExistingPlaneUsingExtent];
if (result.count == 0) {
ARHitTestResult * hitResult = [result firstObject];
[self insertGeometry:hitResult];
通過上述代碼,我們可以得到射線與平面交叉點的世界坐標,并在該位置放置一些3D模型等等。
- (void)insertGeometry:(ARHitTestResult *)hitResult {
float dimension = 0.1;
SCNBox *cube = [SCNBox boxWithWidth:dimension
height:dimension
length:dimension
chamferRadius:0];
SCNNode *node = [SCNNode nodeWithGeometry:cube];
node.physicsBody = [SCNPhysicsBody
bodyWithType:SCNPhysicsBodyTypeDynamic
shape:nil];
node.physicsBody.mass = 2.0;
node.physicsBody.categoryBitMask = CollisionCategoryCube;
float insertionYOffset = 0.5;
node.position = SCNVector3Make(
hitResult.worldTransform.columns[3].x,
hitResult.worldTransform.columns[3].y + insertionYOffset,
hitResult.worldTransform.columns[3].z
);
[self.sceneView.scene.rootNode addChildNode:node];
[self.boxes addObject:node];
我們給每個立方體一個physicsBody,它是SceneKit的物理引擎。
接下來,我們實現停止平面檢測的功能。用戶用兩個手指按住屏幕1秒鐘,那么我們會隱藏所有的平面并關閉平面檢測。
ARWorldTrackingSessionConfiguration *configuration = (ARWorldTrackingSessionConfiguration *)self.sceneView.session.configuration;
configuration.planeDetection = ARPlaneDetectionNone;
[self.sceneView.session runWithConfiguration:configuration];