ARkit 實(shí)戰(zhàn)教程(Xcode開(kāi)發(fā))

ARkit 實(shí)戰(zhàn)教程(Xcode開(kāi)發(fā))


ARKit 最近在開(kāi)發(fā)圈實(shí)在是火,ios 開(kāi)發(fā)者可以快速的進(jìn)行增強(qiáng)現(xiàn)實(shí)的開(kāi)發(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ǔ)效果演示:

打開(kāi)Xcode,新建一個(gè)AR項(xiàng)目

這次我們用SceneKit 來(lái)渲染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è)+可視化

效果演示:

在我們開(kāi)始之前,將一些調(diào)試信息添加到程序中,即渲染ARKit檢測(cè)到的功能點(diǎn),我們可以打開(kāi)我們的ARSCNView:

self.sceneView.debugOptions =

ARSCNDebugOptionShowWorldOrigin |

ARSCNDebugOptionShowFeaturePoints;

我們來(lái)檢測(cè)平面幾何,在ARKit中,可以通過(guò)設(shè)置planeDetection屬性來(lái)檢測(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)整它的大?。?/p>

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方法,可以通過(guò)獲得的屏幕坐標(biāo)點(diǎn),從相機(jī)中心通過(guò)該點(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];

通過(guò)上述代碼,我們可以得到射線與平面交叉點(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的物理引擎。

接下來(lái),我們實(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];

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容