场景套件。将节点合二为一 "surface"
SceneKit. Place nodes in one "surface"
用户在绘图视图上画一条线,然后我需要将这些点转换为 3d 世界,但将这些点放在一个“表面”中。为此,我将点数组映射到向量中(我将 hitTest 与 .featurePoint 结合使用),然后过滤该数组以获得另一个
func didEndDrawing(with points: [CGPoint]) {
guard let transform = sceneView.pointOfView?.transform else { return }
let cameraVectror = SCNVector3(transform.m31, transform.m32, transform.m33)
let farthestVector = points
.reduce((vector: SCNVector3(0, 0, 0), distance: CGFloat.zero)) { result, point in
guard let vector = getVector(for: point) else { return result }
let distance: CGFloat = cameraVectror.distance(to: vector)
return distance > result.distance ? (vector, distance) : result
}
.vector
}
let parentNode = SCNNode()
parentNode.position = farthestVector
如何调整坐标(我猜是 z 位置)以使所有子节点与视点的距离相同?
该应用程序的想法是在AR中徒手绘画。
更新
在 Voltan 的帮助下我解决了这个问题
points.forEach { point in
let scenePoint = sceneView.unprojectPoint(SCNVector3(point.x, point.y, CGFloat(projectedPoint.z)))
let sphere = SCNSphere(radius: 0.01)
let material = SCNMaterial()
material.diffuse.contents = UIColor.green
sphere.materials = [material]
let node = SCNNode(geometry: sphere)
node.position = scenePoint
sceneView.scene.rootNode.addChildNode(node)
}
如果我理解正确,您需要某种 tap/drag 组合 - 从 2D 世界获取点并将其转换为 3D 世界。这是导弹命令类型游戏的一些游戏代码,也许它会帮助你处理 unprojectPoint 的东西。有一些计时器未包括在内,但希望您能理解。
@objc func handleTap(recognizer: UITapGestureRecognizer)
{
if(data.gameState == .endGame)
{
endGameAnimates.stop()
let _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { _ in self.dismiss(animated: false, completion: nil) })
return
}
if(gameControl.isWaveComplete == true || gNodes.gameNodes.isPaused == true) { return }
currentLocation = recognizer.location(in: gameScene)
let projectedPoint = gameScene.projectPoint(SCNVector3(0, 0, 0))
let scenePoint = gameScene.unprojectPoint(SCNVector3(currentLocation.x, currentLocation.y, CGFloat(projectedPoint.z)))
if(data.gameState == .endGame) // Allow animations to finish, otherwise they will show up next round
{
DispatchQueue.main.async { self.endGameAnimates.stop() }
let _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { _ in self.dismiss(animated: false, completion: nil) })
return
}
if(data.missilesAvailable <= 0)
{
sound.playSoundType(vSoundType: .defenseFails)
hudControl.notify()
}
else
{
gameControl.defenseMissileShoot(vPosition: scenePoint, soundType: 0)
sound.playSoundType(vSoundType: .defenseFires)
}
}
//**************************************************************************
@objc func handlePan(recognizer: UIPanGestureRecognizer)
{
currentLocation = recognizer.location(in: gameScene)
let projectedPoint = gameScene.projectPoint(SCNVector3(0, 0, 0))
let scenePoint = gameScene.unprojectPoint(SCNVector3(currentLocation.x, currentLocation.y, CGFloat(projectedPoint.z)))
if(gameControl.isWaveComplete == true || gNodes.gameNodes.isPaused == true) { return }
switch recognizer.state
{
case UIGestureRecognizer.State.began:
gameControl.defenseMissileShoot(vPosition: scenePoint, soundType: 1)
SNDdefenseSoundCount = 0
if(data.missilesAvailable <= 0) { sound.playSoundType(vSoundType: .defenseFails); hudControl.notify() }
beginLocation.x = currentLocation.x
break
case UIGestureRecognizer.State.changed:
if(currentLocation.x > beginLocation.x + dragDistance)
{
beginLocation.x = currentLocation.x
if(data.missilesAvailable > 0) { gameControl.defenseMissileShoot(vPosition: scenePoint, soundType: 2) }
SNDdefenseSoundCount += 1
}
if(currentLocation.x < beginLocation.x - dragDistance)
{
beginLocation.x = currentLocation.x
if(data.missilesAvailable > 0) { gameControl.defenseMissileShoot(vPosition: scenePoint, soundType: 2) }
SNDdefenseSoundCount += 1
}
break
case UIGestureRecognizer.State.ended:
if(data.missilesAvailable > 0)
{
if(SNDdefenseSoundCount < 2) { sound.playSoundType(vSoundType: .defenseFires) }
else { sound.playSoundType(vSoundType: .defensePans) }
}
break
default:
break
}
用户在绘图视图上画一条线,然后我需要将这些点转换为 3d 世界,但将这些点放在一个“表面”中。为此,我将点数组映射到向量中(我将 hitTest 与 .featurePoint 结合使用),然后过滤该数组以获得另一个
func didEndDrawing(with points: [CGPoint]) {
guard let transform = sceneView.pointOfView?.transform else { return }
let cameraVectror = SCNVector3(transform.m31, transform.m32, transform.m33)
let farthestVector = points
.reduce((vector: SCNVector3(0, 0, 0), distance: CGFloat.zero)) { result, point in
guard let vector = getVector(for: point) else { return result }
let distance: CGFloat = cameraVectror.distance(to: vector)
return distance > result.distance ? (vector, distance) : result
}
.vector
}
let parentNode = SCNNode()
parentNode.position = farthestVector
如何调整坐标(我猜是 z 位置)以使所有子节点与视点的距离相同? 该应用程序的想法是在AR中徒手绘画。
更新
在 Voltan 的帮助下我解决了这个问题
points.forEach { point in
let scenePoint = sceneView.unprojectPoint(SCNVector3(point.x, point.y, CGFloat(projectedPoint.z)))
let sphere = SCNSphere(radius: 0.01)
let material = SCNMaterial()
material.diffuse.contents = UIColor.green
sphere.materials = [material]
let node = SCNNode(geometry: sphere)
node.position = scenePoint
sceneView.scene.rootNode.addChildNode(node)
}
如果我理解正确,您需要某种 tap/drag 组合 - 从 2D 世界获取点并将其转换为 3D 世界。这是导弹命令类型游戏的一些游戏代码,也许它会帮助你处理 unprojectPoint 的东西。有一些计时器未包括在内,但希望您能理解。
@objc func handleTap(recognizer: UITapGestureRecognizer)
{
if(data.gameState == .endGame)
{
endGameAnimates.stop()
let _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { _ in self.dismiss(animated: false, completion: nil) })
return
}
if(gameControl.isWaveComplete == true || gNodes.gameNodes.isPaused == true) { return }
currentLocation = recognizer.location(in: gameScene)
let projectedPoint = gameScene.projectPoint(SCNVector3(0, 0, 0))
let scenePoint = gameScene.unprojectPoint(SCNVector3(currentLocation.x, currentLocation.y, CGFloat(projectedPoint.z)))
if(data.gameState == .endGame) // Allow animations to finish, otherwise they will show up next round
{
DispatchQueue.main.async { self.endGameAnimates.stop() }
let _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { _ in self.dismiss(animated: false, completion: nil) })
return
}
if(data.missilesAvailable <= 0)
{
sound.playSoundType(vSoundType: .defenseFails)
hudControl.notify()
}
else
{
gameControl.defenseMissileShoot(vPosition: scenePoint, soundType: 0)
sound.playSoundType(vSoundType: .defenseFires)
}
}
//**************************************************************************
@objc func handlePan(recognizer: UIPanGestureRecognizer)
{
currentLocation = recognizer.location(in: gameScene)
let projectedPoint = gameScene.projectPoint(SCNVector3(0, 0, 0))
let scenePoint = gameScene.unprojectPoint(SCNVector3(currentLocation.x, currentLocation.y, CGFloat(projectedPoint.z)))
if(gameControl.isWaveComplete == true || gNodes.gameNodes.isPaused == true) { return }
switch recognizer.state
{
case UIGestureRecognizer.State.began:
gameControl.defenseMissileShoot(vPosition: scenePoint, soundType: 1)
SNDdefenseSoundCount = 0
if(data.missilesAvailable <= 0) { sound.playSoundType(vSoundType: .defenseFails); hudControl.notify() }
beginLocation.x = currentLocation.x
break
case UIGestureRecognizer.State.changed:
if(currentLocation.x > beginLocation.x + dragDistance)
{
beginLocation.x = currentLocation.x
if(data.missilesAvailable > 0) { gameControl.defenseMissileShoot(vPosition: scenePoint, soundType: 2) }
SNDdefenseSoundCount += 1
}
if(currentLocation.x < beginLocation.x - dragDistance)
{
beginLocation.x = currentLocation.x
if(data.missilesAvailable > 0) { gameControl.defenseMissileShoot(vPosition: scenePoint, soundType: 2) }
SNDdefenseSoundCount += 1
}
break
case UIGestureRecognizer.State.ended:
if(data.missilesAvailable > 0)
{
if(SNDdefenseSoundCount < 2) { sound.playSoundType(vSoundType: .defenseFires) }
else { sound.playSoundType(vSoundType: .defensePans) }
}
break
default:
break
}