我想打开一个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])
}
更新:
更简单的解决方案是使用 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])
我无法在这里找到一个完整的工作片段,但感谢 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()
}
}
使用
SwiftUI
的SpriteView
略有不同。
要在 SwiftUI 中实现透明的SpriteView,您必须使用'options'参数:
// 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])
我不喜欢使用 SpriteKit 使 SceneKit 场景背景内容透明,因为您完全失去了对 SCNView 的访问权限。这是我认为正确的方法。
/// 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()
}
}