Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SceneKit – Drawing on 3D Object

I created sample application to draw on 3d objects, the output drawing is not smooth(as in figure). I spent nearly a day to figure out what is the issue still not able to solve. What might be the issue? enter image description here

I am creating custom drawing geometry like below

//I am creating self.drawingNode touches begin and adding to the rootnode
//points are nothing but 2d points from touches

func createGeometryForPoints(points:[CGPoint]) -> SCNGeometry {

    var all_3d_points:[SCNVector3] = []

    for point in points {

        let result = self.get3dPoint(point)

        if result.1 == true {
            all_3d_points.append(result.0)
        } else {
            print("INVALID POINT")
        }
    }

    var indices: [Int32] = []
    var index:Int32 = 0

    var previousIndex:Int32 = -1

    for _ in all_3d_points {

        if(previousIndex != -1) {

            indices.append(previousIndex)
        }
        indices.append(index)
        index = index + 1
        previousIndex = index
    }

    if indices.count > 0 {
        indices.removeLast();
    }

    let indexData = NSData(bytes: indices, length: sizeof(Int32) * indices.count)

    let source = SCNGeometrySource.init(vertices: all_3d_points, count: all_3d_points.count)
    let element = SCNGeometryElement.init(data: indexData, primitiveType: .Line, primitiveCount: indices.count/2, bytesPerIndex: sizeof(Int32))

    let line = SCNGeometry(sources: [source], elements: [element])
    line.materials.first?.diffuse.contents = UIColor.redColor()
    line.materials.first?.doubleSided = true

    return line
}

func get3dPoint(point:CGPoint) -> (SCNVector3,Bool) {

    var canAdd = false
    let scnView = self.view as! SCNView
    var unprojectedStartPoint = SCNVector3.init(x:Float(point.x), y:Float(point.y), z:0)

    let hitResults = scnView.hitTest(point, options: nil)
    if hitResults.count > 0 {

        let result: AnyObject! = hitResults[0]
        if hitResults.count > 1 {
            print("SOME PROBLEM")
        }
        unprojectedStartPoint = result.localCoordinates
        unprojectedStartPoint = result.node.convertPosition(unprojectedStartPoint, toNode: self.drawingNode!)

        canAdd = true
    }

    return (unprojectedStartPoint,canAdd)
}

EDIT

I am thinking of finding the offset along with the camera direction or normal, since I am new to scenekit i am not getting how to add this offset to drawing node, looking of help here in this direction

func createMarkup() -> Void {   
    let drawingNode = SCNNode()
    drawingNode.renderingOrder = 1000
    self.parentNode!.addChildNode(drawingNode)
    let geometry = self.createGeometryForPoints(allPoints,node: drawingNode)
    drawingNode.geometry = geometry
    drawingNode.geometry?.materials.first?.doubleSided = true
}

EDIT: 2

Solved the issue by adding minor offset along the normal of the hit-test

let offsetToAvoidFlickering: Float = 0.05
unprojectedStartPoint = unprojectedStartPoint + result.localNormal.normalized() * offsetToAvoidFlickering
like image 252
Chandan Shetty SP Avatar asked Jun 21 '16 08:06

Chandan Shetty SP


2 Answers

I suspect you have depth precision issues; it looks like parts of your line are being clipped because they are intersecting parts of the sphere. Try drawing the line with depth testing disabled.

like image 166
solidpixel Avatar answered Nov 04 '22 08:11

solidpixel


the SceneKit State of the Union Demo sample code shows a similar effect, where you can paint on a torus. It's more powerful because you can draw anything (not just line, but splashes from texture etc.) and much more efficient because it doesn't rely on creating new geometry.

like image 37
mnuages Avatar answered Nov 04 '22 10:11

mnuages