ARKit示例 - 第3部分:添加几何和物理乐趣

在上一篇文章中,我们使用ARKit来检测现实世界中的水平平面,然后将这些平面可视化。在本文中,我们现在将开始为我们的AR体验添加虚拟内容,并开始与检测到的平面进行交互。

到本文结束时,我们将能够将立方体放入世界,将真实物理应用于立方体,以便它们相互作用并产生微型冲击波,使立方体飞得很快。

这是一个显示应用程序运行的视频,您可以看到我们首先如何捕获水平平面,然后我们添加一些3D立方体与场景交互,然后最终导致一些小型爆炸使立方体跳转:

youtube

与往常一样,您可以按照以下代码进行操作:https://github.com/markdaws/arkit-by-example/tree/part3

命中测试

正如您在第一个教程中看到的,我们可以在任何X,Y,Z位置插入虚拟3D内容,它将在现实世界中渲染和跟踪。现在我们有平面检测,我们想要添加与这些平面交互的内容。这将使应用程序看起来像桌子,椅子,地板等顶部有物体。

在这个应用程序中,当用户单击屏幕时,我们执行命中测试,这涉及获取2D屏幕坐标并通过2D屏幕点(在投影平面上具有3D位置)从相机原点发射Ray并进入现场。如果光线与任何平面相交,我们得到命中结果,然后我们获取光线和平面相交的3D坐标,并将我们的内容放置在该3D位置。

这个代码非常简单,ARSCNView包含一个hitTest方法,你传递屏幕坐标,它负责通过相机原点从那个点投射3D光线并返回结果:

- (void)handleTapFrom: (UITapGestureRecognizer *)recognizer {
  // Take the screen space tap coordinates and pass them to the
  // hitTest method on the ARSCNView instance
  CGPoint tapPoint = [recognizer locationInView:self.sceneView];
  NSArray *result = [self.sceneView   hitTest:tapPoint types:ARHitTestResultTypeExistingPlaneUsingExtent];
  // If the intersection ray passes through any plane geometry they
  // will be returned, with the planes ordered by distance 
  // from the camera
  if (result.count == 0) {
    return;
  }
  // If there are multiple hits, just pick the closest plane
  ARHitTestResult * hitResult = [result firstObject];
  [self insertGeometry:hitResult];
}

给定ARHitTestResult,我们可以获得光线/平面交叉发生的世界坐标,并在该位置放置一些虚拟内容。对于本文,我们将只插入一个简单的立方体,稍后我们将使对象看起来更逼真:

- (void)insertGeometry:(ARHitTestResult *)hitResult {
float dimension = 0.1;
SCNBox *cube = [SCNBox boxWithWidth:dimension 
                             height:dimension 
                             length:dimension 
                      chamferRadius:0];
SCNNode *node = [SCNNode nodeWithGeometry:cube];
// The physicsBody tells SceneKit this geometry should be
// manipulated by the physics engine
node.physicsBody = [SCNPhysicsBody         
                     bodyWithType:SCNPhysicsBodyTypeDynamic 
                            shape:nil];
node.physicsBody.mass = 2.0;
node.physicsBody.categoryBitMask = CollisionCategoryCube;
// We insert the geometry slightly above the point the user tapped
// so that it drops onto the plane using the physics engine
float insertionYOffset = 0.5;
node.position = SCNVector3Make(
  hitResult.worldTransform.columns[3].x,
  hitResult.worldTransform.columns[3].y + insertionYOffset,
  hitResult.worldTransform.columns[3].z
);
// Add the cube to the scene
[self.sceneView.scene.rootNode addChildNode:node];
// Add the cube to an internal list for book-keeping
[self.boxes addObject:node];
}

添加一些物理

AR假设是为了增强现实世界,所以为了使我们的物体感觉更逼真,我们将添加一些物理来给予一种重量感。

正如您在上面的代码中所看到的,我们为每个立方体提供了一个physicsBody,它指示了SceneKit物理引擎,这个几何应该由物理引擎控制。然后我们还给每个ARKit检测到物理体的平面,以便立方体可以与平面交互(有关更多确切的细节,请参阅github 仓库中的Plane.m类)。

停止平面检测

一旦我们绘制了世界并拥有多个平面,我们就不希望ARKit继续为我们提供新的平面并可能更新现有的平面,因为这可能会影响我们已经添加到世界的几何体。

在这个应用程序中,如果用户按住两个手指一秒钟,那么我们隐藏所有平面并关闭平面检测。为此,您需要更新ARSession配置的planeDetection属性并重新运行会话。默认情况下,会话将保持相同的坐标系和找到的任何锚点:

// Get our existing session configuration
ARWorldTrackingSessionConfiguration *configuration = (ARWorldTrackingSessionConfiguration *)self.sceneView.session.configuration;
// Turn off future plane detection and updating
configuration.planeDetection = ARPlaneDetectionNone;
// Re-run the session for the changes to take effect
[self.sceneView.session runWithConfiguration:configuration];

下一个

在下一篇文章中,我们将向后退一小步,看看我们已编写的一些代码是否有用,添加了一些用于启用/禁用功能的UI控件。我们还将使用光照和纹理来使插入的几何图形看起来更逼真。

原文:https://blog.markdaws.net/arkit-by-example-part-3-adding-geometry-and-physics-fun-8dd2b90037f2
作者:Mark Dawson

你可能感兴趣的:(ARKit示例 - 第3部分:添加几何和物理乐趣)