我有一个SCNCamera的场景设置,围绕一个对象旋转.
限制相机在物体周围可以实现的旋转范围的最佳方法是什么?
示例:我不是可以围绕整个球体旋转,而是如何限制旋转到单个半球?
我的第一次尝试是查看.allowsCameraControl是否有任何夹子.找不到任何东西.
然后我尝试调整c#Unity:鼠标轨道脚本,没有运气.
关于如何接近或解决这个问题的一些指示很好.
Boilersplate Arcball得益于这个答案.
var lastWidthRatio: Float = 0
var lastHeightRatio: Float = 0
let camera = SCNCamera()
let cameraNode = SCNNode()
let cameraOrbit = SCNNode()
override func viewDidLoad() {
super.viewDidLoad()
// create a new scene
let scene = SCNScene(named: "art.scnassets/ship.scn")!
// create and add a camera to the scene
camera.usesOrthographicProjection = true
camera.orthographicScale = 9
camera.zNear = 0
camera.zFar = 100
cameraNode.position = SCNVector3(x: 0, y: 0, z: 50)
cameraNode.camera = camera
cameraOrbit.addChildNode(cameraNode)
scene.rootNode.addChildNode(cameraOrbit)
// retrieve the ship node
let ship = scene.rootNode.childNodeWithName("ship", recursively: true)!
// retrieve the SCNView
let scnView = self.view as! SCNView
// set the scene to the view
scnView.scene = scene
// add a tap gesture recognizer
let gesture = UIPanGestureRecognizer(target: self, action: "panDetected:");
scnView.addGestureRecognizer(gesture);
}
func panDetected(sender: UIPanGestureRecognizer) {
let translation = sender.translationInView(sender.view!)
let widthRatio = Float(translation.x) / Float(sender.view!.frame.size.width) + lastWidthRatio
let heightRatio = Float(translation.y) / Float(sender.view!.frame.size.height) + lastHeightRatio
self.cameraOrbit.eulerAngles.y = Float(-2 * M_PI) * widthRatio
self.cameraOrbit.eulerAngles.x = Float(-M_PI) * heightRatio
print(Float(-2 * M_PI) * widthRatio)
if (sender.state == .Ended) {
lastWidthRatio = widthRatio % 1
lastHeightRatio = heightRatio % 1
}
}
Run Code Online (Sandbox Code Playgroud)
也许这对读者有用.
class GameViewController: UIViewController {
var cameraOrbit = SCNNode()
let cameraNode = SCNNode()
let camera = SCNCamera()
//HANDLE PAN CAMERA
var lastWidthRatio: Float = 0
var lastHeightRatio: Float = 0.2
var WidthRatio: Float = 0
var HeightRatio: Float = 0.2
var fingersNeededToPan = 1
var maxWidthRatioRight: Float = 0.2
var maxWidthRatioLeft: Float = -0.2
var maxHeightRatioXDown: Float = 0.02
var maxHeightRatioXUp: Float = 0.4
//HANDLE PINCH CAMERA
var pinchAttenuation = 20.0 //1.0: very fast ---- 100.0 very slow
var lastFingersNumber = 0
override func viewDidLoad() {
super.viewDidLoad()
// create a new scene
let scene = SCNScene(named: "art.scnassets/ship.scn")!
// create and add a light to the scene
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = SCNLightTypeOmni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = UIColor.darkGrayColor()
scene.rootNode.addChildNode(ambientLightNode)
//Create a camera like Rickster said
camera.usesOrthographicProjection = true
camera.orthographicScale = 9
camera.zNear = 1
camera.zFar = 100
cameraNode.position = SCNVector3(x: 0, y: 0, z: 50)
cameraNode.camera = camera
cameraOrbit = SCNNode()
cameraOrbit.addChildNode(cameraNode)
scene.rootNode.addChildNode(cameraOrbit)
//initial camera setup
self.cameraOrbit.eulerAngles.y = Float(-2 * M_PI) * lastWidthRatio
self.cameraOrbit.eulerAngles.x = Float(-M_PI) * lastHeightRatio
// retrieve the SCNView
let scnView = self.view as! SCNView
// set the scene to the view
scnView.scene = scene
//allows the user to manipulate the camera
scnView.allowsCameraControl = false //not needed
// add a tap gesture recognizer
let panGesture = UIPanGestureRecognizer(target: self, action: "handlePan:")
scnView.addGestureRecognizer(panGesture)
// add a pinch gesture recognizer
let pinchGesture = UIPinchGestureRecognizer(target: self, action: "handlePinch:")
scnView.addGestureRecognizer(pinchGesture)
}
func handlePan(gestureRecognize: UIPanGestureRecognizer) {
let numberOfTouches = gestureRecognize.numberOfTouches()
let translation = gestureRecognize.translationInView(gestureRecognize.view!)
if (numberOfTouches==fingersNeededToPan) {
widthRatio = Float(translation.x) / Float(gestureRecognize.view!.frame.size.width) + lastWidthRatio
heightRatio = Float(translation.y) / Float(gestureRecognize.view!.frame.size.height) + lastHeightRatio
// HEIGHT constraints
if (heightRatio >= maxHeightRatioXUp ) {
heightRatio = maxHeightRatioXUp
}
if (heightRatio <= maxHeightRatioXDown ) {
heightRatio = maxHeightRatioXDown
}
// WIDTH constraints
if(widthRatio >= maxWidthRatioRight) {
widthRatio = maxWidthRatioRight
}
if(widthRatio <= maxWidthRatioLeft) {
widthRatio = maxWidthRatioLeft
}
self.cameraOrbit.eulerAngles.y = Float(-2 * M_PI) * widthRatio
self.cameraOrbit.eulerAngles.x = Float(-M_PI) * heightRatio
print("Height: \(round(heightRatio*100))")
print("Width: \(round(widthRatio*100))")
//for final check on fingers number
lastFingersNumber = fingersNeededToPan
}
lastFingersNumber = (numberOfTouches>0 ? numberOfTouches : lastFingersNumber)
if (gestureRecognize.state == .Ended && lastFingersNumber==fingersNeededToPan) {
lastWidthRatio = widthRatio
lastHeightRatio = heightRatio
print("Pan with \(lastFingersNumber) finger\(lastFingersNumber>1 ? "s" : "")")
}
}
func handlePinch(gestureRecognize: UIPinchGestureRecognizer) {
let pinchVelocity = Double.init(gestureRecognize.velocity)
//print("PinchVelocity \(pinchVelocity)")
camera.orthographicScale -= (pinchVelocity/pinchAttenuation)
if camera.orthographicScale <= 0.5 {
camera.orthographicScale = 0.5
}
if camera.orthographicScale >= 10.0 {
camera.orthographicScale = 10.0
}
}
Run Code Online (Sandbox Code Playgroud)
看起来您已经快到了,只需使用您引用的答案中的@Rickster 代码即可。
\n\n您可以进行的更改如下:
\n\nself.cameraOrbit.eulerAngles.y = Float(-2 * M_PI) * widthRatio\nself.cameraOrbit.eulerAngles.x = Float(-M_PI) * heightRatio\nRun Code Online (Sandbox Code Playgroud)\n\n这隐式允许俯仰和偏航覆盖整个球体。这就是你可以进行限制的地方。例如,\而不是允许音调 (eulerAngles.x您可以不让音高 ( ) 从 0\n 变化到 -\xcf\x80,而是这样做
self.cameraOrbit.eulerAngles.x = Float(-M_PI_2) + Float(-M_PI_2) * heightRatio\nRun Code Online (Sandbox Code Playgroud)\n\n在 -\xcf\x80/2 和 -\xcf\x80 之间平滑变化,使用全屏\n垂直滚动来覆盖该范围。或者您可以在这两行中放置\n硬性最小/最大限制/检查,以限制\n地球的特定区域。
\n\n(编辑以解决惯性评论)
\n\n对于旋转阻尼或惯性,我会使用内置的 SceneKit 物理来实现它,并且可能将相机放在不可见(无几何体)的 SCNNode 上。该相机节点成为一个万向节,类似于该项目中采用的方法:完全用 RubyMotion 和 SceneKit 创建的交互式七英尺地球仪。
\n\n然后,虚拟万向节会得到一个SCNPhysicsBody(您补充一下,默认情况下它不带有一个)和一些damping. 或者也许您将物理原理放在中心物体上,并给该物体一些angularDamping。
| 归档时间: |
|
| 查看次数: |
2372 次 |
| 最近记录: |