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];