gpt4 book ai didi

ios - SceneKit - 使用基于方向的平移手势旋转 SCNNode

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

我正在编写我的第一个 scenekit 项目,我正在尝试使用平移手势在我的场景中旋转一个简单的对象(对象是一个从 .dae 文件导入的简单 L 立方体形状,枢轴点设置正确)。

我浏览了多个 SO 解决方案和教程,并整理了一些代码,但轮换无法正常工作。如果我反复尝试沿一个轴旋转对象,它会正常工作,但是当我尝试另一个方向时,在平移开始时对象会重置到它的初始位置。有时,旋转也会随机出现或跳跃。我不确定我是否使用了正确的方法,请指教。这是我的代码:

func handlePan(sender: UIPanGestureRecognizer){

// determine pan direction
let velocity: CGPoint = sender.velocity(in: sender.view!)
if self.panDirection == nil {
if velocity.x > 0 && velocity.x > abs(velocity.y) { self.panDirection = "right" }
if velocity.x < 0 && abs(velocity.x) > abs(velocity.y) { self.panDirection = "left" }
if velocity.y < 0 && abs(velocity.y) > abs(velocity.x) { self.panDirection = "up" }
if velocity.y > 0 && velocity.y > abs(velocity.x) { self.panDirection = "down" }
}

// do rotation only on selected SCNNode
if self.selectedBrickNode != nil {

// start of pan gesture
if sender.state == UIGestureRecognizerState.began{
// remember initial rotation angle
self.initRot = self.selectedBrickNode.rotation.w
}

let translation = sender.translation(in: sender.view!)
let pan_x = Float(translation.x)
let pan_y = Float(-translation.y)

// add rotation angle to initial rotation
var anglePan = self.initRot + (Float)(sqrt(pow(pan_x,2)+pow(pan_y,2)))*(Float)(Double.pi)/180.0
var rotVector = SCNVector4()

// if left/right, rotate on Y axis
rotVector.x = (self.panDirection == "left" || self.panDirection == "right" ) ? 0 : -pan_y
// if up/down, rotate on X axis
rotVector.y = (self.panDirection == "up" || self.panDirection == "down" ) ? 0 : pan_x
rotVector.z = 0
rotVector.w = anglePan

// set SCNNode's rotation
self.selectedBrickNode.rotation = rotVector

// end of pan gesture
if(sender.state == UIGestureRecognizerState.ended) {

// reset initial rotation
self.initRot = 0.0

// calculate degrees so we can snap to 90deg increments
var angle = anglePan * (Float) (180.0 / Double.pi)

// snap to 90deg increments
let diff = angle.truncatingRemainder(dividingBy: 90.0)
if diff <= 45 {
angle = angle - diff
}else{
angle = (angle - diff ) + 90
}

// set new rotation to snap
rotVector.w = angle * (Float)(Double.pi)/180.0
self.selectedBrickNode.rotation = rotVector
self.selectedBrickNode = nil
}
}


}

最佳答案

经过大量的研究和几个小时的摸索,我终于找到了一个可行的解决方案。

我的工作代码:

func handlePan(sender: UIPanGestureRecognizer){

// get pan direction
let velocity: CGPoint = sender.velocity(in: sender.view!)
if self.panDirection == nil {
self.panDirection = GameHelper.getPanDirection(velocity: velocity)
}

// if selected brick
if self.selectedBrickNode != nil {

if sender.state == UIGestureRecognizerState.began{
lastAngle = 0.0 // reset last angle
}

let translation = sender.translation(in: sender.view!)
let anglePan = (self.panDirection == "horizontal") ? GameHelper.deg2rad(deg: Float(translation.x)) : GameHelper.deg2rad(deg: Float(translation.y))

let x:Float = (self.panDirection == "vertical" ) ? 1 : 0.0
let y:Float = (self.panDirection == "horizontal" ) ? 1 : 0.0

// calculate the angle change from last call
let fraction = anglePan - lastAngle
lastAngle = anglePan

// perform rotation by difference to last angle
selectedBrickNode.transform = SCNMatrix4Mult(selectedBrickNode.transform,SCNMatrix4MakeRotation(fraction, x, y, 0.0))


if(sender.state == UIGestureRecognizerState.ended) {

// calculate angle to snap to 90 degree increments
let finalRotation = GameHelper.rad2deg(rad:anglePan)
let diff = finalRotation.truncatingRemainder(dividingBy: 90.0)
var finalDiff = Float(0.0)

switch diff {
case 45..<90 :
finalDiff = 90 - diff
case 0..<45 :
finalDiff = -diff
case -45..<0 :
finalDiff = abs(diff)
case -90 ..< -45 :
finalDiff = -90 - diff
default:
print("do nothing")
}

// final transform to apply snap to closest 90deg increment
let snapAngle = GameHelper.deg2rad(deg: finalDiff)
selectedBrickNode.transform = SCNMatrix4Mult(selectedBrickNode.transform, SCNMatrix4MakeRotation(snapAngle, x, y, 0.0))

// remove highlight from node and deselect
self.selectedBrickNode?.geometry?.materials = [hlp.defaultMaterial]
self.selectedBrickNode = nil
}
}


}

和GameHelper.swift

class GameHelper {

static func rad2deg( rad:Float ) -> Float {
return rad * (Float) (180.0 / Double.pi)
}

static func deg2rad( deg:Float ) -> Float{
return deg * (Float)(Double.pi / 180)
}

static func getPanDirection(velocity: CGPoint) -> String {
var panDirection:String = ""
if ( velocity.x > 0 && velocity.x > abs(velocity.y) || velocity.x < 0 && abs(velocity.x) > abs(velocity.y) ){
panDirection = "horizontal"
}

if ( velocity.y < 0 && abs(velocity.y) > abs(velocity.x) || velocity.y > 0 && velocity.y > abs(velocity.x)) {
panDirection = "vertical"
}


return panDirection
}

}

关于ios - SceneKit - 使用基于方向的平移手势旋转 SCNNode,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46550595/

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