我有一个SCNNode,在其中显示一个曲面-在此曲面上我想显示一条路径。此路径是一个SCNNode本身,已添加到表面SCNNode。该SCNNode(路径)由多个SCNNode组成,它们是整个路径的一小部分-因此我将它们全部添加到路径SCNNode中。
工作流程如下:
问题:我不仅要添加它,还想从头到尾(从第一个块到最后一个块)对其进行动画处理,但是我该怎么做?
感谢您的帮助!
答案 0 :(得分:2)
由于您尚未提供任何代码(请下次提供),我将提供一种解决方案,该解决方案应为您指明正确的方向。
让我们首先创建一个PathItem Class
,我们将使用它来创建完整的路径,例如其中一行:
/// Path Item Node
class PathItem: SCNNode{
/// Creates A PathItem
///
/// - Parameters:
/// - size: CGFloat (Defaults To 20cm)
/// - texture: UIColour
/// - position: SCNVector3
init(size: CGFloat = 0.2, texture: UIColor, position: SCNVector3){
super.init()
//1. Create Our Path Geometry
let pathGeometry = SCNPlane(width: size, height: size)
//2. Assign The Colour To The Geoemtry
pathGeometry.firstMaterial?.diffuse.contents = texture
//3. Assign The Geometry, Position The Node & Rotate The Node So It Is Horizontal
self.geometry = pathGeometry
self.position = position
self.eulerAngles.x = GLKMathDegreesToRadians(-90)
}
required init?(coder aDecoder: NSCoder) { fatalError("Path Item Coder Has Not Been Implemented") }
}
现在,让我们创建一个func
,它将创建一行PathItem
(路径)。
首先像这样创建一个全局变量,该变量引用每个PathItem
的大小:
let pathItemSize: CGFloat = 0.2
然后,我们创建函数,以替换每个PathItem
的颜色,并为它们提供唯一的name
或索引,我们将在以后的动画中使用它:
/// Create A Path With A Number Of Elements
///
/// - Parameter numberOfElements: Int
/// - Returns: PATH (SCNNode)
func createdPathOfSize(_ numberOfElements: Int) {
var pathColour: UIColor!
//2. Loop Through The Number Of Path Elements We Want & Place Them In A Line
for pathIndex in 0 ..< numberOfElements{
//a. Position Each Peice Next To Each Other Based On The Index
let pathPosition = SCNVector3(0, -0.2, -pathItemSize * CGFloat(pathIndex+1))
//b. Alternate The Colour Of Our Path
if pathIndex % 2 == 0 { pathColour = UIColor.white } else { pathColour = UIColor.black }
//c. Create Our Path Item With A Unique Index We Can Use For Animating
let pathItem = PathItem(texture: pathColour, position: pathPosition)
pathItem.name = String(pathIndex)
//d. Set It To Hidden Initially
pathItem.isHidden = true
//e. Add It To Our Scene
self.augmentedRealityView.scene.rootNode.addChildNode(pathItem)
}
}
要生成Path
,我们现在可以执行以下操作:
override func viewDidLoad() {
super.viewDidLoad()
//1. Set Up Our ARSession
augmentedRealityView.session = augmentedRealitySession
sessionConfiguration.planeDetection = .horizontal
augmentedRealityView.debugOptions = .showFeaturePoints
augmentedRealitySession.run(sessionConfiguration, options: [.resetTracking, .removeExistingAnchors])
//2. Create A Path Of 10 PathItems
createdPathOfSize(10)
}
在此,我有以下Global variables
:
@IBOutlet var augmentedRealityView: ARSCNView!
let augmentedRealitySession = ARSession()
let sessionConfiguration = ARWorldTrackingConfiguration()
现在我们已经生成了路径,需要对其进行动画处理!
为了提供一些多样性,让我们创建一个Enum
,我们可以使用它来创建不同的PathAnimations:
/// Path Item Animation
///
/// - UnHide: UnHides The Path Item
/// - FadeIn: Fades The Path Item In
/// - FlipIn: Flips The Path Item In
enum AnimationType{
case UnHide
case FadeIn
case FlipIn
}
否,因为我们将要制作一些动画,所以我们需要再创建2个全局变量,这些变量将用于在Timer上运行动画并跟踪我们的工作位置:
var pathAnimationTimer: Timer?
var time: Int = 0
现在让我们创建动画功能:
/// Animates The Laying Of The Path
///
/// - Parameters:
/// - numberOfElements: Int
/// - animation: AnimationType
func animatePathElements(_ numberOfElements: Int, withAnimation animation: AnimationType ){
//1. If We Are Flipping The PathItems In We Need To 1st Unhide Them All & Rotate Them To A Vertical Postions
if animation == .FlipIn {
let pathItems = self.augmentedRealityView.scene.rootNode.childNodes
pathItems.forEach({ (pathItemToAnimate) in
pathItemToAnimate.isHidden = false
pathItemToAnimate.eulerAngles.x = GLKMathDegreesToRadians(0)
})
}
//2. Create Our Time Which Will Run Every .25 Seconds
pathAnimationTimer = Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { timer in
//3. Whilst Our Time Doesnt Equal The Number Of Path Items Then Continue Our Animation
if self.time != numberOfElements{
//a. Get The Current Node Remembering Each One Has A Unique Name (Index
guard let pathItemToAnimate = self.augmentedRealityView.scene.rootNode.childNode(withName: "\(self.time)", recursively: false) else { return }
//b. Run The Desired Animation Sequence
switch animation{
case .UnHide:
//Simply Unhide Each PathItem
pathItemToAnimate.isHidden = false
case .FadeIn:
//1. Unhide The Item & Sets It's Opacity To 0 Rendering It Invisible
pathItemToAnimate.isHidden = false
pathItemToAnimate.opacity = 0
//2. Create An SCNAction To Fade In Our PathItem
let fadeInAction = SCNAction.fadeOpacity(to: 1, duration: 0.25)
pathItemToAnimate.runAction(fadeInAction)
case .FlipIn:
//Simply Rotate The Path Item Horizontally
pathItemToAnimate.eulerAngles.x = GLKMathDegreesToRadians(-90)
}
self.time += 1
}else{
//4. Our Animation Has Finished So Invalidate The Timer
self.pathAnimationTimer?.invalidate()
self.time = 0
}
}
}
然后我们需要将其添加到createPathOfSize函数的末尾,如下所示:
/// Create A Path With A Number Of Elements Which Can Be Animated
///
/// - Parameter numberOfElements: Int
/// - Returns: PATH (SCNNode)
func createdPathOfSize(_ numberOfElements: Int) {
var pathColour: UIColor!
//1. Loop Through The Number Of Path Elements We Want & Place Them In A Line
for pathIndex in 0 ..< numberOfElements{
//a. Position Each Peice Next To Each Other Based On The Index
let pathPosition = SCNVector3(0, -0.2, -pathItemSize * CGFloat(pathIndex+1))
//b. Alternate The Colour Of Our Path
if pathIndex % 2 == 0 { pathColour = UIColor.white } else { pathColour = UIColor.black }
//b. Create Our Path Item With A Unique Index We Can Use For Animating
let pathItem = PathItem(texture: pathColour, position: pathPosition)
pathItem.name = String(pathIndex)
//c. Set It To Hidden Initially
pathItem.isHidden = true
//d. Add It To Our Scene
self.augmentedRealityView.scene.rootNode.addChildNode(pathItem)
}
//2. Animate The Path
animatePathElements(10, withAnimation: .FlipIn)
}
这是完整的示例:
import UIKit
import ARKit
//----------------------
//MARK: - Path Animation
//----------------------
/// Path Item Animation
///
/// - Show: UnHides The Path Item
/// - FadeIn: Fades The Path Item In
enum AnimationType{
case UnHide
case FadeIn
case FlipIn
}
//-----------------
//MARK: - Path Item
//-----------------
/// Path Item Node
class PathItem: SCNNode{
/// Creates A PathItem
///
/// - Parameters:
/// - size: CGFloat (Defaults To 20cm)
/// - texture: UIColour
/// - position: SCNVector3
init(size: CGFloat = 0.2, texture: UIColor, position: SCNVector3){
super.init()
//1. Create Our Path Geometry
let pathGeometry = SCNPlane(width: size, height: size)
//2. Assign The Colour To The Geoemtry
pathGeometry.firstMaterial?.diffuse.contents = texture
//3. Assign The Geometry, Position The Node & Rotate The Node So It Is Horizontal
self.geometry = pathGeometry
self.position = position
self.eulerAngles.x = GLKMathDegreesToRadians(-90)
}
required init?(coder aDecoder: NSCoder) { fatalError("Path Item Coder Has Not Been Implemented") }
}
class ViewController: UIViewController {
typealias PATH = SCNNode
@IBOutlet var augmentedRealityView: ARSCNView!
let augmentedRealitySession = ARSession()
let sessionConfiguration = ARWorldTrackingConfiguration()
var pathPlaced = false
let pathItemSize: CGFloat = 0.2
var pathAnimationTimer: Timer?
var time: Int = 0
//----------------------
//MARK: - View LifeCycle
//----------------------
override func viewDidLoad() {
super.viewDidLoad()
//1. Set Up Our ARSession
augmentedRealityView.session = augmentedRealitySession
sessionConfiguration.planeDetection = .horizontal
augmentedRealityView.debugOptions = .showFeaturePoints
augmentedRealitySession.run(sessionConfiguration, options: [.resetTracking, .removeExistingAnchors])
//2. Create A Path Of 10 Path Items
createdPathOfSize(10)
}
//---------------------------------
//MARK: - Path Creation & Animation
//---------------------------------
/// Animates The Laying Of The Path
///
/// - Parameters:
/// - numberOfElements: Int
/// - animation: AnimationType
func animatePathElements(_ numberOfElements: Int, withAnimation animation: AnimationType ){
if animation == .FlipIn {
let pathItems = self.augmentedRealityView.scene.rootNode.childNodes
pathItems.forEach({ (pathItemToAnimate) in
pathItemToAnimate.isHidden = false
pathItemToAnimate.eulerAngles.x = GLKMathDegreesToRadians(0)
})
}
pathAnimationTimer = Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { timer in
//1. Whilst Our Time Doesnt Equal The Number Of Path Items Then Continue Our Animation
if self.time != numberOfElements{
guard let pathItemToAnimate = self.augmentedRealityView.scene.rootNode.childNode(withName: "\(self.time)", recursively: false) else { return }
//2. Run The Desired Animation Sequence
switch animation{
case .UnHide:
pathItemToAnimate.isHidden = false
case .FadeIn:
pathItemToAnimate.isHidden = false
pathItemToAnimate.opacity = 0
let fadeInAction = SCNAction.fadeOpacity(to: 1, duration: 0.3)
pathItemToAnimate.runAction(fadeInAction)
case .FlipIn:
pathItemToAnimate.eulerAngles.x = GLKMathDegreesToRadians(-90)
}
self.time += 1
}else{
self.pathAnimationTimer?.invalidate()
self.time = 0
}
}
}
/// Create A Path With A Number Of Elements Which Can Be Animated
///
/// - Parameter numberOfElements: Int
/// - Returns: PATH (SCNNode)
func createdPathOfSize(_ numberOfElements: Int) {
var pathColour: UIColor!
//1. Loop Through The Number Of Path Elements We Want & Place Them In A Line
for pathIndex in 0 ..< numberOfElements{
//a. Position Each Peice Next To Each Other Based On The Index
let pathPosition = SCNVector3(0, -0.2, -pathItemSize * CGFloat(pathIndex+1))
//b. Alternate The Colour Of Our Path
if pathIndex % 2 == 0 { pathColour = UIColor.white } else { pathColour = UIColor.black }
//b. Create Our Path Item With A Unique Index We Can Use For Animating
let pathItem = PathItem(texture: pathColour, position: pathPosition)
pathItem.name = String(pathIndex)
//c. Set It To Hidden Initially
pathItem.isHidden = true
//d. Add It To Our Scene
self.augmentedRealityView.scene.rootNode.addChildNode(pathItem)
}
//2. Animate The Path
animatePathElements(10, withAnimation: .FlipIn)
}
}
这足以将您指向正确的方向^ __________ ^。