聽起來像你有兩個問題。 (Without even having used regular expressions. :))
首先,您需要獲取點擊點的紋理座標 - 即點對象表面上的二維紋理空間。你幾乎已經有了這個權利。 SCNHitTestResult
爲那些提供了textureCoordinatesWithMappingChannel
方法。 (您正在使用localCoordinates
,它可讓您在命中測試結果中的節點所擁有的3D空間中獲得一個點)。您似乎已經找到了關於映射頻道的業務,因此您知道要傳遞給該方法的內容。
問題2是如何繪製。
您正在做正確的事情來獲取材料的內容爲UIImage
。一旦你有了這些,你可以看看UIGraphics
和CGContext
函數的繪圖 - 創建一個圖像與UIGraphicsBeginImageContext
,繪製現有的圖像,然後繪製任何新的內容,你想添加在點擊點。之後,您可以使用UIGraphicsGetImageFromCurrentImageContext
獲取您正在繪製的圖像,並將其設置爲您的素材的新diffuse.contents
。但是,這可能不是最好的方法 - 你在CPU上掃描一堆圖像數據,而且代碼也有點笨拙。
更好的方法可能是利用SceneKit和SpriteKit之間的集成。這樣,所有的2D繪圖都在與3D繪圖相同的GPU上下文中進行 - 代碼更簡單一些。
您可以將素材的diffuse.contents
設置爲SpriteKit場景。 (要使用目前用於該紋理的UIImage
,只需將其粘貼在填充場景的SKSpriteNode
上。)獲得紋理座標後,可以在該點添加一個精靈到場景中。
var nodeToDrawOn: SCNNode!
var skScene: SKScene!
func mySetup() { // or viewDidLoad, or wherever you do setup
// whatever else you're doing for setup, plus:
// 1. remember which node we want to draw on
nodeToDrawOn = myScene.rootNode.childNodeWithName("ID12", recursively: true)
// 2. set up that node's texture as a SpriteKit scene
let currentImage = nodeToDrawOn.geometry!.firstMaterial!.diffuse.contents as UIImage
skScene = SKScene(size: currentImage.size)
nodeToDrawOn.geometry!.firstMaterial!.diffuse.contents = skScene
// 3. put the currentImage into a background sprite for the skScene
let background = SKSpriteNode(texture: SKTexture(image: currentImage))
background.position = CGPoint(x: skScene.frame.midX, y: skScene.frame.midY)
skScene.addChild(background)
}
@IBAction func tap(sender: UITapGestureRecognizer) {
let results = my3dView.hitTest(sender.locationInView(my3dView), options: [SCNHitTestFirstFoundOnlyKey: true]) as [SCNHitTestResult]
if let result = results.first {
if result.node === nodeToDrawOn {
// 1. get the texture coordinates
let channel = nodeToDrawOn.geometry!.firstMaterial!.diffuse.mappingChannel
let texcoord = result.textureCoordinatesWithMappingChannel(channel)
// 2. place a sprite there
let sprite = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width: 10, height: 10))
// scale coords: texcoords go 0.0-1.0, skScene space is is pixels
sprite.position.x = texcoord.x * skScene.size.width
sprite.position.y = texcoord.y * skScene.size.height
skScene.addChild(sprite)
}
}
}
有關SpriteKit方法(在Objective-C)更多細節參見從WWDC14的SceneKit State of the Union Demo。這表明一個SpriteKit場景用作一個環面的紋理貼圖,並且有球體被拋到它上面 - 每當一個球體與環面碰撞時,它就會得到一個SCNHitTestResult
並使用它的texcoords在SpriteKit場景中創建一個油漆飛濺。
最後,在你的代碼中雨燕風格的註釋(無關的問題和答案):
- 使用
let
而不是var
無論你不需要重新分配一個值,並且優化會讓你的代碼更快。
- 顯式類型註釋(
res: SCNHitTestResult
)很少需要。
- Swift詞典橋接到
NSDictionary
,因此您可以直接將它們傳遞給需要NSDictionary
的API。
- 投射到一個Swift類型的數組(
hitTest(...) as [SCNHitTestResult]
)使您不必投射內容。
Thx!我總是爲映射通道-1。 – Philsen 2014-09-03 18:50:09
我在測試中看到0。你在分配「SKScene」作爲漫反射材料之前還是之後閱讀'mappingChannel'屬性?你使用的紋理座標是幾何嗎? – rickster 2014-09-03 20:26:24
不,我以後做。我怎樣才能確定幾何有紋理座標。 – Philsen 2014-09-04 20:46:36