如何让SceneView的背景透明?

问题描述 投票:0回答:4

我想打开一个3D模型,让它的背景透明,这样我就可以看到SceneView背后的UI。我试过这段代码,但是 sceneView 变成了白色,不透明。


struct ModelView: View {
    var body: some View {
        ZStack {
            Text("Behind Text Behind Text Behind Text")
            SceneView(
                scene: { () -> SCNScene in
                    let scene = SCNScene()
                    scene.background.contents = UIColor.clear
                    return scene
                }(),
                pointOfView: { () -> SCNNode in
                    let cameraNode = SCNNode()
                    cameraNode.camera = SCNCamera()
                    cameraNode.position = SCNVector3(x: 0, y: 0, z: 10)
                    return cameraNode
                }(),
                options: [
                    .allowsCameraControl,
                    .temporalAntialiasingEnabled,
                ]
            )
        }
    }
}

我使用 XCode 12.5 和 iPhone 8.

编辑1:

感谢下面的评论,我决定尝试新方法,但它们仍然不起作用。

方法#1

首先,我尝试通过 UIViewRepresentable 使用 SCNView 创建一个 MySceneView:

struct MySceneView: UIViewRepresentable {
    typealias UIViewType = SCNView
    typealias Context = UIViewRepresentableContext<MySceneView>

    func updateUIView(_ uiView: UIViewType, context: Context) {}
    func makeUIView(context: Context) -> UIViewType {
        let view = SCNView()
        view.allowsCameraControl = true
        view.isTemporalAntialiasingEnabled = true
        view.autoenablesDefaultLighting = true
        view.scene = MySceneView.scene
        return view
    }
    
    static let scene: SCNScene = {
        let scene = SCNScene(named: "art.scnassets/man.obj")!
        scene.background.contents = UIColor.clear
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 10)
        scene.rootNode.addChildNode(cameraNode)
        return scene
    }()
}

方法#2 我尝试使用 SpriteView,这是代码:

        ZStack {
            Text("Behind Text Behind Text Behind Text")
            SpriteView(scene: { () -> SKScene in
                let scene = SKScene()
                scene.backgroundColor = UIColor.clear
                let model = SK3DNode(viewportSize: .init(width: 200, height: 200))
                model.scnScene = MySceneView.scene
                scene.addChild(model)
                return scene
            }(), options: [.allowsTransparency])
}
swiftui scenekit
4个回答
2
投票

更新:

更简单的解决方案是使用 UIViewRepresentable,创建 SCNView 并将 backgroundColor 设置为 clear

旧:

谢谢 George_E,你的想法与 SpriteKit 完美结合。这是代码:

SpriteView(scene: { () -> SKScene in
    let scene = SKScene()
    scene.backgroundColor = UIColor.clear
    let model = SK3DNode(viewportSize: .init(width: 200, height: 200))
    model.scnScene = {
        let scene = SCNScene(named: "art.scnassets/man.obj")!
        scene.background.contents = UIColor.clear
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 10)
        scene.rootNode.addChildNode(cameraNode)
        return scene
    }()
    scene.addChild(model)
    return scene
}(), options: [.allowsTransparency])

1
投票

我无法在这里找到一个完整的工作片段,但感谢 Arutyun 的回答,我设法编译了一个工作解决方案而不需要

SpriteKit
.

import SceneKit
import SwiftUI

struct MySceneView: UIViewRepresentable {
    typealias UIViewType = SCNView
    typealias Context = UIViewRepresentableContext<MySceneView>

    func updateUIView(_ uiView: UIViewType, context: Context) {}
    func makeUIView(context: Context) -> UIViewType {
        let view = SCNView()
        view.backgroundColor = UIColor.clear // this is key!
        view.allowsCameraControl = true
        view.autoenablesDefaultLighting = true
        // load the object here, could load a .scn file too
        view.scene = SCNScene(named: "model.obj")!
        return view
    }
}

像普通视图一样使用它:

import SwiftUI

struct MySceneView: View {
    var body: some View { 
        ZStack{
            // => background views here
            MySceneView()
                .frame( // set frame as required
                    maxWidth: .infinity,
                    maxHeight: .infinity,
                    alignment: .center
                )
        }
    }
}

struct MySceneView_Previews: PreviewProvider {
    static var previews: some View {
        MySceneView()
    }
}

0
投票

使用 SwiftUI:

使用

SwiftUI
SpriteView
略有不同。

要在 SwiftUI 中实现透明的SpriteView,您必须使用'options'参数:

  1. 使用清晰的背景配置您的 SKScene(视图和场景)
  2. 使用正确的选项配置您的 SpriteView
// 1. configure your scene in 'didMove'
override func didMove(to view: SKView) {
    self.backgroundColor = .clear
    view.backgroundColor = .clear
}

最重要的是:

// 2. configure your SpriteView with 'allowsTranspanency'
SpriteView(scene: YourSKScene(), options: [.allowsTransparency])

0
投票

我不喜欢使用 SpriteKit 使 SceneKit 场景背景内容透明,因为您完全失去了对 SCNView 的访问权限。这是我认为正确的方法。

  1. 创建名为 GameScene.scn 的 Scene Kit 场景文件
  2. 将您的 3D 对象放入 GameScene
  3. 使用下面的代码
/// The SCNView view
struct GameSceneView: UIViewRepresentable {
    @ObservedObject var viewModel: GameSceneViewModel
    
    func makeUIView(context: UIViewRepresentableContext<GameSceneView>) -> SCNView {
        let view = SCNView()
        view.backgroundColor = viewModel.backgroundColor
        view.allowsCameraControl = viewModel.allowsCameraControls
        view.autoenablesDefaultLighting = viewModel.autoenablesDefaultLighting
        view.scene = viewModel.scene
        return view
    }
    
    func updateUIView(_ uiView: SCNView, context: UIViewRepresentableContext<GameSceneView>) {}
}

/// The view model supplying the SCNScene and its properties
class GameSceneViewModel: ObservableObject {
    @Published var scene: SCNScene?
    @Published var backgroundColor: UIColor
    @Published var allowsCameraControls: Bool
    @Published var autoenablesDefaultLighting: Bool
    
    init(
        sceneName: String = "GameScene.scn",
        cameraName: String = "camera",
        backgroundColor: UIColor = .clear,
        allowsCameraControls: Bool = true,
        autoenablesDefaultLighting: Bool = true
    ) {
        self.scene = SCNScene(named: sceneName)
        self.backgroundColor = backgroundColor
        self.allowsCameraControls = allowsCameraControls
        self.autoenablesDefaultLighting = autoenablesDefaultLighting
        
        scene?.background.contents = UIColor.clear
        scene?.rootNode.childNode(withName: cameraName, recursively: false)
    }
}

/// Usage
struct ContentView: View {
    var body: some View {
        VStack {
            GameSceneView(viewModel: GameSceneViewModel())
        }
        .background(Color.blue)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.