6

Just wanted to know is it possible (I know it is, but how) to draw dashed line in ARSCNView like in the Measure app? Maybe there is a way to use scene nodes out of the box, idk.

I've been using the SCNCylinder to draw a straight line and IDK is it possible to reuse it and adjust or we have to use a really different way to make the dashed line.

import SceneKit

class CylinderLineNode: SCNNode {

    private(set) var cylinder: SCNCylinder
    private(set) var positionA: SCNVector3
    private(set) var positionB: SCNVector3

    init(with positionA: SCNVector3, positionB: SCNVector3, radius: CGFloat = 0.02, color: UIColor = .red) {
        self.positionA = positionA
        self.positionB = positionB
        let vector = positionB - positionA
        let height = vector.length()
        cylinder = SCNCylinder(radius: radius, height: CGFloat(height))
        cylinder.radialSegmentCount = 8
        cylinder.firstMaterial?.diffuse.contents = color
        super.init()
        geometry = cylinder
        position = (positionB + positionA) / 2
        eulerAngles = SCNVector3.lineEulerAngles(vector: vector)
    }

    ...

}
atereshkov
  • 4,311
  • 1
  • 38
  • 49

1 Answers1

0

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 forheight` I just put the diameter (2*r)).

d4Rk
  • 6,622
  • 5
  • 46
  • 60
  • Yep, thanks. I already came up with the same approach, so will post my solution here (it's very similar to yours). – atereshkov Jan 11 '19 at 13:47
  • @atereshkov hey bro where's your solution? I can't make this solution works :( – Eddie Aug 20 '20 at 08:54
  • @Eddie Why does it not work for you? Maybe I could help. – d4Rk Aug 20 '20 at 09:02
  • @d4Rk I'm not sure where I'm missing since I don't really understand and just copy the code. Maybe the transform is missing because it's unclear to me what's `width`, `height`, and `repeatCountPerMeter`. I'm using the image created by UIGraphicContext, so probably nothing wrong with the image. maybe the contents transform is not correct? :| – Eddie Aug 20 '20 at 09:18
  • @d4Rk I've posted a new question here: https://stackoverflow.com/questions/63502194/draw-dashline-cylinder-in-scenekit-like-measure-app – Eddie Aug 20 '20 at 09:31
  • I used it like `lineMaterial.scaleDiffuse(width: start.distance(to: end), height: 0.004, repeatCountPerMeter: 30)` where `start` and `end` are two `SCNVector3`s, defining the start and end of the line to be rendered. – d4Rk Aug 20 '20 at 14:27
  • @Eddie hey if i can recall it I was using the d4Rk approach finally, there were not big changes between my solution. So following this you should make it work – atereshkov Aug 21 '20 at 13:51