英文:
How to render spheres in SceneKit at user's tap position?
问题
我正在使用Swift和SceneKit开发iOS应用程序。当用户点击屏幕时,我希望在SceneKit中的用户点击位置渲染一个点。我该如何实现这个功能?
我正在使用unprojectPoint()方法,但是我的对象没有渲染在预期的位置。
我有一个SceneView,摄像机设置如下:
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
然后,我通过以下方式在点击位置渲染点:
func handleTap(_ gestureRecognize: UIGestureRecognizer) {
// 获取SCNView
let scnView = self.view as! SCNView
// 创建点
let geo = SCNSphere(radius: CGFloat(0.1))
geo.firstMaterial?.diffuse.contents = UIColor.red
let dotNode = SCNNode(geometry: geo)
let p = gestureRecognize.location(in: scnView)
let uP = scnView.unprojectPoint(SCNVector3(p.x, p.y, 5))
// 在这里 - 如何设置点的位置?
dotNode.position = SCNVector3(uP.x, uP.y, 5)
scnView.scene?.rootNode.addChildNode(dotNode)
}
这是我的Github仓库链接:https://github.com/rudyhuynh/SceneKitExample
英文:
I am working on an iOS app with Swift and SceneKit. When user taps on screen, I want to render a dot in SceneKit at the location that user just tapped. How can I do that?
I am using unprojectPoint() method but my object is not rendered at expected location.
I am having a SceneView, with the camera like this:
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
And then I render the dot at tap position like this:
func handleTap(_ gestureRecognize: UIGestureRecognizer) {
// retrieve the SCNView
let scnView = self.view as! SCNView
// create dot
let geo = SCNSphere(radius: CGFloat(0.1))
geo.firstMaterial?.diffuse.contents = UIColor.red
let dotNode = SCNNode(geometry: geo)
let p = gestureRecognize.location(in: scnView)
let uP = scnView.unprojectPoint(SCNVector3(p.x, p.y, 5))
// HERE - how to set position for the dot ?
dotNode.position = SCNVector3(uP.x, uP.y, 5)
scnView.scene?.rootNode.addChildNode(dotNode)
}
Here is my Github repo: https://github.com/rudyhuynh/SceneKitExample
答案1
得分: 1
反投影一个点
为了在预期位置渲染点节点,请使用以下方法。不要忘记你正在使用透视投影查看场景。对具有 Z 坐标为 0.0
的点进行反投影会返回位于近裁剪平面上的点。对具有 Z 坐标为 1.0
的点进行反投影会返回位于远裁剪平面
上的点。
import SceneKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let sceneView = self.view as! SCNView
sceneView.scene = SCNScene()
sceneView.backgroundColor = UIColor.black
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.simdPosition = simd_float3(0, 0, 1)
sceneView.scene?.rootNode.addChildNode(cameraNode)
let tapGesture = UITapGestureRecognizer(target: self,
action: #selector(tap))
sceneView.addGestureRecognizer(tapGesture)
}
@objc func tap(_ gestureRecognizer: UITapGestureRecognizer) {
let scnView = self.view as! SCNView
let geo = SCNSphere(radius: 0.01)
geo.firstMaterial?.diffuse.contents = UIColor.white
let dotNode = SCNNode(geometry: geo)
let point = gestureRecognizer.location(in: scnView)
let unprojected = scnView.unprojectPoint(.init(point.x, point.y, 0))
dotNode.position = SCNVector3(unprojected.x, unprojected.y, -0.01)
scnView.scene?.rootNode.addChildNode(dotNode)
}
}
要在正交投影下运行相机,请使用:
cameraNode.camera?.usesOrthographicProjection = true
英文:
Unprojecting a Point
To render dot nodes at expected position, use the following approach. Don't forget that you are looking at the scene in perspective projection. Unprojecting a point whose Z-coordinate is 0.0
returns a point on the near clipping plane. Unprojecting a point whose Z-coordinate is 1.0
returns a point on the far clipping plane
.
import SceneKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let sceneView = self.view as! SCNView
sceneView.scene = SCNScene()
sceneView.backgroundColor = UIColor.black
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.simdPosition = simd_float3(0, 0, 1)
sceneView.scene?.rootNode.addChildNode(cameraNode)
let tapGesture = UITapGestureRecognizer(target: self,
action: #selector(tap))
sceneView.addGestureRecognizer(tapGesture)
}
@objc func tap(_ gestureRecognizer: UITapGestureRecognizer) {
let scnView = self.view as! SCNView
let geo = SCNSphere(radius: 0.01)
geo.firstMaterial?.diffuse.contents = UIColor.white
let dotNode = SCNNode(geometry: geo)
let point = gestureRecognizer.location(in: scnView)
let unprojected = scnView.unprojectPoint(.init(point.x, point.y, 0))
dotNode.position = SCNVector3(unprojected.x, unprojected.y, -0.01)
scnView.scene?.rootNode.addChildNode(dotNode)
}
}
To run a camera in orthographic projection, use:
cameraNode.camera?.usesOrthographicProjection = true
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论