Phi*_*sen 3 objective-c ios scenekit swift ios8
我想在3D SceneKit场景中操纵2D纹理.因此我使用此代码获取本地坐标:
@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}
Run Code Online (Sandbox Code Playgroud)
我从我的场景中读出纹理:
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
Run Code Online (Sandbox Code Playgroud)
现在我想在接触点绘制纹理......我怎么能这样做?如何将我的坐标从触摸转换为纹理图像?
听起来你有两个问题.(甚至没有使用正则表达式.:))
首先,您需要获取轻敲点的纹理坐标 - 即对象表面上的2D纹理空间中的点.你已经差不多了.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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
有关SpriteKit方法的更多详细信息(在Objective-C中),请参阅WWDC14的Union Demo的SceneKit状态.这显示了一个SpriteKit场景,用作环面的纹理贴图,其中的球体被抛出 - 当球体与圆环碰撞时,它得到一个SCNHitTestResult并使用其texcoords在SpriteKit场景中创建一个油漆飞溅.
最后,对您的代码进行一些Swift风格的评论(与问题和答案无关):
let而不是var在不需要重新分配值的地方,优化器将使您的代码更快.res: SCNHitTestResult很少需要显式类型注释().NSDictionary,因此您可以将它们直接传递给需要的API NSDictionary.hitTest(...) as [SCNHitTestResult])可以使您不必转换内容.| 归档时间: |
|
| 查看次数: |
3546 次 |
| 最近记录: |