ARKit —几何,材质,节点,手势哦,我的天哪!

本章是我的《 iOS开发者的ARKit》一书的一部分。 立即获取该书,并开始构建出色的增强现实应用程序。

在上一章中,您了解了创建默认ARKit应用程序所涉及的组件。 您还亲眼目睹了一只漂浮在您面前的太空船。 希望您已将其失踪的太空船告知了NASA!

在本章中,您将学习如何创建具有不同几何形状的虚拟对象,使用材质进行装饰,最后将它们作为SceneKit节点对象添加到现实世界中。 您还将学习如何使用手势和命中测试与虚拟对象进行交互。 让我们学习一些毕达哥拉斯定理。

几何:

几何表示与形状相对应的对象的线框。 SceneKit框架开箱即用地支持许多几何,此处显示了其中的一些。

SCNPlane :指定宽度和高度的矩形单边几何

SCNSphere :球形(或球形或球形)几何

SCNBox :六面多面体几何,其面均为矩形,可以选择带有圆角和圆角

SCNPyramid :直角金字塔几何

SCNTube :管的几何形状。 右圆柱体,其中心轴上有一个圆孔

每个类别代表一个特定的几何形状,可以一起使用以创建更复杂的形状。

材料:

默认情况下,几何图形只是线框。 您可以将几何体视为人类的骨骼。 材质就是您用肉装饰骨架的方式。 素材可以是颜色,图像甚至视频。 在阅读本节内容时,请确保您没有靠近食人族,否则他们可能会有错误的主意。

节点:

节点代表可以添加到场景中的对象。 只要未明确隐藏,添加到场景中的任何内容都可以被用户看到。 您可以将节点视为屏幕上的单个元素。 如果您要构建赛车游戏,那么一个节点可以代表一辆汽车。 如果要构建太空飞船游戏,则该节点可以是太空飞船,而一个单独的节点可以代表导弹。 节点也可以是复合节点,这意味着它们可以包含其他节点。 您可以想到一个代表大型卡车的节点,以及一个代表拖车,轮胎,货物等的子节点。

为真实世界添​​加形状:

首先,我们向增强现实世界添加一些形状。 在Xcode 9中创建一个新的Augmented Reality项目,并将清单1中的代码添加到viewDidLoad函数。

 覆盖func viewDidLoad(){ 
  super.viewDidLoad() 
  //设置视图的委托 
  sceneView.delegate =自我 
  //创建一个新场景 
 让场景= SCNScene() 
  let box = SCNBox(宽度:0.2,高度:0.2,长度:0.2,倒角半径:0) 
 让boxNode = SCNNode(geometry:box) 
  boxNode.position = SCNVector3(0,0,-0.5) 
  scene.rootNode.addChildNode(boxNode) 
  //将场景设置为视图 
  sceneView.scene =场景 
  } 

清单1:在场景中添加一个盒子

我们首先创建一个SCNBox几何体,该几何体表示我们正在构建的立方体形状。 我们指定了盒子的宽度,高度,长度和chamferRadius。 倒角半径表示盒子的拐角半径,我们将其设置为0表示我们不需要拐角半径。

注意 :使用SceneKit时的度量单位为米。 这意味着您将要设置的尺寸和位置将以米为单位进行计算。

接下来,我们创建一个SCNNode对象,该对象使用几何作为参数。 这意味着,当我们将节点添加到场景中时,由于已将框指定为几何体,因此它将像框一样。 我们将z轴的值设置为-0.5米,这表示物体将被放置在我们较远的位置 。 最后,我们将boxNode作为子级添加到场景的rootNode中。 这使该节点在屏幕上可见。 图1显示了实际显示的框。

图1:向场景添加盒子

惊人而简单的权利!

本章是我的《 iOS开发者的ARKit》一书的一部分。 立即获取书籍,并开始为iOS构建出色的增强现实应用程序

目前,我们的盒子没有使用任何材料,这就是为什么它看起来是白色的原因。 为了改变盒子的外观,我们需要用一种材料装饰它。 清单2显示了使用SCNMaterial类创建材料并将其应用于框的所有侧面的实现。

 覆盖func viewDidLoad(){ 
  super.viewDidLoad() 
  //设置视图的委托 
  sceneView.delegate =自我 
  //创建一个新场景 
 让场景= SCNScene() 
  let box = SCNBox(宽度:0.2,高度:0.2,长度:0.2,倒角半径:0) 
 让材质= SCNMaterial() 
  material.diffuse.contents = UIColor.red 
  box.materials = [材料] 
 让boxNode = SCNNode(geometry:box) 
  boxNode.position = SCNVector3(0,0,-0.5) 
  scene.rootNode.addChildNode(boxNode) 
  //将场景设置为视图 
  sceneView.scene =场景 
  } 

清单2:将材料应用于包装盒

材质对象的漫反射属性控制阴影将如何受到光的影响。

图2:设置几何材质

这很棒! 但是通常在增强现实应用程序中,您希望使虚拟物品看起来更像真实物品,以便它们可以轻松融入现实世界。 红色很棒,但是如果我们可以用真实世界的纹理代替它,那就更好了。

以下代码段显示了如何将图像用作材料而不是颜色。

  material.diffuse.contents = UIImage(名称:“ brick.png”) 

而不是指定颜色,我们指定的图像将用作盒子的材料。 图3显示了使用图像作为素材的结果。

图3:将图像设置为几何材质

将图像用作纹理时,请确保该纹理与环境完美融合,从而使人幻想它是真实世界的一部分。

添加触摸事件:

在本节中,我们将学习如何向SCNSphere形状添加纹理,并允许用户在触摸球体时循环浏览纹理列表。

与前面讨论的盒子示例类似,我们将从几何开始。 这次,我们将使用SCNSphere类,该类将允许我们使用球体几何来创建虚拟对象。 清单3显示了创建球体节点并将其添加到场景的实现。

 设Sphere = SCNSphere(半径0.3) 
 让sphereNode = SCNNode(geometry:sphere) 
  sphereNode.position = SCNVector3(0,0,-0.5) 

清单3:创建一个球体

我们以米为单位指定球体的半径,然后将其添加到球体节点。 最后,将SphereNode对象添加到场景中。 因为我们没有设置球节点的材质,所以它以白色物体的形式出现。 我们将使用代表我们美丽的星球“地球”的纹理来装饰我们的球体。 清单4显示了如何使用用作材料的图像来装饰球体。

 设Sphere = SCNSphere(半径0.3) 
 让材质= SCNMaterial() 
  material.diffuse.contents = UIImage(名称:“ earth.jpg”) 
  sphere.materials = [material] 
 让sphereNode = SCNNode(geometry:sphere) 
  sphereNode.position = SCNVector3(0,0,-0.5) 

清单4:使用地球材料创建球体几何

继续运行该应用程序,一定会感到惊讶!

图4:设置球体几何的纹理

接下来,我们将为我们的星球添加触摸手势。 这将使我们能够在不同的纹理之间循环并更新球体以反映新的星球。 我们这样做的唯一原因是让我们的邻居开心,以免他们入侵我们美丽的星球。

第一步是为场景视图注册轻击手势。 这可以通过使用清单5所示的UITapGestureRecognizer类来完成。

 私人功能寄存器GestureRecognizers(){ 
 让tapGestureRecognizer = UITapGestureRecognizer(目标:自我,行动​​:#选择器(点击)) 
  self.sceneView.addGestureRecognizer(tapGestureRecognizer) 
  } 

清单5:为场景视图注册轻敲手势

从viewDidLoad函数内部调用registerGestureRecognizer函数,该函数将确保在加载视图时注册手势。 对于每个轻击事件,将调用轻击功能。 利用点击功能,我们将在其中编写代码以检查用户是否点击了虚拟对象。

清单6中的实现显示了如何检测场景视图中的节点是否拦截了用户的触摸。

  @objc func点击(识别器:UITapGestureRecognizer){ 
 让sceneView = ogniser.view为!  ARSCN查看 
 让touchLocation = Recognitor.location(in:sceneView) 
 让hitResults = sceneView.hitTest(touchLocation,选项:[:]) 
 如果!hitResults.isEmpty { 
  //这表示该节点已被触摸 
  } 
  } 

清单6:命中测试检测

我们首先获得2D空间中的触摸位置。 这可以通过identifier.location函数来完成,该函数将视图作为参数并返回CGPoint结构作为触摸位置。 接下来,我们使用ARSCNView的类特殊方法hitTest,该方法可以将触摸的位置作为CGPoint,并返回表示沿点线段找到的对象的结果。

接下来,我们需要访问与线段相交的节点。 这很容易,因为SCNHitTestResult实例由称为节点的属性组成,该属性引用相交的节点。 有了节点,我们就可以简单地更改其使用的材料类型并完成吊臂。 清单7显示了tapped函数的更新实现。

  @objc func点击(识别器:UITapGestureRecognizer){ 
 让sceneView = ogniser.view为!  ARSCN查看 
 让touchLocation = Recognitor.location(in:sceneView) 
 让hitResults = sceneView.hitTest(touchLocation,选项:[:]) 
 如果!hitResults.isEmpty { 
 如果index == self.textures.count { 
 索引= 0 
  } 
 警卫让hitResult = hitResults.first else { 
 返回 
  } 
 让节点= hitResult.node 
  node.geometry?.firstMaterial?.diffuse.contents = UIImage(名称:textures [index]) 
 指数+ = 1 
  } 
  } 

清单7:在触摸手势上更改虚拟对象的材质

继续运行该应用程序! 该应用程序将从显示现实世界中美丽的地球开始。 如果触摸行星,您会注意到它将改变材质以反映纹理数组中的下一个行星。 确保您不要触摸金星,因为高温会烫伤您的手。

结论:

在本章中,我们学习了如何使用几何来创建不同的形状。 我们用材料装饰了以几何图形表示的线框,使其更具逼真的感觉。 最后,我们使用手势和命中测试与现实世界中的虚拟对象进行交互。