I need to associate SceneKit Node objects with arbitrary objects in my program and am looking for an optimal solution.
Here is an example of what I mean:
Say I have a program that renders atoms in a molecule using SceneKit. I have classes Molecule and Atom that model my data. I then render the molecule using SceneKit.
When I click on a sphere node in the Scene View, I need to know which Atom object that sphere represents (the Molecule contains an array of Atoms)
I could create a Dictionary that maps Node to Atom object, but wonder if there is a way to add an Atom object reference to the sphere node. Should one use Key-Value bindings?
I am very new to Cocoa programming and am looking for a nudge in the right direction for an approach. I can then research the implementation specifics.
How about starting with a couple of different SCNNode subclasses? The first is for your Atom, the second for your Molecule. Each MoleculeNode has one or more AtomNodes as children. AtomNode and MoleculeNode have weak references back to the Atom or Molecule they represent.
Now you can move or rotate a MoleculeNode easily, and all of the AtomNodes will move with it. Each AtomNode's geometry will stay fixed, relative to the parent MoleculeNode.
Hit testing will return both AtomNodes and MoleculeNodes. You can filter that result if you want, by either the node's class, or by setting the node's name to "Atom" or "Molecule". The SCNHitTestBoundingBoxOnlyKey might be useful if you want to be lenient about the precision of clicks required.
Just as a small alternative you can you a Map from SCNNode to ModelObject.
Related
I am working on a basic racing game using Apple's SceneKit and am running into issues simulating a car. Using the SCNPhysicsVehicle behavior, I am able to properly set up the car and drive it using the documented methods.
However, I am unable to get the car's position. It seems logical that the SCNPhysicsVehicle would move the SCNNodes that contain the chassis and the wheels as the car moves but the SCNNodes remain at their original position and orientation. Strangely enough, the chassis' SCNPhysicsBody's velocity remains accurate throughout the simulation so I can assume that the car's position is based off of the SCNPhysicsBody and not the SCNNode. Unfortunately, there is no documented method that I have found to get an SCNPhysicsBody's position.
Getting a car's position should be trivial and is essential to create a racing game but I can't seem to find any way of getting it. Any thoughts or suggestions would be appreciated.
Scene Kit automatically updates the position of the node that owns an SCNPhysicsBody based on the physics simulation, so SCNNode.position is the right property to look for.
The catch is that there are actually two versions of that node in play. The one you typically access is called the "model" node. It reflects the target values for properties you set, even if you set those properties through an animation. The presentationNode reflects the state of the node currently being rendered — if an animation is in progress, the node's properties have intermediate values, not the target values of the animation.
Actions, physics, constraints, and any scene graph changes you make inside update/render loop methods directly target the "presentation" version of your scene graph. So, to read node properties that have been set by the physics simulation, get the presentationNode for the node you're interested in (the node that owns the vehicle's chassisBody physics body), then read the presentation node's position (or other properties).
I have the same problem with my player node.
I move it with applyForce (to manage collision detection).
But when i check node position after some movement, the node position has not move (presentation node is the actual position as rickster write in his answer)
I manage to update the scnNode.position with renderer loop
You have to set position of your node with the presentationNode position.
node.position = node.presentationNode.position
Set this into renderer(_: updateAtTime) and your node position will sync with any animation you made to the physicsBody
In SceneKit, you can add a lookAtConstraint constraint to your SceneView's Point Of View, to make Camera look at a certain node.
Is there a standard way of doing the same but for a specific face of a geometry?
So that, if I touch a specific face of a cube, camera would move so that the Z axis of the camera node gets in line with the normal of the touched face? So that the cube would look like a plane form the new perspective.
No.
That would require movement of the camera, in addition to re-aiming it.
Imagine I'm in front of my house. I have a great view of the front and can just barely see the side to my left. In my Scene I tap the side of the house. A LookAt constraint would merely change the angle of the camera. It would not be aligned with the normal of that barely visible side.
To align with the normal, I'd have to walk around the house until I can stare at the house and be perpendicular to the side I tapped. At what radius? What path? You have to figure that out yourself.
Depending on what effect you're trying for, you might want to rotate the model instead of moving the camera. Rotate the tapped node locally (or as a child of an invisible parent) so that its minus-Z axis points out the tapped face, and keep a lookAtConstraint on the node, not the camera. This approach will change the look of the object, though: you will see it rotating, and the shading changing appropriately.
So that, if I touch a specific face of a cube, camera would move so that the Z axis of the camera node gets in line with the normal of the touched face?
Supposing you are using hit-testing to determine what object got touched, a SCNHitTestResult will give you both localCoordinates and localNormal from which it should be fairly easy to derive a camera transform.
One easy way would be to have the camera as a child node of the box, compute a position that would look like localCoordinates + distance * localNormal and finally a transform using GLKMatrix4MakeLookAt and SCNMatrix4FromGLKMatrix4.
Note that you can also use worldCoordinates, worldNormal, as well as conversion utilities such as SCNNode.convertTransform(_:from:).
mutating on mnuages answer, use a hit test or ray trace to find where the user tapped on the mesh, then add a node at that location, and constrain the camera to lookAt that node.
I am working on a basic racing game using Apple's SceneKit and am running into issues simulating a car. Using the SCNPhysicsVehicle behavior, I am able to properly set up the car and drive it using the documented methods.
However, I am unable to get the car's position. It seems logical that the SCNPhysicsVehicle would move the SCNNodes that contain the chassis and the wheels as the car moves but the SCNNodes remain at their original position and orientation. Strangely enough, the chassis' SCNPhysicsBody's velocity remains accurate throughout the simulation so I can assume that the car's position is based off of the SCNPhysicsBody and not the SCNNode. Unfortunately, there is no documented method that I have found to get an SCNPhysicsBody's position.
Getting a car's position should be trivial and is essential to create a racing game but I can't seem to find any way of getting it. Any thoughts or suggestions would be appreciated.
Scene Kit automatically updates the position of the node that owns an SCNPhysicsBody based on the physics simulation, so SCNNode.position is the right property to look for.
The catch is that there are actually two versions of that node in play. The one you typically access is called the "model" node. It reflects the target values for properties you set, even if you set those properties through an animation. The presentationNode reflects the state of the node currently being rendered — if an animation is in progress, the node's properties have intermediate values, not the target values of the animation.
Actions, physics, constraints, and any scene graph changes you make inside update/render loop methods directly target the "presentation" version of your scene graph. So, to read node properties that have been set by the physics simulation, get the presentationNode for the node you're interested in (the node that owns the vehicle's chassisBody physics body), then read the presentation node's position (or other properties).
I have the same problem with my player node.
I move it with applyForce (to manage collision detection).
But when i check node position after some movement, the node position has not move (presentation node is the actual position as rickster write in his answer)
I manage to update the scnNode.position with renderer loop
You have to set position of your node with the presentationNode position.
node.position = node.presentationNode.position
Set this into renderer(_: updateAtTime) and your node position will sync with any animation you made to the physicsBody
I'm trying to make a project "Determine velocity 2D of an object using Camera". That's just 2D velocity. I want to use Lucas Kanade algorithm in OpenCV. But I can't distinguish what coner belong to my object, and i can't find the centroid of my object to track ( This is white object place in Black background, this object have any shape, example: square, elip,.. ). How do I track the centroid of the object to determine the distance of the motion? Do I need use Lucas Kanade algorithm to make this project? Please help me.
To obtain the velocity of an object you need to do two things, firstly you need to detect the object in each image (and condense it to the centroid as you have suggested), secondly you need to associate detected objects across different images. Once you've done that the velocity can be easily calculated by the simple equation of motion velocity = distance/time.
Association is easy if you only detect one object in each image (just assume the detection is the object), although this approach is liable to break in the real world.
Detecting your object is where I believe you are having difficulty. If it really is as simple as a single white object against a solid black background then finding the centroid should be simple, simply average the coordinates of all white pixels. If you have a noisy image, then you will need to do some cleaning up first, for example morphological closing and opening operations to remove small specks of noise.
I have a 3D scene where my 3D models are being loaded in the code behind from XAML files.
Each model is comprised of a tree of nested Model3DGroups each of which has various transformations applied to it to position and orient the next subcomponent of the model in the tree. This model is then used as the content of a ModelVisual3D so that it can be displayed to the screen.
I want to attach a child ModelVisual3D to a 'parent' ModelVisual3D. This child ModelVisual3D needs to use all of the nested transformations of the parent ModelVisual3D.Content to correctly position and orient itself in the virtual space. For example, the first ModelVisual3D is a robot arm which has various moveable joints and I want to attach a tool on the end of this arm--another ModelVisual3D. How can I access this composite transform from the parent ModelVisual3Ds content property to allow me to position the next ModelVisual3D correctly relative to its parent?
As you have no doubt observed, when you group Model3Ds in a Model3DGroup the Transform properties of the children combine with those of the parent.
It sounds like you are asking how to compute the net transform down to a particular Model3D within a tree of Model3Ds that make up what you are calling your "model". To do this you need to know (or be able to scan and discover) the path from your root Model3DGroup down to the Model3D you want to find the transform for.
Once you have this path, all that is required is to combine the Transform properties at each level. To do this, simply construct a Transform3DGroup and add the individual transforms to it.
For example, if your robot arm has Model3D components named "UpperArm", "LowerArm", and "Hand", and you wanted to find out the position and angle of the hand you might do:
var combined = new Transform3DGroup();
combined.Children.Add(UpperArm.Transform);
combined.Children.Add(LowerArm.Transform);
combined.Children.Add(Hand.Transform);
Now you can find the (0,0,0) location on the hand as follows:
combined.Transform(new Point3D(0,0,0));
Similarly you can find other points and use them to position your other ModelVisual3D.