ARkit 實(shí)戰(zhàn)教程(Xcode開發(fā))
ARKit 最近在開發(fā)圈實(shí)在是火,ios 開發(fā)者可以快速的進(jìn)行增強(qiáng)現(xiàn)實(shí)的開發(fā)省有,簡(jiǎn)化了許多步驟澜掩,之前了,我們AR醬也出了相應(yīng)的ARKit 系列教程芹敌,今天了算是ARKit 的實(shí)戰(zhàn)教程番外篇痊远,我們實(shí)現(xiàn)一些網(wǎng)上比較流行的一些AR功能。
ps:代碼地址:http://www.arparticles.com/portal.php?mod=view&aid=107
基礎(chǔ):現(xiàn)實(shí)模型
基礎(chǔ)效果演示:
打開Xcode氏捞,新建一個(gè)AR項(xiàng)目
這次我們用SceneKit 來渲染3D內(nèi)容碧聪。
進(jìn)入項(xiàng)目之后會(huì)有個(gè)smaple project,我們可以嘗試著運(yùn)行:
我們使用SceneKit繪制一個(gè)3D立方體液茎。SceneKit有幾個(gè)基本類逞姿,SCNScene是所有3D模型的容器辞嗡。要向場(chǎng)景添加內(nèi)容,你首先創(chuàng)建幾何滞造,幾何可以是復(fù)雜的形狀续室,或簡(jiǎn)單的像球體,多維數(shù)據(jù)集谒养,平面等挺狰。然后,將幾何模型放在在場(chǎng)景節(jié)點(diǎn)中买窟,并將其添加到場(chǎng)景中她渴。然后,SceneKit將遍歷場(chǎng)景圖并呈現(xiàn)內(nèi)容蔑祟。
- (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的坐標(biāo)系如下所示:
當(dāng)ARSession啟動(dòng)時(shí)趁耗,計(jì)算出的相機(jī)位置最初設(shè)置為X = 0,Y = 0疆虚,Z = 0苛败。
們可以看到立方體的兩面,我們可以稍后添加一些更高級(jí)的照明径簿,但現(xiàn)在我們可以在SCNScene實(shí)例上設(shè)置autoenablesDefaultLighting :
self.sceneView.autoenablesDefaultLighting = YES;
進(jìn)階:平面檢測(cè)+可視化
效果演示:
在我們開始之前罢屈,將一些調(diào)試信息添加到程序中,即渲染ARKit檢測(cè)到的功能點(diǎn)篇亭,我們可以打開我們的ARSCNView:
self.sceneView.debugOptions =
ARSCNDebugOptionShowWorldOrigin |
ARSCNDebugOptionShowFeaturePoints;
我們來檢測(cè)平面幾何缠捌,在ARKit中,可以通過設(shè)置planeDetection屬性來檢測(cè)水平平面译蒂。此值可以設(shè)置為ARPlaneDetectionHorizontal或ARPlaneDetectionNone曼月。
- (void)renderer:(id )renderer
didAddNode:(SCNNode *)node
forAnchor:(ARAnchor *)anchor {
SCNNode實(shí)例是ARKit創(chuàng)建的一個(gè)SceneKit節(jié)點(diǎn),它具有一些類似于方向和位置的屬性柔昼,然后我們獲得一個(gè)錨實(shí)例哑芹,這將告訴我們使用已找到的特定錨點(diǎn)的更多信息,如大小和中心位置的plane捕透。錨實(shí)例實(shí)際上是一個(gè)ARPlaneAnchor類型聪姿,比如我們可以得到plane的范圍和中心信息。
我們進(jìn)行渲染plane乙嘀,可以在虛擬世界中繪制一個(gè)SceneKit 3D平面末购。為此,我們創(chuàng)建一個(gè)繼承自SCNNode的Plane類虎谢。在構(gòu)造方法中盟榴,我們創(chuàng)建平面并相應(yīng)地調(diào)整它的大小:
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];
現(xiàn)在我們有我們的Plane類嘉冒,回到ARSCNViewDelegate回調(diào)方法中曹货,當(dāng)ARKit找到一個(gè)新的錨點(diǎn)時(shí)咆繁,我們可以創(chuàng)建我們的新plane:
if (![anchor isKindOfClass:[ARPlaneAnchor class]]) {
return;
Plane *plane = [[Plane alloc] initWithAnchor: (ARPlaneAnchor *)anchor];
[node addChildNode:plane];
更新Plane SceneKit,使得我們?cè)谝苿?dòng)時(shí)有更穩(wěn)定的效果顶籽。
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);
運(yùn)行,會(huì)發(fā)現(xiàn)如下一些效果礼饱。
添加物理效果
效果預(yù)覽:
在這個(gè)演示中坏为,當(dāng)用戶在屏幕上單擊時(shí),我們執(zhí)行一段代碼镊绪,這個(gè)代碼很簡(jiǎn)單匀伏,ARSCNView包含一個(gè)hitTest方法,可以通過獲得的屏幕坐標(biāo)點(diǎn)蝴韭,從相機(jī)中心通過該點(diǎn)投射一條射線够颠,并返回結(jié)果:
- (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];
通過上述代碼,我們可以得到射線與平面交叉點(diǎn)的世界坐標(biāo)榄鉴,并在該位置放置一些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];
我們給每個(gè)立方體一個(gè)physicsBody,它是SceneKit的物理引擎庆尘。
接下來剃诅,我們實(shí)現(xiàn)停止平面檢測(cè)的功能。用戶用兩個(gè)手指按住屏幕1秒鐘驶忌,那么我們會(huì)隱藏所有的平面并關(guān)閉平面檢測(cè)矛辕。
ARWorldTrackingSessionConfiguration *configuration = (ARWorldTrackingSessionConfiguration *)self.sceneView.session.configuration;
configuration.planeDetection = ARPlaneDetectionNone;
[self.sceneView.session runWithConfiguration:configuration];