从文档目录加载SCNParticleSystem

时间:2018-12-24 14:31:37

标签: ios swift scenekit arkit

我正在尝试从无法加载的下载包中加载SCNParticleSystem。

资源的路径。

file:///var/mobile/Containers/Data/Application/A91E9970-CDE1-43D8-B822-4B61EFC6149B/Documents/so/solarsystem.bundle/Contents/Resources/

                let objScene = SCNParticleSystem(named: "stars", inDirectory: directory)

该对象为空。

3 个答案:

答案 0 :(得分:0)

这是一个合理的问题,因为SceneKit并没有提供用于从主捆绑包之外的文件初始化粒子系统的现成解决方案(唯一的初始化方法SCNParticleSystem.init(named:inDirectory:)暗示SCNParticleSystem.scnp文件在主捆绑包中。

幸运的是,.scnp文件只是经过编码/存档的SCNParticleSystem实例,我们可以使用NSKeyedUnarchiver轻松地对其进行解码/取消存档:

extension SCNParticleSystem {
    static func make(fromFileAt url: URL) -> SCNParticleSystem? {
        guard let data = try? Data(contentsOf: url),
            let object = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data),
            let system = object as? SCNParticleSystem else { return nil }

        return system
    }
}

如果不需要支持iOS 9iOS 10,则可以使用NSKeyedUnarchiver.unarchivedObject(ofClass: SCNParticleSystem.self, from: data)代替NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(_:)并键入强制转换,这是iOS 11.0中引入的。

您最有可能遇到的另一个问题是缺少粒子图像。这是因为默认情况下,SceneKit将在主捆绑包中查找它们。从当前版本的iOS(iOS 12)和Xcode(Xcode 10)开始,.scnp文件(particleImage属性)中的粒子图像是String值,它们是主捆绑包中的纹理文件名(可能会更改,但可能不会更改,但是我们可以使用的东西不多)。

所以我的建议是获取该文件名,并在.scnp文件所在的同一目录中查找具有相同名称的纹理文件:

extension SCNParticleSystem {
    static func make(fromFileAt url: URL) -> SCNParticleSystem? {
        guard let data = try? Data(contentsOf: url),
            let object = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data),
            let system = object as? SCNParticleSystem else { return nil }

        if let particleImageName = system.particleImage as? String {
            let particleImageURL = url
                .deletingLastPathComponent()
                .appendingPathComponent(particleImageName)

            if FileManager.default.fileExists(atPath: particleImageURL.path) {
                system.particleImage = particleImageURL
            }
        }

        return system
    }
}

您只需设置图像文件的URLSceneKit就会从那里进行处理。


作为一点说明,推荐的可下载内容目录为Application Support目录,而不是Documents

  

应用程序支持:使用此目录存储所有应用程序数据文件,与用户文档相关的文件除外。例如,您可以使用此目录来存储由应用程序管理的应用程序创建的数据文件,配置文件,模板或其他固定或可修改的资源。应用可能会使用此目录来存储最初包含在应用捆绑中的资源的可修改副本。游戏可能会使用此目录来存储用户购买并从服务器下载的新关卡。

(来自File System Basics

答案 1 :(得分:0)

没有足够的代表来添加评论,因此将其添加为答案。

LëshaTurkowski的答案可以肯定地起作用,但是在仅使用NSURL加载粒子图像时遇到了问题。

所有粒子均显示为正方形,

  

如果值为nil(默认值),SceneKit会将每个粒子渲染为   小的白色正方形(由particleColor属性着色)。

SCNParticleSystem particleImage

  

在文档中说您可以使用   NSImage(在macOS中)或UIImage(在iOS中)实例,或NSString或   NSURL实例,包含图像文件的路径或URL。

最终没有使用NSURL,而是使用了UIImage并且可以正常加载。

    extension SCNParticleSystem {
    static func make(fromFileAt url: URL) -> SCNParticleSystem? {
        guard let data = try? Data(contentsOf: url),
            let object = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data),
            let system = object as? SCNParticleSystem else { return nil }

        if let particleImageName = system.particleImage as? String {
            let particleImageURL = url
                .deletingLastPathComponent()
                .appendingPathComponent(particleImageName)

            if FileManager.default.fileExists(atPath: particleImageURL.path) {
                // load up the NSURL contents in UIImage
                let particleUIImage = UIImage(contentsOfFile: particleImageURL.path)
                system.particleImage = particleUIImage
            }
        }

        return system
    }
}

答案 2 :(得分:0)

我发现,有时将 SCNParticleSystem 文件拖入您的项目(可能形成不同的项目)时,可能会由于 Xcode 中的某些错误而发生静默错误。因此,您无法获得对 SCNParticleSystem 实例的引用。

解决方案:检查目标中的 BuildSettings。 SCNPaticleSystem 和关联的 ImageFile 应该列在那里,然后你应该把它弄对。 (见下方截图)

ScreenShot