Stop sharing node's geometry with its clone programmatically
According to the clone()
API reference, you can copy the geometry after cloning, this will create a new unshared geometry for your node.
let newNode = node.clone()
newNode.geometry = node.geometry?.copy() as? SCNGeometry
The material attached to the copied geometry is still the same one being used on the original, so any changes will still affect both.
Either create a new material, or make a copy.
if let newMaterial = newNode.geometry?.materials.first.copy() as? SCNMaterial {
//make changes to material
newNode.geometry?.materials = [newMaterial]
}
Workflow between blender and xcode (scenekit)
SceneKit supports materials exported in DAE from Blender. It doesn't support every possible shading option that Blender has, but unless you're doing exotic stuff it should cover most of what you're looking for.
At run time there's no difference between materials loaded from DAE and those created programmatically.
What you do want to think about at authoring/export time is stuff like real-time versus static lighting/shadows and high-poly geometry versus baked normal maps. In other words, material performance is more about how the materials are set up (complexity) than where they're set up (imported or at run time). See WWDC 2014 session 610: Building a Game with SceneKit for some tips.
How to add a 3D object as SCNNode in ARKit2?
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
...
}
How can I apply coordinates to a 3D earth model in xcode's scenekit?
You don't need to go into complex math to do this. All you need to do is add two extra helper nodes.
Lets assume the Earth is represented by earthNode
with its geometry (a sphere) at the centre of the node and with a radius of 100 points.
Add a child node to it with the same centre called longtudeHandle
, without any geometry.
Now add another child node to the first one latitudeHandle
, without any geometry.
Then you add the space station node stationNode
as a child to latitudeHandleNode
, but not in the centre. Offset it along the X axis by, say, 105 points to place it 5 points above "the Equator".
SCNNode * longtudeHandle = [SCNNode node];
[earthNode addChildNode:longtudeHandle];
SCNNode * latitudeHandle = [SCNNode node];
[longtudeHandle addChildNode:latitudeHandle];
stationNode.position = SCNVector3Make(105, 0, 0);
[latitudeHandle addChildNode:stationNode];
You should end up with the following node graph in your scene
earthNode
|
|--------longitudeHandle
|
|----------latitudeHandle
|
|-----------stationNode
As a result you have 4 nested coordinate systems and every node 3D rotation is set according to its parent node coordinate system.
You can then manipulate the long/lat position of your Station using
longitudeHanlde.eulerAngles
Y component for longitude angle in radianslatitudeHanlde.eulerAngles
Z component for latitude angle in radians
which should look like
longitudeHandle.eulerAngles = SCNVector3Make(0, LONGITUDE, 0);
latitudeHanlde.eulerAngles = SCNVector3Make(0, 0, LATITUDE);
An additional benefit of using these nested helper nodes is that the Station will always be perpendicular to it's parent's X axis and respectively the planet surface, while if you use complex math to position it in orbit and want to achieve the same effect it becomes even more complex.
Alternatively, you should be able to do the same with only one helper (positioning) node and whichever "rotational" property you are familiar with to orient it in 3D space
.eulerAngles // SCNVector3
.rotation // SCNVector4
.orientation // SCNQuaternion
.transform // SCNMatrix4, includes position and scale
but this will require some math and/or use of matrices or quaternions (which I've not spent time to learn yet).
Related Topics
iOS Coredata Compatible with Both iOS 9 and iOS 10
Allow Line Editing When Reading Input from The Command Line
Open Attachment from Mail Using iOS 8 App [Swift]
Decrypting Des with Commoncrypto in Swift 3
Swift - Rotate Gesture and Rotation Increments of 90 Degrees
Trouble Passing Array Through Prepareforsegue
Swift & Nstextfield: How to Work with Text Completion
Gmsmarker Not Appearing on Map
How to Convert a Pair of Bytes into a Float Using Swift
Animation Triggered Using a Button Stops a Repeatforever Animation Added Onappear
How to Assign Elements of a Dictionary to JSON Object in Vapor 3
Wkwebview Problems in Macos Mojave
Swift 4 Base64 String to Data Not Working Due to String Containing "Incomplete" Emoji
Spritekit Skscene Not Resizing Correctly to Fit iPhone 12