ios - 在 SceneKit (SwiftUI) 中初始化场景变化的材质
问题描述
我在我的 SwiftUI 应用程序中使用 SceneKit 来显示从 Blender 导出的.scn
文件转换而来的一些文件。.dae
SceneKit 正在使用UIViewRepresentable
.
我正在展示一步一步的指导指南,每个步骤都包含一些文本和动画。每个动画都是它自己的.scn
文件,我正在根据当前步骤交换场景文件。
我的问题是我需要在交换场景时对材质进行一些初始化,但只有updateUIView
在这种情况发生时才会被调用,而且我不想在这里做这项工作,因为每次动画暂停时都会调用它等。
每次更换场景时,我都想做一次这项工作,但我正在努力用我当前的实现找到解决方案。
我在想我处理这个场景交换的方式是不正确的,但我想知道是否有人能指出我正确的方向。
谢谢!
请参阅下面的完整代码:
struct MaintenanceFlowDetailView: View {
var maintenanceFlow: MaintenanceFlow
@State private var currentStepIndex = 0
@State private var pauseAnimation = false
func stepBackwards() {
currentStepIndex -= 1
pauseAnimation = false
}
func stepForwards() {
currentStepIndex += 1
pauseAnimation = false
}
func togglePauseAnimation() {
pauseAnimation = !pauseAnimation
}
var body: some View {
NavigationView{
VStack(alignment: .leading, spacing: 12){
SceneKitView(sceneFilePath: maintenanceFlow.steps[currentStepIndex].scenePath, pauseAnimation: $pauseAnimation)
.frame(height: 300)
Text(maintenanceFlow.steps[currentStepIndex].text)
Spacer()
HStack{
if currentStepIndex > 0 {
Button(action: stepBackwards) {
Text("Back")
}
}
Spacer()
Button(action: togglePauseAnimation) {
Text(pauseAnimation ? "Play" : "Pause")
}
Spacer()
if currentStepIndex < maintenanceFlow.steps.count - 1 {
Button(action: stepForwards) {
Text("Next")
}
}
}
}.padding()
.navigationBarTitle(Text(maintenanceFlow.name))
}
}
}
struct SceneKitView : UIViewRepresentable {
var sceneFilePath: String
@Binding var pauseAnimation: Bool
func makeUIView(context: Context) -> SCNView {
print("calling CREATE view")
// I NEED TO INITIALISE MATERIALS ETC JUST ONCE HERE...
let scnView = SCNView()
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
print("calling UPDATE view")
// BUT THE SCENE IS REPLACED HERE :(
let scene = SCNScene(named: sceneFilePath)!
scene.isPaused = pauseAnimation
scnView.scene = scene
scnView.showsStatistics = true
}
}
解决方案
使用以下内容:
struct SceneKitView : UIViewRepresentable {
var sceneFilePath: String
@Binding var pauseAnimation: Bool
func makeUIView(context: Context) -> SCNView {
print("calling CREATE view")
let scnView = SCNView()
let scene = SCNScene(named: sceneFilePath)
scnView.scene = scene
scnView.showsStatistics = true
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
print("calling UPDATE view")
scnView.scene?.isPaused = pauseAnimation
}
}
更新:有点纠正,但想法是一样的。使用 Xcode 11.4 / iOS 13.4 测试。SceneKitView
更改时重新创建sceneFilePath:
,因此如果未更新,则为不同的代码问题。
这是使用的测试视图:
struct TestSceneKitView: View {
@State private var filePath = "test1"
var body: some View {
VStack {
Button("Push") { self.filePath = "test2" }
SceneKitView(sceneFilePath: filePath, pauseAnimation: .constant(false))
}
}
}
推荐阅读
- android - 更改 android seekbar 值而不直接单击 seekbar 拇指
- javascript - 递归中的异步方法如何正确返回结果?
- c# - C# 中的 C++ 结构化绑定的模拟
- azure - C# 中用于使用 Azure API 管理删除缓存的 SDK 的可用性
- angularjs - AngularJS - 使用 .components() 与使用 TypeScript 定义组件
- apache - 如果目录显示为可写,为什么“该目录不可被 Web 进程写入”?
- asp.net-mvc - Kentico 12 PageBuilder 缺少参考
- matrix - 使用 Julia 将未格式化的 FORTRAN 文件读入多维数组
- reactjs - 单击卡片时如何路由到具有特定卡片详细信息的页面?
- javascript - 根据范围返回数组中的对象