是可能的有一个动画背景纹理在SceneKit?



我的意思是动画场景背景(scene.background.contents)。不是放置在对象上的纹理。

我目前有一个。exr文件作为我的项目背景,但我想有一个动画背景在循环中运行。我的第一个想法是创建一组exr图像,将其转换为动画,然后使用该动画作为材料的漫反射纹理。但是,它不工作。

我只创建了3个起始帧来测试(background_0, 1和2)
但是,当应用程序加载时,我可以在它变黑之前看到半秒的背景

我做错什么了吗?或者也许我处理这个问题的方式是错误的,有一个更简单的方法来达到这种效果?

这是我目前为背景的代码,任何帮助是非常感激的:

// load the image sequences: .exr
var imageArray: [UIImage] = []
for i in 0...2 { // afor now 3 frames long, 0, 1 and 2
if let image = UIImage(named: "background_(i).exr") { // we assume their names: "background_0.exr", "background_1.exr", etc.
imageArray.append(image)
print(image)
}
}
print(imageArray)
// Create texture animation
let bg_animation = CAKeyframeAnimation(keyPath: "contents")
bg_animation.calculationMode = .discrete
bg_animation.duration = 5 // animation's duration
bg_animation.values = imageArray.map { $0.cgImage as Any }
bg_animation.repeatCount = .infinity // animation repeats forever.
//bg_animation.autoreverses = true // the animation reverses
print("hi, this is the bg animation: ")
print(bg_animation)
// Create the animation using the array
backgroundAnimation = SCNMaterialProperty(contents: bg_animation)
print("hi, this is the SCNMaterial property animation: ")
print(backgroundAnimation)
// Create the material and asign the animation as its content
let backgroundMaterial = SCNMaterial()
backgroundMaterial.setValue(backgroundAnimation, forKey: "contents")
backgroundMaterial.locksAmbientWithDiffuse = true
print("This is background Material")
print(backgroundMaterial)
print(backgroundMaterial.animationKeys)
print(backgroundMaterial.diffuse)
// Assign the material to the scene background content
scene.background.contents = backgroundMaterial
print("Asign material as background")
print(scene.background.contents)

我尝试:
创建一个图像数组,将其转换为动画,该动画使用它作为纹理并将其分配为背景内容。
每一帧都是独立的,而不是像一个数组。

尝试以下方法之一(UIKit vs SwiftUI):

UIKit版本基于OpenEXR图像序列创建动画SCNScene背景的最简单的解决方案是实现renderer(_:updateAtTime:)委托方法。

import UIKit
import SceneKit
extension ViewController: SCNSceneRendererDelegate {

func renderer(_ renderer: SCNSceneRenderer,
updateAtTime time: TimeInterval) {
scene.background.contents = imageArray[Int(time / 5) % 3]
}
}

class ViewController: UIViewController {

@IBOutlet var sceneView: SCNView!
var imageArray: [UIImage] = []
let scene = SCNScene()
override func viewDidLoad() {
super.viewDidLoad()

sceneView.delegate = self
sceneView.scene = scene
sceneView.isPlaying = true
sceneView.allowsCameraControl = true

for frame in 0...2 {
DispatchQueue.main.async { [self] in
if let image = UIImage(named: "bg_(frame).exr") {
self.imageArray.append(image)
}
}
}
}
}

SwiftUI版本SwiftUI版本将额外要求你实现一个协调器。

import SwiftUI
import SceneKit
struct ContentView : View {
var body: some View {
SceneKitView().ignoresSafeArea()
}
}

struct SceneKitView : UIViewRepresentable {        
@State var imageArray: [UIImage] = []
let sceneView = SCNView(frame: .zero)
let scene = SCNScene()

func makeCoordinator() -> Coordinator { Coordinator(self) }

final class Coordinator: NSObject, SCNSceneRendererDelegate {
var control: SceneKitView
init(_ control: SceneKitView) { self.control = control }

func renderer(_ renderer: SCNSceneRenderer, 
updateAtTime time: TimeInterval) {
control.scene.background.contents = 
control.imageArray[Int(time / 5) % 3]
}
}
func updateUIView(_ view: SCNView, context: Context) {
for frame in 0...2 {
DispatchQueue.main.async {
if let image = UIImage(named: "bg_(frame).exr") {
imageArray.append(image)
}
}
}
}
func makeUIView(context: Context) -> SCNView {
sceneView.delegate = context.coordinator
sceneView.scene = scene
sceneView.isPlaying = true
sceneView.allowsCameraControl = true
return sceneView
}
}

最新更新