将模型添加到场景中 - 在您的环境中显示3D内容

在最后几节中,我们能够检测到一个平面并显示一个焦点方块,以帮助我们为模型指定一个位置。我们也熟悉了热门测试和世界变换。现在,我们拥有显示虚拟对象所需的所有工具。在本教程中,我们将学习如何检索模型并使用按钮的触发器将其呈现在场景中。一旦显示,我们将隐藏焦点方块。

下载

要学习本教程,您需要Xcode 9或更高版本,以及Focus Square的最终Xcode项目。您可以下载本节的最终Xcode项目,以帮助您与自己的进度进行比较。

基本视图

Main.Storyboard中,我们已经提到ARSCNView默认放在视图控制器的顶部。但是,如果没有UIView作为基础,则仅限于您可以在用户界面上执行的操作。为了能够正确添加我们的按钮,我们必须删除当前的 ARSCNView并首先从对象库添加UIView作为底层。接下来,选择相同的ARKit SceneKit View并将其放回UIView之上。调整大小以填充整个视图控制器。

约束

然后,单击Storyboard编辑器左下角的第四个图标,将新约束添加到场景视图中。定义约束以确保您的用户界面适应不同的屏幕尺寸或设备方向。设置为0顶部底部。确保它们都被约束到视图而不是安全区域,然后单击Add Constraints安全区域是凹口下方和主页指示器上方的边距,通常是屏幕的可见部分。此外,请确保未选中“ 限制到边距”

如果被限制在安全区域而不是超级视图,这就是看起来的样子,显然,这看起来并不好看。

横屏约束安全区

重新 Outlet

请记住,一个IBOutletsceneView链接到ARSCNView?因为我们删除了旧的ARSCNView,所以它打破了这个Outlet。我们需要重新考虑新的。为此,请打开“ 助理”编辑器,该图标看起来像两个交织在一起的圆圈。现在,我们并排放置两个分屏,非常适合连接。在右侧,我们有ViewController.swift,在那里我们可以找到该出口的声明。单击并拖动左侧的圆圈,它应该是第15行,然后释放到ARSCNView上。现在,关闭助理编辑。

添加按钮

我们想在视图中添加一个按钮,用作在场景中添加模型的触发器。从对象库中,将UIButton拖动到场景视图的顶部。在“ 属性”检查器中,删除“ 按钮”标题并将图像设置为“ 按钮/添加”

约束到底部20但这次是在安全区域,并取消选中Constrain到边距。然后,将鼠标悬停在左侧的“ 对齐”图标上,并在“容器”中选中“水平”以在屏幕中水平居中。

添加按钮功能

我们刚刚在屏幕上添加了按钮,但它根本没有做任何事情。当我们触摸它时,让按钮执行某些操作。现在,打开Assistant编辑器并控制将故事板中的按钮拖到ViewController类。代码中的顺序并不重要,因为我们稍后会移动此函数。原因是我们不能在扩展类中执行此操作。将Connection更改为Action,将其命名为addObjectButtonTapped。保持原样。完成后,关闭“ 助理”编辑器

@IBAction func addObjectButtonTapped(_ sender: Any) {
    print("Add button tapped")
}

让我们运行应用程序来查看我们的新按钮。但在此之前,评论一些印刷品陈述是明智的。转到updateFocusSquare()并注释掉这些代码行。

// print("Focus square hits a plane")

// print("Focus square does not hit a plane")

对象添加文件

让我们创建另一个swift文件,以便在场景中添加模型。右键单击视图控制器+ ARSCNViewDelegate.swift并选择新建文件...。然后,选择Swift File,单击Next。称之为ViewController + ObjectAddition,然后是Create

导入套件(Kits)

与往常一样,用以下框架替换Foundation。然后,向ViewController添加扩展。

import UIKit
import SceneKit
import ARKit

extension ViewController {}

检索模型

在扩展内部,创建一个新函数来检索我们选择的模型是一个很好的主动。此函数仅在此文件中使用,因此我们将采用fileprivate。将有一个String类型的参数,它将有两个名称。在函数外部使用的那个被命名,而在函数内使用的是名称。它将返回一个可选的SCNNode

fileprivate func getModel(named name: String) -> SCNNode? {}

与飞船场景类似,我们将使用我们指定的名称调用场景。然后,检索该场景SketchUp的父节点。我们递归设置为false以返回具有该名称的直接子节点。如果为true,它将解析所有节点,直到找到它为止。我们知道SketchUp是场景中唯一的节点,所以在我们的情况下,真实的不准确。之后,我们将变量名称分配给模型的名称。最后,此函数将在调用时返回模型。

let scene = SCNScene(named: "art.scnassets/\(name)/\(name).scn")!
guard let model = scene.rootNode.childNode(withName: "SketchUp", recursively: false) else {return nil}
model.name = name
return model

可选:PIVOT POINT FIX

如果您需要将模型的轴心点修改为所有3轴的中心,那么您可以在此处执行此操作。您可以使用以下公式。别客气。

let min = model.boundingBox.min
let max = model.boundingBox.max

model.pivot = SCNMatrix4MakeTranslation(
    min.x + (max.x - min.x) / 2,
    min.y + (max.y - min.y) / 2,
    min.z + (max.z - min.z) / 2)

显示模型

我们刚刚完成了这个功能,现在,我们准备在点击按钮时在场景中显示我们的模型。让我们转到ViewController.swift并剪切动作函数addObjectButtonTapped并将其粘贴到这里以将其全部放在一个地方。

我们首先确保焦点方块首先存在,因为它只在检测到表面时才出现在屏幕上。

guard focusSquare != nil else {return}

我们选择展示的模型是iPhoneX。因此,我们将使用getModel函数检索该模型。如果由于某种原因它失败了,我们将打印一条消息给我们。然后,让我们用一个小消息将它添加到场景中。

let modelName = "iPhoneX"
guard let model = getModel(named: modelName) else {
    print("Unable to load \(modelName) from file")
    return
}

sceneView.scene.rootNode.addChildNode(model)
print("\(modelName) added successfully")

运行应用程序。您将意识到该设备不仅站起来而且漂浮在空中。当然,我们已经在场景中添加了我们的模型,我们还没有把它放在表面上。所以,让我们这样做。

命中测试

显然,我们将再次使用命中测试,方法与之前相同。

let hitTest = sceneView.hitTest(screenCenter, types: .existingPlaneUsingExtent)
guard let worldTransformColumn3 = hitTest.first?.worldTransform.columns.3 else {return}
model.position = SCNVector3(worldTransformColumn3.x, worldTransformColumn3.y, worldTransformColumn3.z)

翻转设备

要将电话平放在桌子上,请打开iPhoneX.scn。在“ 节点”检查器中,将x Euler Angle重置为0

让我们再试一次。现在,我们的设备看起来更像是在房间里。

缩放模型

如果您选择了其他型号,您可能已经注意到尺寸不合适。因此,我们将扩展它们中的每一个。我们在iPhoneX的场景编辑器中完成了它。现在,我们在这里撤消它并代之以编码。让我们为所有边界将比例放回到1

回到ViewController + ObjectAddition并在getModel函数中,我们首先为比例声明一个变量,然后根据模型设置不同的值。在我们的情况下,使用[switch]控制流来匹配我们设置的许多条件是完美的。switch语句必须是详尽的,这就是为什么有一个默认情况来涵盖所有其他方案。

var scale: CGFloat

switch name {
    case "iPhoneX":         scale = 0.025
    case "iPhone6s":        scale = 0.025
    case "iPhone7":         scale = 0.0001
    case "iPhone8":         scale = 0.000008
    case "iPhone8Plus":     scale = 0.000008
    case "iPad4":           scale = 0.0006
    case "MacBookPro13":    scale = 0.0029
    case "iMacPro":         scale = 0.0245
    case "AppleWatch":      scale = 0.0000038
    default:                scale = 1
}

在返回之前将模型缩放到我们之前分配的值。

model.scale = SCNVector3(scale, scale, scale)

场景模型

知道我们在场景中有多少模型会很高兴。在ViewController.swift中,将一个新的类变量声明为一个节点数组,我们将其初始化为空。

var modelsInTheScene: Array<SCNNode> = []

返回ViewController + ObjectAddition.swift,并在addObjectButtonTapped操作方法的末尾您添加的每个模型追加到数组modelsInTheScene中。然后,打印该数组的计数

modelsInTheScene.append(model)
print("Currently have \(modelsInTheScene.count) model(s) in the scene")

我们如何运行应用程序并坚果?

焦点方块隐藏/显示选项

当我们在屏幕上显示模型时,我们仍然看到焦点方块干扰了我们漂亮的模型。如果我们在安置后隐藏它,你怎么说?

FocusSquare类中,让我们创建一个函数来为焦点方块的表示设置动画。将隐藏和显示两种情况,因此隐藏值是布尔值。然后我们声明一个SCNAction用于淡入淡出,淡出用于隐藏和淡入显示。这些行动将运行根据是否隐藏是真还是假,一前一后。为此目的使用序列

func setHidden(to hidden: Bool) {
    var fadeTo: SCNAction
        
    if hidden {
        fadeTo = .fadeOut(duration: 0.5)
    } else {
        fadeTo = .fadeIn(duration: 0.5)
    }
        
    let actions = [fadeTo, .run({ (focusSquare: SCNNode) in
        focusSquare.isHidden = hidden
    })]
    runAction(.sequence(actions))
}

视图观点

下一步将有点棘手。如果我们看到模型,我们希望隐藏焦点方块,对吧?但是,如果我们在屏幕上看不到任何内容呢?我们再次需要它来选择下一个位置。我们在屏幕上看到的是不断变化的,所以我们需要在updateFocusSquare()中实现它。在那里,让我们将pointOfView设置为场景视图的视角。

guard let pointOfView = sceneView.pointOfView else {return}

然后,让我们将firstVisibleModel的定义作为场景中的第一个模型。我们正在使用第一个返回满足条件的第一个元素的方法。如果节点从视角可见,它将返回true或false 。

let firstVisibleModel = modelsInTheScene.first { (node) -> Bool in
    return sceneView.isNode(node, insideFrustumOf: pointOfView)
}

隐藏/显示焦点方块

现在,如果第一个模型是可见的而不是零,则模型将在视图中可见。请记住,如果显示模型,我们将隐藏焦点方块,反之亦然。如果这两个因子的值不相等,我们将改变焦点平方的isHidden值。

let modelsAreVisible = firstVisibleModel != nil

if modelsAreVisible != focusSquareLocal.isHidden {
    focusSquareLocal.setHidden(to: modelsAreVisible)
}

实际上,这一切都令人困惑。我们实际上没有选择,因为节点具有isHidden的属性,并且不显示一个for。好吧,不是我所知道的。

那么,让我们来看看这两个场景。如果modelsAreVisible为true且focusSquareLocal.isHidden为false,则表示两者都可见,然后使setHidden为true(与modelsAreVisible值相同)以隐藏焦点方块。另一方面,如果modelsAreVisible为false且focusSquareLocal.isHidden为true,则两者都无处可见,然后setHidden为false以显示焦点方块。听起来很合乎逻辑。有了它,让我们最后一次运行应用程序。

结论

经过漫长的旅程,我们终于将我们的模型添加到我们的环境中,好像它们属于它。我们在本节中也学到了其他有用的概念。我们在故事板中定制了我们的视图,并在代码中播放动画。在下一课中,我们将使用虚拟对象本身。敬请关注。

原文: https://designcode.io/arkit-adding-models

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容

  • 1 CALayer IOS SDK详解之CALayer(一) http://doc.okbase.net/Hell...
    Kevin_Junbaozi阅读 4,981评论 3 23
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,611评论 4 59
  • 我去买满天星 唯一一株满天星 长势喜人的满天星 当时店员不在 我便想着大不了下次再来买 其实心里也知道 有些花不在...
    Zack要多喝热水阅读 228评论 0 0
  • 又是一个雨天,心情如这雨,无助凄凉。看尽事态繁华与落幕,正义的泯灭与人性的残忍,独自一个人在悲伤,一如这雨,如诉如泣。
    大道自然123阅读 280评论 0 0
  • 现在电商卖家都会有一种感觉,电商越来越难做了,这不仅仅是中小店铺所面临的苦恼,第一波入驻某宝的老店铺也开始重新审视...
    Helloii阅读 400评论 0 0