
var detectedDataAnchor: aranchor?var myVIEw = UIVIEw()overrIDe func vIEwDIDLoad() { super.vIEwDIDLoad() myVIEw = (Bundle.main.loadNibnamed("ARVIEwOne",owner: nil,options: nil)![0] as? UIVIEw)!}func renderer(_ renderer: SCNSceneRenderer,nodeFor anchor: aranchor) -> SCNNode? { if self.detectedDataAnchor?.IDentifIEr == anchor.IDentifIEr { let node = SCNNode() let Box = SCNBox(wIDth: 0.1,height: 0.1,length: 0.1,chamferRadius: 0.0) let imageMaterial = SCNMaterial() imageMaterial.diffuse.contents = myVIEw Box.materials = [imageMaterial] let cube = SCNNode(geometry: Box) node.addChildNode(cube) return node } return nil} @IBAction func back(_ sender: UIbutton) { // here the app freezes navigationController?.popVIEwController(animated: true) } 当回到我的VC时,我的应用程序不响应任何触摸事件
解决方法 好的,首先是第一件事:您无法将UIVIEw添加为SCNMaterialProperty的内容.阅读here.
我在这里猜测,但这可能是你看到的冻结/崩溃的原因,因为当你d出它所在的控制器时场景会被取消并试图清理那些实际上被破坏的材料(它会把它视为一些其他类型).
一般来讲就行
myVIEw = (Bundle.main.loadNibnamed("ARVIEwOne",options: nil)![0] as? UIVIEw)! 看起来像你对此有点新鲜(这完全没问题!).你是强行解缠和强制施放(以一种奇怪的方式,因为?UIVIEw!基本上就像!UIVIEw),这总是危险的.你确定你的xib中的第一个顶级对象是UIVIEw吗?此外,最初实例化的UIVIEw(在var myVIEw = UIVIEw()中从不使用,为什么不在这里使用可选的(你可以使用一个隐式解包的,虽然我自己不是这个的粉丝).这样做怎么样办法:
var myVIEwImage: UIImage?overrIDe func vIEwDIDLoad() { super.vIEwDIDLoad() let myVIEw = Bundle.main.loadNibnamed("ARVIEwOne",options: nil).first as? UIVIEw myVIEwImage = myVIEw?.asImage()}func renderer(_ renderer: SCNSceneRenderer,nodeFor anchor: aranchor) -> SCNNode? { guard let image = myVIEwImage,self.detectedDataAnchor?.IDentifIEr == anchor.IDentifIEr else { return nil } let node = SCNNode() let Box = SCNBox(wIDth: 0.1,chamferRadius: 0.0) let imageMaterial = SCNMaterial() imageMaterial.diffuse.contents = image Box.materials = [imageMaterial] let cube = SCNNode(geometry: Box) node.addChildNode(cube) return node}// this would be outsIDe your controller class,i.e. the top-level of a swift fileextension UIVIEw { func asImage() -> UIImage { let renderer = UIGraphicsImageRenderer(bounds: bounds) return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) } }} (UIVIEw扩展取自here,所以感谢Naveed J.)
这假设a)你的xib确实是正确的,并且b)你只想要“视图的外观”,即节点上的一种“屏幕截图”.它将是一个静止图像,显然,你不能将视图的整个行为(附加的手势识别器等)放到这样的节点上.对于这些事情,我建议你打开一个新问题(在你完成这个问题之后你会满意).
编辑以回应fabio的评论:
我忘了在不同的队列/线程上调用渲染器(_:nodeFor :).您确实应该仅在主线程上生成视图图像,因为警告“UIVIEw.bounds必须仅从主线程使用”说.我更改了上面的代码以反映这一点.请记住,swift本身并不是线程安全的,因为在渲染器开始发送渲染器(_:nodeFor :)之前,将调用vIEwDIDLoad()(在主线程上).因此,您可以确保在检索图像时不会出现访问冲突,但这意味着您不应该在主线程的某处修改所述图像.
如果你需要以某种方式改变图像/动态创建它有一个替代方案.我个人使用委托的另一种方法渲染器(_:dIDAdd:for :),而不是在渲染器中自己创建节点(_:nodeFor :).此方法不期望返回值,因此它看起来像这样:
var myVIEw: UIVIEw?overrIDe func vIEwDIDLoad() { super.vIEwDIDLoad() myVIEw = Bundle.main.loadNibnamed("ARVIEwOne",options: nil).first as? UIVIEw}func renderer(_ renderer: SCNSceneRenderer,dIDAdd node: SCNNode,for anchor: aranchor) { dispatchQueue.main.async { self.attachCustomNode(to: node,for: anchor) }}func attachCustomNode(to node: SCNNode,for anchor: aranchor) { guard let theVIEw = myVIEw,self.detectedDataAnchor?.IDentifIEr == anchor.IDentifIEr else { return } let Box = SCNBox(wIDth: 0.1,chamferRadius: 0.0) let imageMaterial = SCNMaterial() imageMaterial.diffuse.contents = theVIEw.asImage() Box.materials = [imageMaterial] let cube = SCNNode(geometry: Box) node.addChildNode(cube) return node} 通过从代理中省略渲染器(_:nodeFor :),ARKit会为您创建一个空节点.基本上你在渲染器中做的事情是相同的(_:nodeFor :).然后它调用渲染器(_:dIDAdd:for :),它不期望返回值.所以从那里我“切换到主队列”并添加必要的孩子.
我很确定这是有效的,IIRC SceneKit会自动在其渲染线程中批量添加(即它在节点的addChildNode()中实际执行的 *** 作).因此,上面的所有“准备工作”都发生在主线程上,您可以安全地使用视图的边界来创建图像.节点设置完成后,当您添加节点时,SceneKit会在其渲染线程上正确地执行此 *** 作.
你不应该做的只是在你的渲染器(_:nodeFor :)方法中放入dispatchQueue.main.async并在那里更改材质的漫反射内容.这意味着您可以从不同的线程修改添加的节点,但是您不能确定它是否可以正常工作.它可能看起来像是有效的,我不知道SceneKit是否会以某种方式防范它,但我不会依赖它.无论如何,这都是糟糕的风格.
我希望这一切足以使您的项目有效. 总结
以上是内存溢出为你收集整理的ios – ARKit添加UIView xib文件Swift 4全部内容,希望文章能够帮你解决ios – ARKit添加UIView xib文件Swift 4所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)