[英]ARKit - How to contain SCNText within another SCNNode (speech bubble)
我正在嘗試在ARKit的氣泡中創建帶有簡單文本的報價生成器。
我可以用文本顯示氣泡,但是文本總是從中間開始,並在氣泡之外溢出。
任何將其對齊在氣泡左上方並包裹在氣泡內的幫助將不勝感激。
結果
類
class SpeechBubbleNode: SCNNode {
private let textNode = TextNode()
var string: String? {
didSet {
textNode.string = string
}
}
override init() {
super.init()
// Speech Bubble
let plane = SCNPlane(width: 200.0, height: 100.0)
plane.cornerRadius = 4.0
plane.firstMaterial?.isDoubleSided = true
geometry = plane
// Text Node
textNode.position = SCNVector3(position.x, position.y, position.z + 1.0)
// textNode.position = convertPosition(SCNVector3(0.0, 0.0, 1.0), to: textNode)
// textNode.position = SCNVector3(0.0, 0.0, position.z + 1.0)
addChildNode(textNode)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
class TextNode: SCNNode {
private let textGeometry = SCNText()
var string: String? {
didSet {
updateTextContainerFrame()
textGeometry.string = string
}
}
override init() {
super.init()
textGeometry.truncationMode = CATextLayerTruncationMode.middle.rawValue
textGeometry.isWrapped = true
textGeometry.alignmentMode = CATextLayerAlignmentMode.left.rawValue
let blackMaterial = SCNMaterial()
blackMaterial.diffuse.contents = UIColor.black
blackMaterial.locksAmbientWithDiffuse = true
textGeometry.materials = [blackMaterial]
geometry = textGeometry
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private func updateTextContainerFrame() {
let (min, max) = boundingBox
let width = CGFloat(max.x - min.x)
let height = CGFloat(max.y - min.y)
print("width :",max.x - min.x,"height :",max.y - min.y,"depth :",max.z - min.z)
textGeometry.containerFrame = CGRect(x: 0.0, y: 0.0, width: width, height: height)
// textGeometry.containerFrame = CGRect(origin: .zero, size: CGSize(width: 1.0, height: 1.0))
}
}
履行
private func makeSpeechBubbleNode(forBobbleheadNode bobbleheadNode: BobbleheadNode) {
let node = SpeechBubbleNode()
node.position = sceneView.scene.rootNode.convertPosition(bobbleheadNode.position, to: node)
node.scale = SCNVector3(0.002, 0.002, 0.002)
sceneView.scene.rootNode.addChildNode(speechBubbleNode)
self.speechBubbleNode = speechBubbleNode
speechBubbleNode.string = "Some random string that could be long and should wrap within speech bubble"
}
我遇到了同樣的問題,終於解決了如下問題:
創建一個SCNText並將其作為幾何添加到SCNNode:
let string = "Coverin text with a plane :)" let text = SCNText(string: string, extrusionDepth: 0.1) text.font = UIFont.systemFont(ofSize: 1) text.flatness = 0.005 let textNode = SCNNode(geometry: text) let fontScale: Float = 0.01 textNode.scale = SCNVector3(fontScale, fontScale, fontScale)
let (min, max) = (text.boundingBox.min, text.boundingBox.max) let dx = min.x + 0.5 * (max.x - min.x) let dy = min.y + 0.5 * (max.y - min.y) let dz = min.z + 0.5 * (max.z - min.z) textNode.pivot = SCNMatrix4MakeTranslation(dx, dy, dz)
創建一個PlaneNode並將textNode添加為PlaneNode的childNode:
let width = (max.x - min.x) * fontScale let height = (max.y - min.y) * fontScale let plane = SCNPlane(width: CGFloat(width), height: CGFloat(height)) let planeNode = SCNNode(geometry: plane) planeNode.geometry?.firstMaterial?.diffuse.contents = UIColor.green.withAlphaComponent(0.5) planeNode.geometry?.firstMaterial?.isDoubleSided = true planeNode.position = textNode.position textNode.eulerAngles = planeNode.eulerAngles planeNode.addChildNode(textNode)
最后,將PlaneNode添加到sceneView中:
sceneView.scene.rootNode.addChildNode(planeNode)
結果是:
如果您只需要在文本后面添加一個白框,則可以通過在渲染器函數中執行此操作來實現:
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
let node = SCNNode()
............
let testPlane = SCNPlane(width: someWidth, height: someHeight)
let testScene = SKScene(size: CGSize(width: 900, height: 900))
testScene.backgroundColor = UIColor.white
let str = SKLabelNode(text: "This is just a test")
str.color = UIColor.black
str.fontColor = UIColor.black
str.fontSize = 45.5
str.position = CGPoint(x: stuff.size.width / 2,
y: stuff.size.height / 2)
testScene.addChild(str)
testPlane.firstMaterial?.diffuse.contents = testScene
testPlane.firstMaterial?.isDoubleSided = true
testPlane.firstMaterial?.diffuse.contentsTransform = SCNMatrix4Translate(SCNMatrix4MakeScale(1, -1, 1), 0, 1, 0)
let testNode = SCNNode(geometry: testPlane)
testNode.eulerAngles.x = -.pi / 2
testNode.position = SCNVector3Make(0.0,0.0,0.0)
node.addChildNode(testNode)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.