SCNScene is nil when loading using `named: ` - ios

I am using the following code to render a scene in scenekit and it works perfectly when the dae file is loaded from art.scnassests folder.
let scene = SCNScene(named: "art.scnassets/idle.dae")
However I want to download the asset and apply it and I am getting an error
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let scene = SCNScene(named: documentsURL.absoluteString+"idle.dae")
A file named idle.dae exists in the folder.
I get the error: fatal error: unexpectedly found nil while unwrapping an Optional value
How to load the downloaded asset and apply dynamically? What am I doing wrong? Any pointers please? I am a noob to iOS programming.

Unless something has changed for iOS 11, you won't be able to download and instantiate a DAE file at runtime on iOS. They are compressed/compiled at build time using a utility named scntool.
Can you instead use one of the file formats supported by Model I/O? See https://developer.apple.com/videos/play/wwdc2015/602/?time=320 for the original list (Alembic .abc, Polygon .ply Triangles .stl, WaveFront .obj), and https://developer.apple.com/videos/play/wwdc2017/610/ for a quick discussion of Pixar's USD (Universal Scene Description).
If you're stuck with DAE files, Frederik Jacques has an article at https://the-nerd.be/2014/11/07/dynamically-load-collada-files-in-scenekit-at-runtime/ which outlines his experience reverse engineering the DAE processing pipeline. His technique allows downloaded SCN files which have been processed from DAE files on a server.
See also Load uncompressed collada file using iOS Scene Kit (with comments by an authoritative source) and https://forums.developer.apple.com/thread/38010.

Related

SCNSceneSource identifiers with usdz file are empty

We are working on a project with ARKit 2 + SceneKit, iOS 12.
We were able to retrieve CAAnimation instances with .dae files and control them at runtime.
Now, we are trying .usdz, but none of the classes can be extracted from SCNSceneSource with usdz :
let source = SCNSceneSource(url: url, options: options)
let animationIdentifiers = source?.identifiersOfEntries(withClass: CAAnimation.self)
animationIdentifiers is always empty. The same goes for all classes listed in the documentation for this function https://developer.apple.com/documentation/scenekit/scnscenesource/1523656-identifiersofentries
We have tested our own usdz creations as well as some usdz from https://fusionar.app.
Tough, the animations play nicely when viewing the file either on iOS or in Xcode, where we have access to the animations and scene graph settings :
But definitely not from code at runtime, so we are unable to control the animations.
Have you ever had this issue ?
Any insight on this ?
Retrieving entries from a SCNSceneSource only works for Collada files. When working with USDZ file you'll have to traverse the node hierarchy and retrieve the animation from the node that holds it using -animationPlayerForKey:.

How to generate smaller url bookmarks in Swift?

I want to create bookmarks for locally stored files so that the files can be tracked if they are moved to new locations.
My attempts to use Swift 3's NSURL function bookmarkData(options:includingResourceValuesForKeys:relativeTo) finds it obligatorily generating bookmark data objects that are almost a megabyte in size, even in cases in which the files themselves are orders of magnitude smaller than that.
For example, for a 4-byte text file, the following code produces 410kb bookmark data.
(Running in AppDelegate's applicationDidFinishLaunching, OS X, Xcode 8.2)
(Note that when I tried using NSURL.BookmarkCreationOptions.minimalBookmark, instead of .suitableForBookmarkFile, the output was only 0kb and I could not use it to track the original file.)
Similarly, bookmarking a 19kb .jpg file produces an 888kb bookmark.
Am I doing something wrong? If not, is there a way to get bookmarks that is not quite so greedy?
let url = URL(fileURLWithPath: "/Users/U/test.txt", isDirectory: false)
if let urlBookmark = try? url.bookmarkData(options: .suitableForBookmarkFile, includingResourceValuesForKeys: nil, relativeTo: nil) {
print("bookmark size = \(urlBookmark.count / 1024) kb")
}
Edit:
From a few further quick and dirty tests, I see that the size of the bookmark is fixed and is determined by the file's category rather than by the file's size:
.pages 479kb
.txt 419kb
.pdf 898kb
.numbers 309kb
.jpg 888kb
.png 915kb
.exe 342kb
.mp4 691kb
.mkv 594kb
Still, I would like to know if there is any way within those constraints to get even smaller bookmarks.

Play downloaded Widevine Classic files from app document folder in iOS?

I am trying to play wvm files from the app documents folder since 3 days but without success...
I removed "file://" from my path but I still get 1013 error (as discussed here), does someone have some sample code or at least the procedure to follow to make it works properly?
WV_RegisterAsset(myFilePath) always return WViOsApiStatus(rawValue: 1013)
The file should exists because when I try this:
let fileManager = NSFileManager()
print(fileManager.fileExistsAtPath(myFilePath))
It returns true
Thanks in advance for your help!
Widevine Classic on iOS uses an "asset root" directory. When you initialize the library, you pass it in the settings dictionary using the key WVAssetRootKey.
After that, all local asset pathnames you pass to the library are relative to the AssetRoot.
One simple option is to use NSHomeDirectory() as the AssetRoot, and then trim it from the beginning of absolute pathnames.

How do you convert Wavefront OBJ file to an SCNNode with Model I/O

I've imported a Wavefront OBJ file from a URL and now I'd like to insert it into my scene (SceneKit) on my iOS 9 app (in Swift). What I've done so far is:
let asset = MDLAsset(URL: localFileUrl)
print("count = \(asset.count)") // 1
Any help converting this to a SCNNode would be appreciated. According to to Apple's docs:
Model I/O can share data buffers with the MetalKit, GLKit, and SceneKit frameworks to help you load, process, and render 3D assets efficiently.
But I'm not sure how to get buffer from an MDLAsset into a SCNNode.
Turns out this quite easy as many of the ModelIO classes already bridge. I was doing import ModelIO which gave me access to all the ModelIO classes and likewise import SceneKit which gave me the SceneKit classes, but, I was missing import SceneKit.ModelIO to bring in the SceneKit support for ModelIO.
let url = NSURL(string: "url-to-your-obj-here")
let asset = MDLAsset(URL: url!)
let object = asset.objectAtIndex(0)
let node = SCNNode(MDLObject: object)
Easy as that...

How can I use OBJ file or CTM file instead of DAE file in SceneKit?

I used to render 3d scene with openGL and metal on IOS, and the file format which I used was OBJ and CTM. These days I am trying Scene Kit. It seems that SceneKit only load DAE file. All the demos I can found on the Internet use DAE file , and I can't see the array of vertex and facet in their codes.
How can I load OBJ file or CTM file instead of DAE file?
Loading an OBJ file
It is as simple as passing MDLAsset a valid URL.
private func nodeForURL(url: NSURL) -> SCNNode
{
let asset = MDLAsset(URL: url)
let object = asset.objectAtIndex(0)
let node = SCNNode(MDLObject: object)
return node
}
This will not only correctly load the .obj file, but it will load referenced .mtl files.
you can do that by writing your own importer. Take a look at SCNGeometry, SCNGeometrySource and SCNGeometryElement.
edit: starting iOS 9.0 and OS X 10.11 SceneKit can open OBJ files or any other file format supported by Model I/O. You can use previously existing APIs to do that (such as +sceneNamed:) or the new +sceneWithMDLAsset: method.
As of iOS 9/OS X 10.11, you can use Model I/O's MDLAsset to import OBJ files (and a few other formats). How do you convert Wavefront OBJ file to an SCNNode with Model I/O has sample code.
EDIT: ModelIO can probably load OBJ files now. I haven’t tried this path myself. This answer was written before iOS 9 and OS X 10.11:
SceneKit can't load DAE files on iOS, actually, it actually precompiles the DAE files to an internal format for iOS devices.
If you want to transform your OBJs to DAEs you can write a simple importer/exporter on OS X to do so — on OS X SceneKit will actually read OBJ files (it's not documented but it works) and will write DAEs.
Or you could download the "Assimp" project on github if you'd like to try to read OBJs yourself, but it's going to be a bit of work getting it into SceneKit objects.
Further information regarding the supported file formats:
The following 3D file formats are supported by SceneKit and can be imported to an .scn file using the Scene Editor in Xcode:
DAE, OBJ, Alembic, STL and PLY files.
Source: WWDC 2015 Session "Enhancements to SceneKit" at 02:24

Resources