Drawing a line between two points using SceneKit

I have two points (let’s call them pointA and pointB) of type SCNVector3. I want to draw a line between them. Seems like it should be easy, but can’t find a way to do it.

I see two options, both have issues:

  • cameranode rotate as iOS device moving
  • How to use SceneKit to display a colorful point cloud using custom SCNGeometry?
  • How to calculate the camera position from Vuforia GL matrix?
  • Including textures when exporting from Blender to COLLADA/.dae format for use in SceneKit
  • Combining scenekit and spritekit in a single screen
  • How to get the real position of a sub node in SceneKit after rotation?
  • Use a SCNCylinder with a very small radius, with length |pointA-pointB| and then position it/rotate it.

    Use a custom SCNGeometry but not sure how; would have to define two triangles to form a very thin rectangle perhaps?

    It seems like there should be an easier way of doing this, but I can’t seem to find one.

    Edit: Using the triangle method gives me this for drawing a line between (0,0,0) and (10,10,10):

    CGFloat delta = 0.1;
    SCNVector3 positions[] = {  SCNVector3Make(0,0,0),
        SCNVector3Make(10, 10, 10),
        SCNVector3Make(0+delta, 0+delta, 0+delta),
        SCNVector3Make(10+delta, 10+delta, 10+delta)};
    int indicies[] = {
    SCNGeometrySource *vertexSource = [SCNGeometrySource geometrySourceWithVertices:positions count:4];
    NSData *indexData = [NSData dataWithBytes:indicies length:sizeof(indicies)];
    SCNGeometryElement *element = [SCNGeometryElement geometryElementWithData:indexData primitiveType:SCNGeometryPrimitiveTypeTriangles primitiveCount:2 bytesPerIndex:sizeof(int)];
    SCNGeometry *line = [SCNGeometry geometryWithSources:@[vertexSource] elements:@[element]];
    SCNNode *lineNode = [SCNNode nodeWithGeometry:line];
    [root addChildNode:lineNode];

    But there are problems: due to the normals, you can only see this line from one side! It’s invisible from the other side. Also, if “delta” is too small you can’t see the line at all. As it is, it’s technically a rectangle, rather than the line I was going for, which might result in small graphical glitches if I want to draw multiple joined up lines.

    4 Solutions Collect From Internet About “Drawing a line between two points using SceneKit”

    There are lots of ways to do this.

    As noted, your custom geometry approach has some disadvantages. You should be able to correct the problem of it being invisible from one side by giving its material the doubleSided property. You still may have issues with it being two-dimensional, though.

    You could also modify your custom geometry to include more triangles, so you get a tube shape with three or more sides instead of a flat rectangle. Or just have two points in your geometry source, and use the SCNGeometryPrimitiveTypeLine geometry element type to have Scene Kit draw a line segment between them. (Though you won’t get as much flexibility in rendering styles with line drawing as with shaded polygons.)

    You can also use the SCNCylinder approach you mentioned (or any of the other built-in primitive shapes). Remember that geometries are defined in their own local (aka Model) coordinate space, which Scene Kit interprets relative to the coordinate space defined by a node. In other words, you can define a cylinder (or box or capsule or plane or whatever) that’s 1.0 units wide in all dimensions, then use the rotation/scale/position or transform of the SCNNode containing that geometry to make it long, thin, and stretching between the two points you want. (Also note that since your line is going to be pretty thin, you can reduce the segmentCounts of whichever built-in geometry you’re using, because that much detail won’t be visible.)

    Yet another option is the SCNShape class that lets you create an extruded 3D object from a 2D B├ęzier path. Working out the right transform to get a plane connecting two arbitrary points sounds like some fun math, but once you do it you could easily connect your points with any shape of line you choose.

    Here’s a simple extension in Swift:

    extension SCNGeometry {
    class func lineFrom(vector vector1: SCNVector3, toVector vector2: SCNVector3) -> SCNGeometry {
        let indices: [Int32] = [0, 1]
        let source = SCNGeometrySource(vertices: [vector1, vector2], count: 2)
        let element = SCNGeometryElement(indices: indices, primitiveType: .Line)
        return SCNGeometry(sources: [source], elements: [element])

    New code for a line from (0, 0, 0) to (10, 10, 10) below.
    I’m not sure if it could be improved further.

    SCNVector3 positions[] = {
        SCNVector3Make(0.0, 0.0, 0.0),
        SCNVector3Make(10.0, 10.0, 10.0)
    int indices[] = {0, 1};
    SCNGeometrySource *vertexSource = [SCNGeometrySource geometrySourceWithVertices:positions
    NSData *indexData = [NSData dataWithBytes:indices
    SCNGeometryElement *element = [SCNGeometryElement geometryElementWithData:indexData
    SCNGeometry *line = [SCNGeometry geometryWithSources:@[vertexSource]
    SCNNode *lineNode = [SCNNode nodeWithGeometry:line];
    [root addChildNode:lineNode];

    Here’s one solution

    class func lineBetweenNodeA(nodeA: SCNNode, nodeB: SCNNode) -> SCNNode {
        let positions: [Float32] = [nodeA.position.x, nodeA.position.y, nodeA.position.z, nodeB.position.x, nodeB.position.y, nodeB.position.z]
        let positionData = NSData(bytes: positions, length: MemoryLayout<Float32>.size*positions.count)
        let indices: [Int32] = [0, 1]
        let indexData = NSData(bytes: indices, length: MemoryLayout<Int32>.size * indices.count)
        let source = SCNGeometrySource(data: positionData as Data, semantic: SCNGeometrySource.Semantic.vertex, vectorCount: indices.count, usesFloatComponents: true, componentsPerVector: 3, bytesPerComponent: MemoryLayout<Float32>.size, dataOffset: 0, dataStride: MemoryLayout<Float32>.size * 3)
        let element = SCNGeometryElement(data: indexData as Data, primitiveType: SCNGeometryPrimitiveType.line, primitiveCount: indices.count, bytesPerIndex: MemoryLayout<Int32>.size)
        let line = SCNGeometry(sources: [source], elements: [element])
        return SCNNode(geometry: line)

    if you would like to update the line width or anything related to modifying properties of the drawn line, you’ll want to use one of the openGL calls in SceneKit’s rendering callback:

    func renderer(aRenderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: NSTimeInterval) {
        //Makes the lines thicker