本帖最后由 xieyoulong 于 2017-8-8 19:33 编辑
ARKit 最近在开发圈实在是火,ios 开发者可以快速的进行增强现实的开发,简化了许多步骤,接下来我们实现一个简单的AR功能
打开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:
- - (void)renderer:(id )renderer
- didAddNode:(SCNNode *)node
- forAnchor:(ARAnchor *)anchor {
- if (![anchor isKindOfClass:[ARPlaneAnchor class]]) {
- return;
- }
- Plane *plane = [[Plane alloc] initWithAnchor: (ARPlaneAnchor *)anchor];
- [node addChildNode:plane];
- }
- 更新Plane SceneKit,使得我们在移动时有更稳定的效果。
- - (void)renderer:(id )renderer
- didUpdateNode:(SCNNode *)node
- forAnchor:(ARAnchor *)anchor {
- // See if this is a plane we are currently rendering
- Plane *plane = [self.planes objectForKey:anchor.identifier];
- if (plane == nil) {
- return;
- }
- [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) {
- return;
- }
- 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];
复制代码
ARKit技术交流qq群:482631386 ARVR训练营:www.arvrthink.com
文章转自AR酱:https://335284.kuaizhan.com/15/63/p4416344644c71d
|
|
|
|
|
|