Water forms a simple molecular structure which we will build in AR with Apple’s ARKit. We’ll learn basics of ARKit like working with nodes and manipulating them.
// Create a new scenelet scene = SCNScene(named: "art.scnassets/ship.scn")!// Set the scene to the viewsceneView.scene = scene
For reference, the x, y and z axes are as below. The camera is at the origin.
Oxygen is bigger than Hydrogen. So, we’ll first place an Oxygen atom. We’ll work with the ViewController.swift
from now on.
func getMainAnchor() -> ARAnchor {
// Creates an anchor at a distance 0.1m in front of you .
var anchorPosition = matrix\_identity\_float4x4
anchorPosition.columns.3.z = -0.1
let mainAnchor = ARAnchor(transform: anchorPosition)
return mainAnchor
}
viewDidLoad
function.let sphere = SCNSphere(radius: 0.01)
let oxygenNode = SCNNode(geometry: sphere)
oxygenNode.geometry?.firstMaterial?.diffuse.contents = UIColor.red
sceneView.session.add(anchor: self.getMainAnchor())
sceneView.scene.rootNode.addChildNode(oxygenNode)
oxygenNode.position = SCNVector3(0.0, 0.0, Float(-0.1))
The above code creates a sphere geometry and an SCNNode for the Oxygen atom. Then, add the AR Anchor to the sceneView’s session and then add the Oxygen atom node as a child to the sceneview’s root node. This puts a red sphere at 0.1m in front of you.
Fig 1. Oxygen Atom
Now we should think about how we are going to construct the molecule by analyzing the structure.
Fig 2. Top view of the molecule
From the structure we have here, we need three atoms(spheres) and two tubes/cylinders which are separated by the specified angle. Also, the axis of the tubes need to be in X-Z plane(axis of the tube here means an imaginary line passing through the center of the tube length wise). Now this can be done in multiple ways by various translations and rotations. I will pick the one which is relatively easy.
Fig 3. Tube(O-H bond) on top of Oxygen
3. Now rotate the tube 90º along Z axis to place the tube in X-Z axis
Fig 4. OH bond rotated by 90 degrees
4. Rotate again by specified angle to form the water molecule. Do this for other O-H bond too
Fig 5. OH bond rotated by 37.775 degrees along Y axis
5. Add the Hydrogen atoms and you have the water molecule.
Now lets put this into code…
The following code adds two tubes at the head of the Oxygen atom already in place as shown in Fig 3.
By default the pivot of the tube is at the center. We change that and place it at the lower end of the tube.
let tube = SCNTube(innerRadius: 0.001, outerRadius: 0.0015, height: 0.05)
let OHbondOne = SCNNode(geometry: tube)OHbondOne.geometry?.firstMaterial?.diffuse.contents = UIColor.blue
let OHbondTwo = SCNNode(geometry: tube)OHbondTwo.geometry?.firstMaterial?.diffuse.contents = UIColor.blue
OHbondOne.position = SCNVector3(0.0, 0.025, -0.1)OHbondOne.pivot = SCNMatrix4MakeTranslation(0, -0.025, 0)OHbondOne.position.y = OHbondOne.position.y - 0.025
OHbondTwo.position = SCNVector3(0.0, 0.025, -0.1)OHbondTwo.pivot = SCNMatrix4MakeTranslation(0, -0.025, 0)OHbondTwo.position.y = OHbondTwo.position.y - 0.025
sceneView.scene.rootNode.addChildNode(OHbondOne)sceneView.scene.rootNode.addChildNode(OHbondTwo)
Now we need to rotate the tubes 90º clockwise to bring them in X-Z axis as in Fig 4.
let rotateAlongZAxis = SCNAction.rotateBy(x:0 , y: 0, z: -CGFloat(Float.pi/2), duration: 1)
OHbondOne.runAction(rotateAlongZAxis)OHbondTwo.runAction(rotateAlongZAxis)
Now we need to rotate the tubes along Y axis to get the molecular structure (Fig 5). But we need to determine to what angle it needs to be rotated. Simple analysis of the angles gives us the following.
We need to rotate first tube by 37.755º and second tube by 142.205º(37.755º+104.45º).
let rotateOHBondOneAlongYAxis = SCNAction.rotateBy(x:CGFloat(self.degreesToRadians(degrees: 37.755)), y: 0, z: 0, duration: 0.1)
let rotateOHBondTwoAlongYAxis = SCNAction.rotateBy(x:CGFloat(self.degreesToRadians(degrees: 142.205)), y: 0, z: 0, duration: 0.1)
OHbondOne.runAction(rotateOHBondOneAlongYAxis)
OHbondTwo.runAction(rotateOHBondTwoAlongYAxis)
Function to convert degrees to radians
func degreesToRadians(degrees: Float) -> Float {return (degrees * .pi) / 180.0}
Fig 6. OH bonds after rotation along Y axis
Now we need to add the Hydrogen atoms. We know where to add — at the other end of the bonds. But the problem is how exactly do we do it?
Fig 7. Hydrogen atom displacement calculation
So for H1, Place the Hydrogen atom in the same place as Oxygen and then
and for H2, Place the Hydrogen atom in the same place of Oxygen and then
Here is the code to do that,
let hSphere = SCNSphere(radius: 0.007)
let hOneNode = SCNNode(geometry: hSphere)hOneNode.geometry?.firstMaterial?.diffuse.contents = UIColor.gray
let hTwoNode = SCNNode(geometry: hSphere)hTwoNode.geometry?.firstMaterial?.diffuse.contents = UIColor.gray
hOneNode.position = SCNVector3(0.0, 0.0, Float(-0.1))hTwoNode.position = SCNVector3(0.0, 0.0, Float(-0.1))
sceneView.scene.rootNode.addChildNode(hOneNode)sceneView.scene.rootNode.addChildNode(hTwoNode)
self.placeHOneAtom(hone: hOneNode)self.placeHTwoAtom(htwo: hTwoNode)
// 0.05m is the bond(tube) length here
func placeHOneAtom(hone: SCNNode) {
hone.position.x = hone.position.x -cos(self.degreesToRadians(degrees: 37.755)) \* 0.05
hone.position.z = hone.position.z + sin(self.degreesToRadians(degrees: 37.755)) \* 0.05
}
func placeHTwoAtom(htwo: SCNNode) {
htwo.position.x = htwo.position.x + cos(self.degreesToRadians(degrees: 37.755)) \* 0.05
htwo.position.z = htwo.position.z + sin(self.degreesToRadians(degrees: 37.755)) \* 0.05
}
Finally, we have the molecule once all of the code is added…
The completed project is available here.
Note: