How to draw dashed line in ARKit (SceneKit) like in the Measure app?
Probably not the most professional solution, but I started with a very similar approach. And then added the dashed-style like follows.
First I created an image that is half white, half transparent, to create the dashed-style
Then used it in the material of the SCNCylinder
:
material.diffuse.contents = UIImage(named: "line")!
material.diffuse.wrapS = .repeat
material.diffuse.wrapT = .repeat
material.isDoubleSided = true // Not sure if this is really needed here^
Next I scaled it accordingly, to repeat it (make it as fine) as I want it:
material.diffuse.contentsTransform = SCNMatrix4MakeScale(width * repeatCountPerMeter, height * repeatCountPerMeter, 1)
As I used a white image, I can "tint" it in any color I want:
material.multiply.contents = UIColor.green
To make it look more "2D like", ignore the lighting, using:
material.lighting = .constant
Additionally (as my Cylinder is rotated by 90°) I had to rotate the material as well:
let rotation = SCNMatrix4MakeRotation(.pi / 2, 0, 0, 1)
material.diffuse.contentsTransform = SCNMatrix4Mult(rotation, material.diffuse.contentsTransform)
And whenever the line gets resized, update its SCNMatrix4MakeScale
accordingly (see width
and heightabove, where for
height` I just put the diameter (2*r)).
Draw dashline cylinder in scenekit like measure app?
Another approach for Line & DashLine
final class LineNode: SCNNode {
var color: UIColor? {
set { geometry?.firstMaterial?.diffuse.contents = newValue }
get { geometry?.firstMaterial?.diffuse.contents as? UIColor }
}
convenience init(positionA: SCNVector3, positionB: SCNVector3, dash: CGFloat = 0, in scene: SCNScene? = nil) {
self.init()
let indices: [Int32] = [0, 1]
let source = SCNGeometrySource(vertices: [positionA, positionB])
let element = SCNGeometryElement(indices: indices, primitiveType: .line)
geometry = SCNGeometry(sources: [source], elements: [element])
geometry?.firstMaterial?.diffuse.contents = UIColor.green
geometry?.firstMaterial?.lightingModel = .constant
return
}
}
final class DashLineNode: SCNNode {
convenience init(positionA: SCNVector3, positionB: SCNVector3) {
self.init()
let vector = (positionB - positionA)
let length = floor(vector.length / 1)
let segment = vector / length
let indices:[Int32] = Array(0..<Int32(length))
var vertices = [positionA]
for _ in indices {
vertices.append(vertices.last! + segment)
}
let source = SCNGeometrySource(vertices: vertices)
let element = SCNGeometryElement(indices: indices, primitiveType: .line)
geometry = SCNGeometry(sources: [source], elements: [element])
geometry?.firstMaterial?.lightingModel = .constant
}
}
How to draw line node keep same size in camera as Measure App in iPhone?
I use this to update scale if even if you stay far away it still readable
func updateScaleFromCameraForNodes(_ nodes: [SCNNode], fromPointOfView pointOfView: SCNNode , useScaling: Bool){
nodes.forEach { (node) in
//1. Get The Current Position Of The Node
let positionOfNode = SCNVector3ToGLKVector3(node.worldPosition)
//2. Get The Current Position Of The Camera
let positionOfCamera = SCNVector3ToGLKVector3(pointOfView.worldPosition)
//3. Calculate The Distance From The Node To The Camera
let distanceBetweenNodeAndCamera = GLKVector3Distance(positionOfNode, positionOfCamera)
let a = distanceBetweenNodeAndCamera*1.75
if(useScaling) {
node.simdScale = simd_float3(a,a,a)
}
}
SCNTransaction.flush()
}
then called it in the renderer updateAtTime
self.updateScaleFromCameraForNodes(self.nodesAdded, fromPointOfView:
self.cameraNode, useScaling: true)
Stroke Width with a SceneKit line primitive type
SceneKit doesn't provide controls for this. However, SceneKit draws using OpenGL ES, which does.
When you're drawing with GL in the GL_LINES
mode, the glLineWidth
call changes the line width. (Watch out: the argument is in actual pixels, not UI-layout points, so you'll need a larger width than you might think if you don't want super-thin hairlines on a Retina display.)
So, where do you call that in your SceneKit app? You have a few options there. In a simple scene like yours, where you're only rendering one thing, you can just set it before the scene renders. Set a delegate for your view, then implement renderer:willRenderSceneAtTime:
and call glLineWidth
there.
However, OpenGL line rendering is pretty limited — if you want to customize rendering more, you'll need a different approach. Just which approach works best depends on exactly what you're going for, so here are a few ideas for you to research:
- Make your "lines" from narrow triangle strips
- Make them from primitive SCN geometries like boxes and cylinders
- Keep a simple cube geometry, but use a fragment shader (or shader modifier snippet) to draw only near the edges of each polygon
Drawing edges of SCNBox without diagonal line?
I’m not sure on how to get rid of the diagonal lines.
But setting the material to double sided will draw the lines on the opposite side of the box.
box.geometry?.firstMaterial?.isDoubleSided = true
Edit:
Here's another approach to achieve what you want (get rid of those diagonal lines!)
let sm = "float u = _surface.diffuseTexcoord.x; \n" +
"float v = _surface.diffuseTexcoord.y; \n" +
"int u100 = int(u * 100); \n" +
"int v100 = int(v * 100); \n" +
"if (u100 % 99 == 0 || v100 % 99 == 0) { \n" +
" // do nothing \n" +
"} else { \n" +
" discard_fragment(); \n" +
"} \n"
let box = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)
box.firstMaterial?.emission.contents = UIColor.green
box.firstMaterial?.shaderModifiers = [SCNShaderModifierEntryPoint.surface: sm]
box.firstMaterial?.isDoubleSided = true
Related Topics
Delegate Must Respond to Locationmanager:Didupdatelocations Swift Eroor
Does Nsnumberformatter.Stringfromnumber Ever Return Nil
How Have Multiple Init() with Swift
How to Open a Url in Safari Even If My Default Browser Is Not Safari Using Swift in MACos
Why Can't Swift Automatically Convert a Generic Type Parameter to Its Superclass
Googlesignin - Always Return "The User Canceled the Sign-In Flow." in iOS 11
How to Convert a Unsafemutablepointer<Void> to Uint8
Why Is Casting a Struct to Anyobject Not a Compile Error in Swift
Cannot Call Value of Non-Function Type 'Nshttpurlresponse' Alamofire Objectmapper
Swiftui Nested Foreach Causes Unexpected Ordering
Round Currency Closest to Five
Swift Radio Streaming Avplayer
How to Create a Directory in Downloads Folder with Swift on MACos? Permission Exception
Check If Color Is Blue(Ish), Red(Ish), Green(Ish),
Codable/Decodable Should Decode Array with Strings