Load .scn file as SCNNode LOSS animations - ios

When I load Horse.scn to a SCNNode, the animations are lost.
func addHorse(for parentNode:SCNNode, postion:SCNVector3){
guard let virtualObjectScene = SCNScene(named: "Horse.scn") else {
return
}
let wrapperNode = SCNNode()
for child in virtualObjectScene.rootNode.childNodes {
child.geometry?.firstMaterial?.lightingModel = .physicallyBased
child.movabilityHint = .movable
wrapperNode.addChildNode(child)
}
wrapperNode.scale = SCNVector3(0.001,0.001,0.001)
wrapperNode.position = postion;
parentNode.addChildNode(wrapperNode)
}
If I load scene from Horse.dae file, everything is fine. Setting rootNode 's playing property to YES doesn't work.

Related

Inverse Kinematics in Arkit

I have Scenekit model with 4 joints.
When I use it in SCNView with the code below and change the position of the parent node (Joint) I can see it animated according to the joints.
private lazy var scene: SCNScene = {
let scene = SCNScene(named: "art.scnassets/ears")!
return scene
}()
in viewDidLoad
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 5)
rootNode.addChildNode(cameraNode)
scnView.scene = scene
scnView.allowsCameraControl = true
scnView.backgroundColor = .white
let joint = contentNode!.childNode(withName: "Joint", recursively: true)!
var ik:SCNIKConstraint = .inverseKinematicsConstraint(chainRootNode: joint)
joint.childNode(withName: "head", recursively: true)!.constraints = [ik]
The problem occurs when I use the same model in Arkit. In this case, I use a separate View Controller than above. I place it on the head. The model collapse when I show it in Arkit with the code below. I expect it to track head movement and bend according to it.
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
guard let sceneView = renderer as? ARSCNView,
anchor is ARFaceAnchor else { return nil }
faceGeometry = ARSCNFaceGeometry(device: sceneView.device!)!
contentNode = SCNReferenceNode(named: "art/ears")
//contentNode!.physicsBody = .kinematic()
let joint = contentNode!.childNode(withName: "Joint", recursively: true)!
var ik:SCNIKConstraint = .inverseKinematicsConstraint(chainRootNode: joint)
joint.childNode(withName: "head", recursively: true)!.constraints = [ik]
return contentNode
}
I have this extension
extension SCNReferenceNode {
convenience init(named resourceName: String, loadImmediately: Bool = true) {
let url = Bundle.main.url(forResource: resourceName, withExtension: "scn", subdirectory: "Models.scnassets")!
self.init(url: url)!
if loadImmediately {
self.load()
}
}
Normal look of model is like this
Correctly applied inverse kinematics snapshot
I tried setting setMaxAllowedRotationAngle(between 20-45 degrees) to the joints, this prevents collapse behavior but it also prevents bending.
y property of model gravity is -9.8, x and z are 0.
What might be the problem that I can't create the same effect in Arkit?

Unable to view geometry in ARKit Scene after loading in from .scn file

I have a swatch.scn file and I'm trying to add its geometry to my scene. I have to grab swatch.childNodes.first to get the proper geometry and then I add it but nothing shows up in my scene. Would love any thoughts on how to solve this. Thanks!
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)
}
}
}
// in viewDidLoad
// Create a new scene
let scene = SCNScene(named: "art.scnassets/ship.scn")!
let swatch = SCNNode(named: "art.scnassets/swatch.scn")
let n = swatch.childNodes.first!
let geo = n.geometry!
print(n.geometry!) // <SCNGeometry: 0x281cb3b60 'bigger_swatch'>
n.position = SCNVector3(0, 0, -1)
n.scale = SCNVector3(3, 3, 3)
scene.rootNode.addChildNode(n)
try this
let swatch = SCNNode(named: "art.scnassets/swatch.scn")
swatch.position = SCNVector3(0, 0, -1)
swatch.scale = SCNVector3(3, 3, 3)
scene.rootNode.addChildNode(swatch)
// Note: your swatch-node holds the entire geometries from your file.
// You can do something like this:
print(swatch.childnodes.count)

How to download ARImage (.SCN) file to display image in ARSCNView?

I am trying to download the ARImage(.scn file) In my application. And display in the ARSCNView
Below my code is working fine it's able to display the image. An image is also below
func addARObject(x: Float = 0, y: Float = 0, z: Float = -0.5) {
let aRUrl : URL = URL(string :arImageUrl2)!
do {
let arScene = try SCNScene(url: aRUrl , options: nil)
let arNode = arScene.rootNode.childNode(withName: "chair", recursively: false)
print("x,y,z",x,y,z)
arNode?.position = SCNVector3(x,y,z)
zAxis = z
if isNodeAvailable {
currentNode.position = SCNVector3(x,y,z)
}else{
isNodeAvailable = true
currentNode = arNode
sceneView.scene.rootNode.addChildNode(arNode!)
}
}
catch {
print("errrrrororororor")
}
}
And Output of this is 👇🏻
But chair color is Red and its showing surface white color. but actually, there is no surface.
If the same image I am using In My project folder Without download then chair color is Red.
So Can Anyone Explain to me what's wrong with my code or image issue?
Below Image is when I am using the local File in my Project.
You create a parent node and then you can add all your nodes as children.
var nodes: [SCNNode] = getMyNodes()
var parentNode = SCNNode()
parentNode.name = "chair"
for node in nodes {
parentNode.addChildNodes(node)
}
You can access a specific child using:
parentNode.childNode(withName: nameOfChildNode, recursively: true)
If you are importing from a scene file:
let scene = SCNScene(named: "myScene.scn")
func getMyNodes() -> [SCNNode] {
var nodes: [SCNNode] = [SCNNode]()
for node in scene.rootNode.childNodes {
nodes.append(node)
}
return nodes
}
After getting child node from parent node, you can add texture to the child node.
let childOne = parentNode.childNode(withName: nameOfChildNode, recursively: true)
childOne.?.firstMaterial?.diffuse.contents = UIColor.red

SceneKit: Create SCNNodes from models at runtime

I am making a SceneKit game, and I have a folder with my models (file.obj, file.mtl, file.png). I can drag the models to the game.scn file.
let node = rootNode.childNode(withName: "boxTarget", recursively: true)!.flattenedClone()
node.isHidden = false
Then I look for the name of the node and I create a flattenedClone.
But I think that there will be a better way to create multiple SCNNodes with models, dynamically, at runtime, without adding them to the game.scn file.
If I understand the question correctly, I did mine something like this:
func initGameNodes() {
scene = SCNScene()
gameNodes = SCNNode()
gameNodes.name = "gameNodes"
scene.rootNode.addChildNode(gameNodes)
initLights()
scene.rootNode.addChildNode(camera.cameraEye)
scene.rootNode.addChildNode(camera.cameraFocus)
camera.reset()
}
func loadCollada(sceneName: String, objName: String) -> SCNNode {
let vScene = SCNScene(named: sceneName)!
let gObject = vScene.rootNode.childNode(withName: objName, recursively: true)!
return gObject
}
func createProjectileNodes(vMissile: weaponTypes) -> SCNNode {
switch vMissile
{
case .defenseMissile:
let vNode = loadCollada(sceneName: "art.scnassets/Models/missile.dae", objName: "Default")
vNode.scale = SCNVector3Make(0.05, 0.05, 0.05)
vNode.name = "Missile01"
return vNode
case . etc.
}
}

How to detect the current scene in SpriteKit project

In my SpriteKit app I've 3 different scenes and I want to set a specific settings for each scene.
I mean I want set visible an AdBanner in MainPage and SomeInfoScene but not in GameScene. How can I do this?
This is my code:
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
let mainPage = SKScene(fileNamed: "MainPage")!
mainPage.name = "MainPage"
let someInfoPage = SKScene(fileNamed: "SomeInfoScene")!
someInfoPage.name = "SomeInfoScene"
let gameScene = SKScene(fileNamed: "GameScene")!
gameScene.name = "GameScene"
view.presentScene(mainPage)
if let currentScene = view.scene {
if currentScene.name == mainPage.name {
print("MainPage")
adBannerView.isHidden = false
}
if currentScene.name == someInfoPage.name {
print("SomeInfoScene")
adBannerView.isHidden = false
}
if currentScene.name == gameScene.name {
print("GameScene")
adBannerView.isHidden = true
}
}
}
}
This is tracked by scene property of the SKView class. For instance:
if let view = self.view as? SKView {
if let currentScene = view.scene {
print("Current scene is: \(currentScene)")
else {
print("Current scene is nil")
}
}
By the way, your first line really should read:
if let view = self.view as? SKView { ...
That's the standard/idiomatic way to try a downcast in an if statement.
Update. You also need to set the name property if you are planning to use that in your game code (in the *.sks file or directly inside your code). For instance:
let scene = SKScene(fileNamed: "MainPage")!
scene.name = "MainPage"
view.presentScene(scene)

Resources