Swift SCENKEKIT SCNSCENERENDERDelegate-未调用渲染器函数
我最近问了一个问题,答案很明显。我还在做同一个项目,却遇到了另一个问题。我需要实现每帧逻辑,Swift SCENKEKIT SCNSCENERENDERDelegate-未调用渲染器函数,swift,macos,scenekit,Swift,Macos,Scenekit,我最近问了一个问题,答案很明显。我还在做同一个项目,却遇到了另一个问题。我需要实现每帧逻辑,scnscenerendereredelegate协议在iOS上运行得非常好,但在OSX上,渲染器功能没有启动。我创建了一个小示例项目来说明我的问题。它由情节提要中的场景工具包视图和ViewController类中的以下代码组成: import Cocoa import SceneKit class ViewController: NSViewController, SCNSceneRendererDe
scnscenerendereredelegate
协议在iOS上运行得非常好,但在OSX上,渲染器
功能没有启动。我创建了一个小示例项目来说明我的问题。它由情节提要中的场景工具包视图和ViewController
类中的以下代码组成:
import Cocoa
import SceneKit
class ViewController: NSViewController, SCNSceneRendererDelegate {
@IBOutlet weak var sceneView: SCNView!
let cubeNode = SCNNode()
override func viewDidLoad() {
super.viewDidLoad()
let scene = SCNScene()
let sphere = SCNSphere(radius: 0.1)
sphere.firstMaterial!.diffuse.contents = NSColor.yellowColor()
let sphereNode = SCNNode(geometry: sphere)
scene.rootNode.addChildNode(sphereNode)
let cube = SCNBox(width: 0.2, height: 0.2, length: 0.2, chamferRadius: 0)
cube.firstMaterial!.diffuse.contents = NSColor.greenColor()
cubeNode.geometry = cube
cubeNode.position = SCNVector3(1,0,0)
scene.rootNode.addChildNode(cubeNode)
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(2, 1, 2)
let constraint = SCNLookAtConstraint(target: cubeNode)
cameraNode.constraints = [constraint]
scene.rootNode.addChildNode(cameraNode)
sceneView.scene = scene
sceneView.backgroundColor = NSColor(red: 0.5, green: 0, blue: 0.3, alpha: 1)
sceneView.allowsCameraControl = true
sceneView.delegate = self
sceneView.playing = true
}
func renderer(renderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval) {
cubeNode.position.x += 0.1
}
}
我只想基本上用每一帧移动立方体。但什么也没发生。奇怪的是,当我将sceneView.allowsCameraControl
设置为true
时,每当我在屏幕上单击或拖动时就会调用渲染器
函数(这很有意义,因为它需要根据相机角度更新视图)。但我希望它被称为每一帧
是否有我看不到的错误,或者这是我的Xcode中的错误
编辑:
我已尝试按照下面答案中的说明进行操作,现在获得了ViewController的以下代码:
import Cocoa
import SceneKit
class ViewController: NSViewController {
@IBOutlet weak var sceneView: SCNView!
let scene = MyScene(create: true)
override func viewDidLoad() {
super.viewDidLoad()
sceneView.scene = scene
sceneView.backgroundColor = NSColor(red: 0.5, green: 0, blue: 0.3, alpha: 1)
sceneView.allowsCameraControl = true
sceneView.delegate = scene
sceneView.playing = true
}
}
还有一个MyScene类:
import Foundation
import SceneKit
final class MyScene: SCNScene, SCNSceneRendererDelegate {
let cubeNode = SCNNode()
convenience init(create: Bool) {
self.init()
let sphere = SCNSphere(radius: 0.1)
sphere.firstMaterial!.diffuse.contents = NSColor.yellowColor()
let sphereNode = SCNNode(geometry: sphere)
rootNode.addChildNode(sphereNode)
let cube = SCNBox(width: 0.2, height: 0.2, length: 0.2, chamferRadius: 0)
cube.firstMaterial!.diffuse.contents = NSColor.greenColor()
cubeNode.geometry = cube
cubeNode.position = SCNVector3(1,0,0)
rootNode.addChildNode(cubeNode)
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(2, 1, 2)
let constraint = SCNLookAtConstraint(target: cubeNode)
cameraNode.constraints = [constraint]
rootNode.addChildNode(cameraNode)
}
@objc func renderer(aRenderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval) {
cubeNode.position.x += 0.01
}
}
然而,它仍然不起作用。我做错了什么
编辑:设置sceneView.loops=true修复了描述的问题尝试此操作…将代码放在场景类中–保持视图控制器干净
final class MySCNScene:SCNScene, SCNSceneRendererDelegate
{
@objc func renderer(aRenderer:SCNSceneRenderer, updateAtTime time:NSTimeInterval)
{
}
}
还将视图的代理设置为场景:
mySCNView!。delegate=myscnsene我不明白是什么导致了问题,但我能够复制它。不过,我通过添加一个毫无意义的
SCNAction
,实现了这一目标:
let dummyAction = SCNAction.scaleBy(1.0, duration: 1.0)
let repeatAction = SCNAction.repeatActionForever(dummyAction)
cubeNode.runAction(repeatAction)
仅当场景正在“播放”时,渲染循环才会激发(请参见)。我希望是这样
sceneView.isPlaying = true
(正如您已经在做的)将足以触发渲染回调
我上面的代码不是一个解决方案。解决你的问题,让你继续生活,这是一个令人讨厌的黑客行为 对于仍有问题的任何人,设置代理和播放变量都可以
sceneView.delegate = self
sceneView.isPlaying = true
我怀疑答案取决于Querent所说的“每一帧”是什么意思。Querent可能应该澄清这一点,但无论如何我都会尝试回答,因为我就是这样 最简单的解释可能是“无论如何都会渲染的每一帧”,但这似乎不太可能是所希望的,除非立方体被用作渲染器的活动监视器,这似乎也不太可能;有更好的方法来解决这个问题
Querent可能希望在视图的属性为“是”时重复渲染。如果是这样的话,那么答案可能很简单,只需将视图的属性设置为YES即可。这最近为我解决了一个问题,我希望在按住键盘键时进行渲染。(我注意到,将playing设置为YES会导致对我的委托进行一次调用。)除了此链中的几个有用提示之外,我调用委托的最后一个提示是:如果对
SCNSceneRendererDelegate
类使用pre-Swift 4方法,则它编译良好,没有错误或警告,但从未调用该委托
因此,Swift 4之前过时的定义:
func renderer(aRenderer:SCNSceneRenderer, updateAtTime time:TimeInterval) {...}
(这是我从网上的一个片段中得到的)编译得很好,从未调用过,而正确的定义
func renderer(_ renderer:SCNSceneRenderer, updateAtTimet time:TimeInterval) {...}
编译并被调用
由于
SCNSceneRendererDelegate
是一个协议,因此覆盖提供的正常Swift保护不适用。由于scnscenerenderdelegate
将其方法定义为可选的(我喜欢),因此也不会以这种方式捕获它 故事板和视图控制器在这方面没有任何作用,实际上,这都是关于SCNView和您的SCNScene的。SCNView有一个场景属性,只需将SCNScene设置为它。子类化SCNScene
不是一个好主意。当您稍后尝试使用NSKeyedArchiver
进行序列化和反序列化时,您会遇到问题。在最初的代码示例中,OP已经将场景的委托设置为VC。那没用。至于SCNScene子类化,请阅读@rickster对我引用的帖子的回答。我自己过去一直都是SCNScene的子类。但是重复出现的归档和初始化问题、苹果的示例代码以及Xcode场景编辑器与SCNScene交互的方式都反对子类化。子类SCNNode,或者有一个单独的游戏类来保存游戏逻辑。请参阅这个带有工作呈现器和子类的示例项目。可以将SCNScene子类化,只需加载场景文件内容并将其添加到其中。简单干净!可以为SceneKit应用程序子类化SCNScene
,就像为文本编辑器子类化NSString
一样。这两种情况都不会带来直接的问题。然而,Cocoa及其相关框架鼓励组合而不是继承,以至于打算作为基本数据模型对象的子类化类型可能会在以后给您带来其他问题。谢谢,我将提交一份报告!我不明白这怎么可能是一个“解决方案”,通过添加一个毫无意义的条款…真的吗?人们在搜索答案时会感到困惑。@Nico如果你提交了一份报告,更新此线程是很重要的。但我怀疑他们会把你的报告当作bug来接受。我已经这么做了,但正如Integer Potter指出的,sceneView.loops=true解决了这个问题。没错!我也弄明白了,但忘了更新我的答案。在这种情况下,似乎这是应该接受的答案。