Draw hemisphere in SceneKit using Swift - swift4

How to draw a hemisphere in scene kit programatically using swift, I trying the build the hemisphere robot head using scene kit but did not how to do, I came to know we can use SCNShape with bezier path
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 0.4, height: 0.4))
let bottomNode = SCNNode()
let hemisphere = SCNShape(path: path, extrusionDepth: 0.1)
but did not generated the hemisphere. Can any one help me on this?

Related

How can I draw a circle in SceneKit using its radius and origin?

What I am trying to do that draw a circle node using its radius and origin points.
Is there any way to draw a circle node in SceneKit?
How can I draw that?
First approach
Use SceneKit SCNCylinder's procedural mesh to create a circle.
func circle(origin: SCNVector3, radius: CGFloat) -> SCNNode {
let cylinderNode = SCNNode()
cylinderNode.geometry = SCNCylinder(radius: radius, height: 0.001)
cylinderNode.geometry?.firstMaterial?.diffuse.contents = UIColor.red
cylinderNode.geometry?.firstMaterial?.isDoubleSided = true
cylinderNode.position = origin
cylinderNode.eulerAngles.x = .pi/2
return cylinderNode
}
sceneView.scene?.rootNode.addChildNode(circle(
origin: SCNVector3(), radius: 0.5)
)
Second approach
This approach is impractical for your particular case, because you must specify the radius in UIKit units, not in meters like in SceneKit. However, I decided to publish it as option B.
// Path
let circlePath = UIBezierPath(arcCenter: CGPoint(x: 0, y: 0),
radius: 20,
startAngle: 0.0,
endAngle: .pi * 2,
clockwise: true)
circlePath.flatness = 0.1
// Shape
let material = SCNMaterial()
material.diffuse.contents = UIColor.systemRed
material.isDoubleSided = true
let circleShape = SCNShape(path: circlePath, extrusionDepth: 0.001)
circleShape.materials = [material]
// Node
let circleNode = SCNNode()
circleNode.geometry = circleShape
sceneView.scene?.rootNode.addChildNode(circleNode)
You could probably do something like this:
let circle = SCNPlane(width: 1.0, height: 1.0)
circle.cornerRadius = circle.width/2
hope, this is, what you are looking for.
another approch might be the SCNCylinder with a very small height or even SCNTorus with a very small pipe radius.

Cropping An Image (CIImage) To A UIBezierPath

I have seen this question asked in varying ways on Stack Overflow, but I have not seen an implementation that leverages anything but UIKit to develop an approach. For my use case, I have a CIImage and UIBezierPath (rather, a set of points from a machine learning feature detection model) that I would like to use a "mask" for the CIImage.
For example, I may have an image of a person's face. Subsequently, I may have a UIBezierPath that creates a closed shape around one of their eyes. Ideally, I would like to "crop" my CIImage to encompass the UIBezierPath. I recognize that since the final image will need to be square/rectangle, I would like to have any area outside of the UIBezierPath either black or transparent so it can be used as a mask for a future composition.
At present, I have code set up as such;
func doCrop(image: CIImage) -> CIImage {
// The drawing context (here to show I need to use CIContext for another use later on in this function.
let ciContext = CIContext()
// The original source image
let source = image
// Setup the path
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 400, y: 0))
path.addLine(to: CGPoint(x: 600, y: 200))
path.addLine(to: CGPoint(x: 400, y: 400))
path.addLine(to: CGPoint(x: 200, y: 400))
path.addLine(to: CGPoint(x: 100, y: 200))
path.close()
// Test
let cropped = source.cropped(to: path.bounds)
}
To be honest, I'm really unsure where to go from here. From what I have ascertained online, I see solutions that either implement UIKit to create an image context and draw a path, or solutions that only mask a UIImageView (which is not relevant for my needs, as I will need to draw this into a CIContext and pass through a Metal shader at a later point).

ARKit: Occlude everything in a plane except reference image

I have an image reference that is triggering an experience on ARKit2, and I want to create an occlusion plane that covers everything around my trigger, except the trigger itself. Representatively, it is something like this (placed the image below the plane to show better, but it is in reality on the same level):
As of now, I have no issue with making an occlusion on a regular shape like so:
func setOcclusionMaterial() {
let occlusionPlane = SCNPlane(width: imageReference!.physicalSize.width, height: imageReference!.physicalSize.height)
let holdout = SCNMaterial()
holdout.isDoubleSided = true
holdout.diffuse.contents = CIColor.black
holdout.colorBufferWriteMask = SCNColorMask(rawValue: 0)
occlusionPlane.firstMaterial? = holdout
let occlusionNode = SCNNode()
occlusionNode.eulerAngles.x = -.pi / 2
occlusionNode.geometry = occlusionPlane
node!.addChildNode(occlusionNode)
}
However, I'm not sure how I could create a plane that excludes the image area (a circle).
What I'm trying to do is to place a 3D element that appears to be below my trigger but only visible if seen top-down or with a slight angle.
Hope this is clear enough and thanks for your help if you have any ideas.
Your code does not render an occlusion for me, at least not in the Playground I quickly threw together. Maybe you can create one if my answer does not actually solve your problem.
You have to options here. Either create a custom geometry, in a 3D modelling tool like blender or manual via SCNGeometrySource but that is expansive because you will need a lot of triangles to make it work.
You can try to apply a CALayer as the plane's geometry:
Create a CGPath that is the rectangle with the circular cutout (or any form you'd like) and create a CAShapeLayer from the path.
var path = CGMutablePath()
path.addRect(CGRect(x: 0, y: 0, width: 100, height: 100))
path.addEllipse(in: CGRect(x: 25, y: 25, width: 50, height: 50))
let layer = CAShapeLayer()
layer.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
layer.path = path
layer.fillColor = UIColor.white.cgColor
layer.fillRule = .evenOdd
I could not confirm this actually worked because your occlusion is not quite working for me.

Move object with finger following path [Swift]

I have a circle in my view, With a little oval that can be moved around that big circle, the idea of moving the little oval is to change the time on the clock. I am trying to move the oval but only by following the path so it won't get out of the circle. As if it was a rail road and the train only follows the rail roads but at the time follows the finger position.
Here I attach the image Image
I tried creating an animation, and maybe use that animation to then follow the finger. I don't really know how to do this. Any help please?
Here is my code for the animation (that don't work):
let customPath = UIBezierPath()
customPath.move(to: CGPoint.init(x: 160, y: 165))
customPath.addLine(to: CGPoint.init(x: 260, y: 245))
customPath.addLine(to: CGPoint.init(x: 165, y: 365))
customPath.addLine(to: CGPoint.init(x: 60, y: 260))
let movingImage = UIImage(named: "MoveOval")
let movingLayer = CALayer()
movingLayer.anchorPoint = CGPoint.zero
movingLayer.contents = moveOval
movingLayer.frame = CGRect.init(x: 0.0, y: 0.0, width: (movingImage?.size.width)!, height: (movingImage?.size.height)!)
self.view.layer.addSublayer(movingLayer)
let pathAnimation = CAKeyframeAnimation(keyPath: "anim")
pathAnimation.duration = 4.0
pathAnimation.path = customPath.cgPath
pathAnimation.calculationMode = kCAAnimationLinear
movingLayer.add(pathAnimation, forKey: "anim")

How to draw 3D object with core graphics in Swift?

How can I draw a 3D object (preferably a rectangle) with core graphics in Swift?
Is it possible or do I have to use a different library?
Is it possible with UIKit?
Borrowing from this answer: https://stackoverflow.com/a/24127282/887210
The key part for your question is:
SCNBox(width: 1, height: 4, length: 9, chamferRadius: 0)
This draws a rectangular box with SceneKit and UIKit. It's set up to be used in a custom UIViewController in your project but it can easily be adapted to other uses.
The example code:
override func loadView() {
// create a scene view with an empty scene
let sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
let scene = SCNScene()
sceneView.scene = scene
// default lighting
sceneView.autoenablesDefaultLighting = true
// a camera
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
scene.rootNode.addChildNode(cameraNode)
// a geometry object
let box = SCNBox(width: 1, height: 4, length: 9, chamferRadius: 0)
let boxNode = SCNNode(geometry: box)
scene.rootNode.addChildNode(boxNode)
// configure the geometry object
box.firstMaterial?.diffuse.contents = UIColor.red
box.firstMaterial?.specular.contents = UIColor.white
// set a rotation axis (no angle) to be able to
// use a nicer keypath below and avoid needing
// to wrap it in an NSValue
boxNode.rotation = SCNVector4(x: 1, y: 1, z: 0.0, w: 0.0)
// animate the rotation of the torus
let spin = CABasicAnimation(keyPath: "rotation.w") // only animate the angle
spin.toValue = 2.0*Double.pi
spin.duration = 10
spin.repeatCount = HUGE // for infinity
boxNode.addAnimation(spin, forKey: "spin around")
view = sceneView // Set the view property to the sceneView created here.
}
This question is similar to the question whether it is possible to draw a 3D object on a sheet of paper which is, between, 2D. The third dimension effect is achieved drawing additional lines as the projections. The third dimension could also be perceived through the motion, so, Core Animation is a possible companion to Core Graphics but it requires a lot of calculation, as result, it is quite complicated (using Core Animation).
Actually, SceneKit or Metal are the options to draw 3D models using Swift.