I'm using Apples SceneKit and have a custom .dae asset. I've converted the asset to a .scn file. I am grabbing the SCNNode by name from the .scn file. After placing the SCNNode in my SCNView scene as a child node and setting it's position to be SCNVector3(0,0,-1), it ignores this position and instead follows my phone location. The asset renders right on top of me and when I walk away, it follows me. It's getting to be very annoying and I can't find a solution.
However, if I replace the SCNNode taken from the .scn file, and use a SCNBox, instead, everything works just fine. The cube stays in it's set position.
Here is the relevant code:
func addCoins(at position: SCNVector3) {
let donorScene = SCNScene(named: "art.scnassets/nodes.scn")
if let coin = donorScene?.rootNode.childNode(withName: "coin", recursively: true) {
coin.position = position // 0, 0, -1 (right in front of me)
scene.scene.rootNode.addChildNode(coin)
}
}
Attached is a screenshot showing what I see whenever I move.
So the problem was that my 3d asset was too large. The asset was created at 200cm^2 which is 2meter^2 in the 3d modeling program. After the asset was imported into Xcode, it's interpreted by SceneKit as 200meters, which is way too large for SceneKit, apparently.
Related
I made an animation in Blender and moved it to Xcode and it is converted from .dae file
to .scn by Xcode.
I can play the animation in scene graph of Xcode as it is designed in the Blender.
I am loading geometry and animation and create node for animated object.
I use SCNAnimationPlayer() to load animation. The code is below.
let scene = SCNScene(named: "scene.scn")!
let geometry = scene.rootNode.childNode(withName: "animatedGeo",
recursively:true).geometry!
let animationNode = SCNNode(geometry: geometry)
let armature = scene.rootNode.childNode(withName: "Armature", recursively: true)!
let animationPlayer = armature.animationPlayer(forKey: "action_container-Armature")!
animationNode.addAnimationPlayer(animationPlayer, forKey: "action_container-Armature")
rootNode.addChildNode(animationNode)
I did not set anything for animationPlayer programmatically because all the settings looks
Ok in scene graph window of Xcode.
However when scene loaded I see a small movement on animated object on iPhone screen.
Looks like only first (parent) bone animation is partly playing.
I could not find the why all of animation was not playing as it is played in scene graph.
Yes, I found how to do it when I was trying to manipulate my object designed and animated in Blender programmatically instead of animation I made in Blender.
What you have to do is to add "Armature" node to your scene node.
This is all. You don't have to use SCNAnimationPlayer().
let scene = SCNScene(named: "scene.scn")!
let myObjectArmaturNode = scene.rootNode.childNode(withName: "Armature", recursively: true)!
rootNode.addChildNode(myObjectArmaturNode)
This is it.
The animation runs like it is designed in Blender.
The animation consists of 4 bones by the way.
I am trying to fix the camera to a sprite node “players.first!” and I managed to do so using SKConstraints as follows
func setupWorld(){
let playerCamera = SKCameraNode()
let background = SKSpriteNode(imageNamed: platformType + "BG")
var cameraFollow = [SKConstraint]()
cameraFollow.append(SKConstraint.distance(SKRange(constantValue: 0), to: players.first!))
playerCamera.constraints = cameraFollow
background.zPosition = layers().backgroundLayer
background.constraints = cameraFollow
background.size = self.size
self.addChild(playerCamera)
self.camera = playerCamera
self.addChild(background)
physicsWorld.contactDelegate = self
addEmitter()
}
But this keeps the camera fixed to the exact location of the node, I want the camera to be shifted to the right of the node “players.first!” (only in X dimension) and I couldn’t manage to do so with SKConstraints, note that the node is moving fast so updating the position of the camera in the update function makes the camera jitter.
This image is explaining my issue
Constrain the camera to an empty SKNode and make it a child node of the first player which is offset to the right in the frame of the player. This can be accomplished in the scene editor or programmatically by setting this dummy node's position to something like CGPoint(x: 100, y: 0). When the player moves, this node will also move, dragging the camera along with it; and since the camera is focused on this node, the nodes in the same 'world' of the player will appropriately appear to move in the opposite direction while maintaining the look you want for the player.
EDIT: If the player rotates
If the player needs to rotate, the above configuration will result in the entire node world revolving around the fixed empty node. To prevent this, instead place an empty SKNode that acts as the fixed camera point which will be called "cameraLocation" and the player node into another empty SKNode which will be called "pseudoPlayer". Constrain the camera to "cameraLocation". Moving the "pseudoPlayer" node will then move both the camera's fixed point (so that the camera moves) and the player node while only resulting in the rotation of the player and not the entire world.
NOTE: The only potential drawback is that in order to move the player correctly through the world, you must move the "pseudoPlayer" instead.
I am new in ARKit2 and followed a couple of tutorials and official documentation.
problem
How to add 3d object as SCNNode()?
Code
let artFrame = SCNBox(width: CGFloat(w), height: CGFloat(h), length: 0.002, chamferRadius: 0.02)
artFrame.firstMaterial?.diffuse.contents = imageToDisplay
let artFrameNode = SCNNode(geometry: artFrame)
artFrameNode.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry: artFrame, options: nil))
artFrameNode.position = SCNVector3Make(Float(x), Float(y), Float(z*3))
sceneView.scene.rootNode.addChildNode(artFrameNode)
As per the above code, I am using predefined SCNBox in SCNNode. Is there any way that I can use 3d object such as .dae, .obj instead of SCNBox and wrap with Image?
I check out the documentation and it says that you can add Mesh objects to SCNNode :
https://developer.apple.com/documentation/scenekit/scnnode/1419841-init
Edit
Whenever I am adding a new .dae and converting to .scn. Xcode is throwing follwing error:
/Users/paly/Library/Developer/Xcode/DerivedData/sample-bohiilnhthuwfkechtmhscucgccc/Build/Products/Debug-iphoneos/sample.app: resource fork, Finder information, or similar detritus not allowed
Command CodeSign failed with a nonzero exit code
To add .dae or .obj object to the scene, you need to get childNode of the .dae object and simply add it to your scene. I recommend to convert your .dae file to .scn simply using Xcode's Editor menu.
You also need the node's name, which can be accessed in Scene Graph View. Just click on your .obj file and click the Scene Graph View button on bottom left corner of the Xcode scene editor. Here, my node's name is "objectNode":
Now you can add the 3D object as a SCNNode to your scene:
override func viewDidLoad() {
super.viewDidLoad()
...
let objectScene = SCNScene(named: "object.scn") // Here, add your .obj or .scn file
let objectNode: SCNNode = objectScene.rootNode.childNode(withName: "YourObjectName", recursively: true) // Get the object name from Scene Graph View, which is "objectNode" for me.
objectNode.position = SCNVector3(0,0,-4)
let scene = SCNScene() // Main scene of the app
scene.rootNode.addChildNode(objectNode)
sceneView.scene = scene
...
}
I am trying to move implement bouncing balls using ARKit. I want the balls coming from one end of screen bouncing and moving out of screen.
Can anyone please recommend best approach or point to sample code to implement this?
Can I use UIBezierPath to create a path and move SCNNode along the path. If yes, how can I move the node along path.
Create a scene and a ball Node. Use force direction for ball Node and animate the ball Node with Physics. This is just an example.
// Create a new scene
guard let scene = SCNScene(named: "BouncingBalls.scn", inDirectory: "art.scnassets") else { return }
sceneView.scene = scene
// Add physics bodies
guard let ballsNode = scene.rootNode.childNode(withName: "balls", recursively: true) else { return }
let forceDirection = SCNVector3Make(0, 3, 0)
for ballNode in ballsNode.childNodes {
let physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil)
physicsBody.applyForce(forceDirection, asImpulse: true)
ballNode.physicsBody = physicsBody
}
Try this in View didLoad. Hope this works.
The best way to get what you want is to use a predefined animation or dynamics that was made in such 3D apps as Autodesk Maya, Autodesk 3dsMax, or Maxon Cinema4D.
After producing a ball animation (or dynamics, it's up to you) you need to bake this animation (baking is a process of keyframe generation for every frame instead of using interpolated curve) and export this scene as a .dae file format. ARKit/SceneKit supports not only .dae animations but also brand-new format .usdz.
SceneKit API (as well as other Apple frameworks' APIs) is not designed for 3D animation.
I’m trying to animate specific parts of a SCNScene object in SceneKit (in my case I want to animate fingers of a hand). I import the .dae (COLLADA) file easily from Blender with the respective bones to generate articulation on the model.
override func viewDidLoad() {
super.viewDidLoad()
var scene = SCNScene(named: "hand.dae")!
sceneView.scene = scene
sceneView.allowsCameraControl = true
sceneView.autoenablesDefaultLighting = true
sceneView.backgroundColor = UIColor.lightGrayColor()
}
My goal is to animate those bones on iOS with user generated values between 0 and 1. Imagine a UISlider where you scroll back and forth and see the specific finger move depending on the value of the slider.
This is needed animation screenshot
Image with the animation pretended
I’ve tried animate the model by calling an animation file like the Apple’s Fox example:
private var indexFingerAnimation: CAAnimation!
indexFingerAnimation = CAAnimation.animationWithSceneNamed(“move_index_finger.dae”)
indexFingerAnimation = false
indexFingerAnimation = 0.3
indexFingerAnimation = 0.3
indexFingerAnimation = Float.infinity
The problem is that’s a Global animation instead of just the index finger. Besides it’s always a ‘pre-defined’ animation instead of an animation controlled by user input. Ultimately I want to mix animations (e.g. move index finger and thumb at the same time revealing gestures)
Is this possible? I’m struggling because I can’t figure out how to manipulate specific parts of the mesh. I’m starting to study MetalKit but it’s not clear to me that’s the solution.
Any help would be really appreciated.
I have never tried two animations at the same time
but I can rotate SCNNode in dae file with two or more animate
You must set pivot point and group them together