2014-08-31 3 views
3

3D SceneKit 장면에서 2D 텍스처를 조작하고 싶습니다. 그러므로 내가 로컬 좌표를 얻기 위해이 코드를 사용 :SceneKit은 Swift로 터치 한 후 텍스처 좌표를 얻습니다.

@IBAction func tap(sender: UITapGestureRecognizer) { 
    var arr:NSArray = my3dView.hitTest(sender.locationInView(my3dView), options: NSDictionary(dictionary: [SCNHitTestFirstFoundOnlyKey:true])) 
    var res:SCNHitTestResult = arr.firstObject as SCNHitTestResult 

    var vect:SCNVector3 = res.localCoordinates} 

나는 질감이 내 장면로부터 판독이 있습니다

var mat:SCNNode = myscene.rootNode.childNodes[0] as SCNNode 
    var child:SCNNode = mat.childNodeWithName("ID12", recursively: false) 
    var geo:SCNMaterial = child.geometry.firstMaterial 
    var channel = geo.diffuse.mappingChannel   
    var textureimg:UIImage = geo.diffuse.contents as UIImage 

지금은 텍스처에 터치 포인트에서 그리려는 .. 어떻게 할 수 있습니까? 터치에서 텍스처 이미지로 좌표를 변환하는 방법은 무엇입니까?

답변

6

두 가지 문제가있는 것 같습니다. (Without even having used regular expressions. :))

먼저, 꼭지점의 텍스처 좌표, 즉 객체 표면의 2D 텍스처 공간에있는 점을 가져와야합니다. 당신은 거의 이미 그걸 가지고 있습니다. SCNHitTestResulttextureCoordinatesWithMappingChannel 방법을 제공합니다. (당신은 localCoordinates을 사용하고 있습니다. 이는 히트 테스트 결과에서 노드가 소유 한 3D 공간에서 한 지점을 얻습니다.) 그리고 채널 매핑에 대한 사업을 이미 알았으므로 그 방법에 무엇을 전달해야하는지 알 것입니다 .

문제 2는 그립하는 방법입니다.

자료의 내용을 UIImage으로 가져 오는 것은 옳은 일입니다. 일단 당신이 그것을 얻으면, 당신은 UIGraphicsCGContext 함수로 그림을 볼 수 있습니다. UIGraphicsBeginImageContext으로 이미지를 만들고, 기존 이미지를 그려 넣은 다음, 새로운 점을 추가 할 위치에 추가하십시오. 그 다음에는 그림을 UIGraphicsGetImageFromCurrentImageContext으로 가져와 새로운 재질로 diffuse.contents으로 설정할 수 있습니다. 그러나 이것이 아마도 최선의 방법은 아닙니다. CPU에서 이미지 데이터를 많이 사용하고 있으며 코드도 다루기가 쉽지 않습니다.

더 나은 방법은 SceneKit과 SpriteKit 간의 통합을 활용하는 것입니다. 이렇게하면 모든 2D 드로잉이 3D 드로잉과 동일한 GPU 컨텍스트에서 일어나고 코드가 조금 더 간단 해집니다.

재료의 diffuse.contents을 SpriteKit 장면으로 설정할 수 있습니다. (텍스처를 가지고있는 UIImage을 사용하려면 장면을 채우는 SKSpriteNode에 붙이면됩니다.) 텍스처 좌표를 얻으면 그 시점의 장면에 스프라이트를 추가 할 수 있습니다. (오브젝티브 C로) SpriteKit 방법에 대한 자세한 내용

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) 
     } 
    } 
} 

는 WWDC14에서 SceneKit State of the Union Demo 참조. SphereKit 장면이 토러스의 텍스처 맵으로 사용되어 페인트 구가 던져진 상태입니다. 구가 토러스와 충돌 할 때마다 SCNHitTestResult이 생기고 그 텍스쳐를 사용하여 SpriteKit 장면에 페인트 튄자를 만듭니다.


마지막으로, 코드에 대한 몇 가지 스위프트 스타일의 주석 (질문과 대답 무관) :

  • 사용 let 대신 var는 어디든지 당신이 값을 다시 할당 할 필요가 없습니다, 및 최적화 코드를 더 빨리 만들 수 있습니다.
  • 명시 적 형식 주석 (res: SCNHitTestResult)은 거의 필요하지 않습니다.
  • 스위프트 사전은 NSDictionary에 연결되므로 NSDictionary을 사용하는 API로 직접 전달할 수 있습니다.
  • 신속한 입력 배열 (hitTest(...) as [SCNHitTestResult])로 전송하면 내용을 캐스팅하지 않아도됩니다.
+0

Thx! 나는 매핑 채널을 위해 항상 -1을 얻고있다. – Philsen

+0

테스트에서 0이 표시됩니다. 'SKScene'을 확산 머티리얼로 지정하기 전이나 후에'mappingChannel' 속성을 읽으십니까? 텍스처 좌표가있는 지오메트리를 사용하고 있습니까? – rickster

+0

아니, 나중에 해. 어떻게 기하학이 텍스처 좌표를 가지고 있는지를 결정할 수 있습니다. – Philsen

관련 문제