How to draw line node keep same size in camera as Measure App in iPhone?

隐身守侯 提交于 2021-02-19 09:00:23

问题


I try make an AR app as a Measure default app in iPhone. ( I base on project TBXark/Ruler on github)

I draw startNode, endNode, cylinder line, and SCNText. But I can't manage the scale of size, it only readable in near, and so small when measure far plane detect.

I have 2 question:

  1. How to keep size node, cylinder and text same when draw near or far as Measure App

  2. How to draw scntext with background and align the same direction cylinder line as Measure App.

Here is my Line Node class:

class LineNode: NSObject {

let startNode: SCNNode
let endNode: SCNNode
var lineNode: SCNNode?
let textNode: SCNNode
let sceneView: ARSCNView?

// init func
init(startPos: SCNVector3,
     sceneV: ARSCNView,
     color: (start: UIColor, end: UIColor) = (UIColor(hexCss: 0xF1B426), UIColor(hexCss: 0xD43278)),
     font: UIFont = UIFont.boldSystemFont(ofSize: 8) ) {
    sceneView = sceneV

    let scale = 1 / 400.0
    let scaleVector = SCNVector3(scale, scale, scale)

    func buildSCNSphere(color: UIColor) -> SCNSphere {
        let dot = SCNSphere(radius: 1)
        dot.firstMaterial?.diffuse.contents = color
        dot.firstMaterial?.lightingModel = .constant
        dot.firstMaterial?.isDoubleSided = true
        return dot
    }
    // startNode
    startNode = SCNNode(geometry: buildSCNSphere(color: color.start))
    startNode.scale = scaleVector
    startNode.position = startPos
    sceneView?.scene.rootNode.addChildNode(startNode)

    // endNode
    endNode = SCNNode(geometry: buildSCNSphere(color: color.end))
    endNode.scale = scaleVector
    // line with start to end
    lineNode = CylinderLine(parent: sceneView!.scene.rootNode,
                            v1: startNode.position,
                            v2: endNode.position,
                            radius: 0.001,
                            radSegmentCount: 16,
                            color: UIColor.white)

    sceneView?.scene.rootNode.addChildNode(lineNode!)
    // text show measure line length
    let text = SCNText (string: "--", extrusionDepth: 0.1)
    text.font = font
    text.firstMaterial?.diffuse.contents = UIColor(hexCss: 0xffa800)
    text.firstMaterial?.lightingModel = .constant
    text.alignmentMode = CATextLayerAlignmentMode.center.rawValue
    text.truncationMode = CATextLayerTruncationMode.middle.rawValue
    text.firstMaterial?.isDoubleSided = true
    textNode = SCNNode(geometry: text)

    textNode.scale = SCNVector3(1 / 500.0, 1 / 500.0, 1 / 500.0)

    super.init()
}

// update end node realtime
public func updatePosition(pos: SCNVector3, camera: ARCamera?, unit: MeasurementUnit.Unit = MeasurementUnit.Unit.centimeter) -> Float {
    // update endNode
    let posEnd = updateTransform(for: pos, camera: camera)
    if endNode.parent == nil {
        sceneView?.scene.rootNode.addChildNode(endNode)
    }
    endNode.position = posEnd
    // caculate new mid
    let posStart = startNode.position
    let middle = SCNVector3((posStart.x + posEnd.x) / 2.0, (posStart.y + posEnd.y) / 2.0 + 0.002, (posStart.z + posEnd.z) / 2.0)
    // update text measure
    let text = textNode.geometry as! SCNText
    let length = posEnd.distanceFromPos(pos: startNode.position)
    text.string = MeasurementUnit(meterUnitValue: length).roundUpstring(type: unit)
    text.materials.first?.diffuse.contents = UIColor.orange
    textNode.setPivot()
    textNode.position = middle
    if textNode.parent == nil {
        sceneView?.scene.rootNode.addChildNode(textNode)
    }

    lineNode?.removeFromParentNode()
    lineNode = lineBetweenNodeA(nodeA: startNode, nodeB: endNode)
    sceneView?.scene.rootNode.addChildNode(lineNode!)

    return length
    }
}


回答1:


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)


来源:https://stackoverflow.com/questions/57264206/how-to-draw-line-node-keep-same-size-in-camera-as-measure-app-in-iphone

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!