3D model not loading correctly in Scenekit - ios

So I purchased a 3D model of a car to display in my ARKIT app.The folder consisted of different model formats and a single image.
I dragged and dropped the .dae file to my project. This is the file structure.
However when adding to the scene the axis would be completely off and not load correctly. It did not load the complete model with textures, and would load above me.
See example:
Then I decided to load the .Blender file in Blender and export again as a colada .dae file.
This was the result when adding to my project.
When loading it in the real world a half car would appear where I stood at a ridiculously large scale.
I have tried the project with a separate model and it worked fine. Does anyone have any ideas how I can work with the 3D Model to load correctly in my app ?

I had some problems scaling models I have purchased. You aren't supposed to post links, but it's too big to paste in - I followed this guide to scale down the models and rotate them into the proper position in blender before exporting.
https://jibransyed.wordpress.com/2014/06/05/how-to-correct-scale-and-rotation-of-static-blender-models-for-unity/
On most models I use this to load:
func loadCollada(sceneName: String, objName: String) -> SCNNode
{
let vScene = SCNScene(named: sceneName)!
let gObject = vScene.rootNode.childNode(withName: objName,
recursively: true)!
return gObject
}
On some larger models, I had to do it this way:
func collada2SCNNode(filepath: String) -> SCNNode
{
let returnNode = SCNNode()
let scene = SCNScene(named: filepath)
for vNode in (scene?.rootNode.childNodes)!
{
returnNode.addChildNode(vNode)
}
return returnNode
}
Then set Y UP:
scntool --convert fighter0.dae --format c3d --output out.dae --force-y-up --force-interleaved --look-for-pvrtc-image

Related

Swift Scenekit show image on basic plane

My goal is to have an app where I can scan a certain image and display an AR-Generated Model next to it. I am following this project.
I already imported the image I want to scan and that is working as expected. The problem now is to import my own Model. And that is where I struggle.
What I want is to display a 2D Image on a simple PlaneScene on top or next to the detected image.
I managed to create a .dae file from Blender. I also imported it into Xcode and converted it inside XCode to a .scn file.
This is how it looks:
As you can see the image is not correctly displayed.. It is just white. Also when running the app, the Object is not being displayed. I can not see it anywhere, but it is also not throwing an error.
This is my .dae file: File
Maybe I dont even need Blender for that but I couldn't find a way to display an image onto a Plane in XCode...
What am I missing here? I feel like there is something wrong with my Model. Any help is appreciated!
As I can see, when I open your file in Blender and go to the Front view:
Your Plane is wrong oriented in the space. One looks at it from the side and it is not well centered. (but this is probably what you want).
But you don't need an imported geometry object. Apple has a solution to this.
I recommend you to use the built in plane (SCNPlane, what is a SCNGeometry object) for your project. It will have a front view oriantation by default and you can easely move the offset position.
Let me know if you need an example. But it should be easy to find out how to do this.
PS: If you want to import Models this here is a useful extension to do this:
extension SCNNode {
convenience init(named name: String) {
self.init()
guard let scene = SCNScene(named: name) else {return}
for childNode in scene.rootNode.childNodes {addChildNode(childNode)}
}
}

How can I access multiple animations in Swift?

Image of the file hierarchy in xcode of my animation file
Issue:
xcode is recognizing multiple animations for a single Collada (.dae) file. But I can't find any documentation on how to access these animations directly. I tried using the fox game example, but it only loads one of the animations.
Here's my code:
let modelNode = self.addModel_DAE_return(x: 0, y: 0, z: 0, scaleFactor: 0.0005, fileName: "models.scnassets/export_014/export_014_model.dae")
// add the animation to the model
let modelAnim = self.loadAnim_DAE(fileName: "models.scnassets/export_014/export_014_anim.dae")
modelNode.addAnimationPlayer(modelAnim, forKey: "headMove")
modelAnim.play()
// add the model to the scene
node.addChildNode(modelNode)
How can I access and load in the other animations?
Context:
I'm making an AR app. I'm using the Apple Image Recognition example as a base.
Here's a link to it:
https://developer.apple.com/documentation/arkit/recognizing_images_in_an_ar_experience
I animated a skeleton in Maya and exported the animation to a COLLADA (.DAE) file using the OpenCollada extension for Maya.
I exported separate files for the model and the animation, because if I export them as a single file, none of my animations export and xcode crashes every time I try to access the file to check if it registers any animations.
I want to access the "Entities" of my animation file so I can just loop over, load and attach the animations, but I can't
also I have looked into GameKit kind of but, is there not a way to do this with SceneKit?
Each joint in the rig has animation information
Originally I was only getting the information the first joint that had animations on it and not its children that also had animations attached
i.e. lets say your rig hierarchy is
hips > rightShoulder > arm > elbow > wrist
and your animations were on the shoulder, arm, elbow, and wrist joints
you do not have any animations on your hip joint
using enumerateChildNodes will only grab the information from the shoulder joint
using enumerateHierarchy will grab all the animation information from the shoulder, the elbow, AND the wrist joint
see below for my function that I used:
note that I had separately loaded and saved my 3D model onto an SCNNode and that was passed in so I could attach the animations to it
func loadAttachAnim_DAE(fileName: String, modelNode: SCNNode){
let scene = SCNScene(named: fileName)!
//find top level animation
var animationPlayer: SCNAnimationPlayer! = nil
scene.rootNode.enumerateHierarchy{ (child, stop) in
if !child.animationKeys.isEmpty {
print ("child = \(child) -----------------")
animationPlayer = child.animationPlayer(forKey: child.animationKeys[0])
modelNode.addAnimationPlayer(animationPlayer, forKey: "\(child)")
animationPlayer.play()
}
}
}

How can I load multiple nodes of the same 3d model all at once?

I'm working on an ARKit application where you would walk through a portal and you'd be somewhere else. I purchased a 3d model of an archway to serve as the portal. I took the model in to Blender to flatten it down to one piece, but the texture disappeared and whenever I apply a new texture it only shows up on one portion of the model.
Here is the original model, only modified by changing it to .dae format. however, I can't load arch1, arch2, arch3, etc. without writing the same line over and over
With this model I'd be writing the same code over and over
private func addPortalArch(hitResult: ARHitTestResult) {
let portalScene = SCNScene(named: "art.scnassets/Medieval_portal.dae")
let portalNode = portalScene?.rootNode.childNode(withName: "arch1", recursively: true)
// I'd be writing this portalNode = portalScene line over and over for each arch.
//I'd also have to get the position for each piece as far as I understand, which I do not know how I'd begin to do that based on where the user taps to place the portal.
portalNode?.position = SCNVector3(hitResult.worldTransform.columns.3.x, hitResult.worldTransform.columns.3.y, hitResult.worldTransform.columns.3.z)
self.sceneView.scene.rootNode.addChildNode(portalNode!)
}
I need the model to be all once piece but still have the same stonework material over the whole of it.
Looking at the file you sent, your best bet is to use the model which contains each aspect of the Arch (your 1st picture).
The 1st step (not always necessary but useful) is to convert the dae file to an .scn file:
Having done this you then want to create an Empty Node to be the Portal Door RootNode and make each element of the Portal a child of this e.g:
You will also need to rotate each ChildNode's (not the PortalRoot) Euler Angle X by -90 (as when you load the model the Portal Door is on it's side):
Now since you have a single RootNode, there is no need to loop through all the nodes so that is displayed on the screen. You can simple use a function like this:
/// Places The Portal Door 5m Aeay From The Camera
func setupPortalDoor(){
//1. Get The Portal Scene
guard let portalScene = SCNScene(named: "portalDoor.scn"),
//2. Get The Portal Node
let portalModel = portalScene.rootNode.childNode(withName: "PortalRoot", recursively: false) else { return }
//3. Add To The ARSCNView Root
augmentedRealityView?.scene.rootNode.addChildNode(portalModel)
//4. Position It 5m Away From The Camera
portalModel.position = SCNVector3(0, 0, -5)
/*
The Portal Is Large So I Suggest Scaling It ^__________*
*/
}
If you later wanted to change the portal arch to say marble you can easily do it like so:
for node in portalModel.childNodes{
node.geometry?.firstMaterial?.diffuse.contents = UIColor.cyan
}
Hope this helps...

How to scale DAE models correctly in ARKit and SceneKit?

I'm currently trying to combine the following sources:
Apples SceneKit Vehicle Demo, Resp. its Swift version,
ARKit by example, and resp. its Swift version.
Each project on its own works like a charm (although I changed the vehicle demo so that the car can be controlled by on-screen buttons).
Now, when I try to combine both projects to create an augmented reality racing game, I run into problems regarding the size of the .dae model of the car: it's too big.
I can scale the model using the (chassis) nodes .scale property, but as soon as I add the SCNPhysicsVehicle properties and behaviour, the car gets reset(?) to its original size. I tried to scale the model in Xcode (open dae file, change scale), but its bounding box remains the same - that tells me that the rescaling didn't work properly.
Any hints?
1)you can scale the dae models by art.scnassets directly.
art.scnassets -> car.dae -> node inspector -> transforms -> scale the object
2) can scale 3dmodel by SCNAction
let scene = SCNScene(named: "art.scnassets/cup.dae")!
let node = scene.rootNode.childNode(withName: "cup", recursively: true)!
let action = SCNAction.scale(by: sender.scale, duration: 1.0)
node.runAction(action)
What I like to do is use Blender or some other 3d modeling program to resize your dae model to work in meters. Everything in ARKit is based on meters, so by sticking to the same metric you can get all your models to play well together without having to guess what the scale factor needs to be.
I'm not sure how to fix the model directly in Xcode. However, you can fix it in blender. Start by importing the object into blender. Select the object and observe it's dimensions. Scale the object to the desired dimensions and apply them by hittin Ctrl + A, and selecting scale. Alternatively, from the object menu, you can select Apply -> Scale. Now you can export your model with the corrected size.

Particle system is seen as black from certain angles

I created a particle system that should act as a spaceship's vehicle fire.
I've added it in a node loaded from a COLLADA file (made with Blender):
let engine = _spaceship.childNode(withName: "Engine", recursively: false)!
let engine_pSystem = SCNParticleSystem(named: "Engine", inDirectory: "art.scnassets")!
engine.addParticleSystem(engine_pSystem)
But the particle system looks black (literally like smoke) from certain angles, while from certain angles it looks normal (like in the scnp file of the image above). This video shows the problem: https://youtu.be/JvNe140C068
Try these settings, or similar to them...

Resources