gpt4 book ai didi

ios - SceneKit 在与 Swift 接触后获取纹理坐标

转载 作者:搜寻专家 更新时间:2023-10-31 22:09:00 25 4
gpt4 key购买 nike

我想在 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}

我从我的场景中读取了纹理:

    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

现在我想在纹理的接触点处绘制...我怎样才能做到这一点?如何将我的坐标从触摸转换为纹理图像?

最佳答案

听起来你有两个问题。 ( Without even having used regular expressions. :) )

首先,您需要获取点击点的纹理坐标——即物体表面二维纹理空间中的点。你几乎已经做对了。 SCNHitTestResult 提供了 textureCoordinatesWithMappingChannel方法。 (您正在使用 localCoordinates,这会在 HitTest 结果中的节点拥有的 3D 空间中获取一个点。)并且您似乎已经找到了有关映射 channel 的业务,所以您知道要传递给该方法的内容。

问题 #2 是如何绘制。

您以 UIImage 的形式获取 Material 的内容是正确的做法。完成后,您可以研究使用 UIGraphicsCGContext 函数进行绘图——使用 UIGraphicsBeginImageContext 创建图像,绘制现有图像放入其中,然后在点击点绘制要添加的任何新内容。之后,您可以使用 UIGraphicsGetImageFromCurrentImageContext 获取正在绘制的图像,并将其设置为 Material 的新 diffuse.contents。然而,这可能不是最好的方法——您在 CPU 上处理大量图像数据,而且代码也有点笨拙。

更好的方法可能是利用 SceneKit 和 SpriteKit 之间的集成。这样,您的所有 2D 绘图都在与 3D 绘图相同的 GPU 上下文中进行——而且代码也稍微简单一些。

您可以将 Material 的 diffuse.contents 设置为 SpriteKit 场景。 (要使用您当前拥有的用于该纹理的 UIImage,只需将其粘贴到填充场景的 SKSpriteNode 上即可。)获得纹理坐标后,您可以添加 Sprite 到现场。

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 中)的更多详细信息,请参阅 SceneKit State of the Union Demo来自 WWDC14。这显示了一个用作环面纹理贴图的 SpriteKit 场景,油漆球体被扔向它——每当球体与环面碰撞时,它都会得到一个 SCNHitTestResult 并使用它的纹理坐标创建一个在 SpriteKit 场景中绘制飞溅效果。


最后,对您的代码进行一些 Swift 风格的注释(与问答无关):

  • 在不需要重新分配值的地方使用 let 而不是 var,优化器将使您的代码运行得更快。
  • 很少需要显式类型注释(res: SCNHitTestResult)。
  • Swift 词典桥接到 NSDictionary,因此您可以将它们直接传递给采用 NSDictionary 的 API。
  • 转换为 Swift 类型数组(hitTest(...) as [SCNHitTestResult])使您不必转换内容。

关于ios - SceneKit 在与 Swift 接触后获取纹理坐标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25591573/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com