sven7
sven7

Reputation: 758

SK3DNode shows SCNScene darker than in SCNView

Before I am going mad I'd like to ask here about the following issue. I wrote an iOS test app in SwiftUI that shows a SpriteView and a SceneView. The SpriteView shows (among other things) two SK3DNode nodes that display one and the same SCNScene from different camera positions. The SceneView renders the very same SCNScene.

The problem is that the rendered scene in both SK3DNode's are shown darker than in SceneView.

The scenes in SpriteKit are unusable because they are too dark.

This is a screenshot from the iPad simulator:

Screenshot in simulator

I expected both SK3DNode's (at the top half) to render the scene at the same brightness as the SceneView (bottom half).

If I simply increase the ambient light, objects are shown way too bright. I thought the problem is the texture or the material, but the problem also occurs with colours. Hence the red/green/blue shapes. I have disabled SK3DNode's built-in lighting by setting autoenablesDefaultLighting to false. Somehow SceneView (or its internal SCNView) must add its own lighting but I cannot figure how. The scene's rootNode only shows my nodes from the .scn file.

I've disabled the environment in the scene file so there is no sky cube. There is one ambient light source, one spot light, and one omni light. No matter which lights I am using, both SK3DNode's still present the scene much darker than the SceneView.

Here is the function that creates the two SK3DNodes:

func make3DNode(camPos: SCNVector3) -> SK3DNode {
    // Add SceneKit scene in 3D node
    let node3d = SK3DNode(viewportSize: CGSize(width: 300, height: 200))
    node3d.scnScene = scnScene
    node3d.autoenablesDefaultLighting = false
    
    let camera = SCNCamera()
    let cameraNode = SCNNode()
    cameraNode.camera = camera
    if let lookAtTarget = scnScene.rootNode.childNode(withName: "red_texture", recursively: false) {
        let constraint = SCNLookAtConstraint(target: lookAtTarget)
        // why does this not work?
        cameraNode.constraints = [constraint]
    }
    cameraNode.position = camPos
    node3d.pointOfView = cameraNode

    return node3d
}

On a side note: the camera lookAt constraint does not seem to work either.

Code to add the nodes to the scene:

    // Add SceneKit nodes
    let node3d_1 = make3DNode(camPos: SCNVector3(x: -5, y: -2, z: 14))
    node3d_1.name = "3d_1"
    node3d_1.position = CGPoint(x: 150, y: 110)
    spriteScene.addChild(node3d_1)

    let node3d_2 = make3DNode(camPos: SCNVector3(x: 5, y: 2, z: 14))
    node3d_2.name = "3d_2"
    node3d_2.position = CGPoint(x: 150, y: -110)
    spriteScene.addChild(node3d_2)

Full project source: https://github.com/biochill/test-spritekit

It includes both the SpriteKit scene file and the SceneKit file. The SK3DNodes are added programmatically. I can't paste code for the scenes because I have created scene files both for SpriteKit and SceneKit. Best if you download the GitHub project and hit Cmd+R in Xcode for some iPad simulator.

Thanks for any help in advance.

Upvotes: 3

Views: 90

Answers (1)

ZAY
ZAY

Reputation: 5040

Here is what I did, to make both scenes (upper SpriteKit embedded and lower part SceneKit of the screen) to look the same:

Enabled: autoenablesDefaultLighting (you could also add lighting manually and then set autoenablesDefaultLighting to false)

in file: ContentView.swift

func make3DNode(camPos: SCNVector3) -> SK3DNode {
        // Add SceneKit scene in 3D node
        let node3d = SK3DNode(viewportSize: CGSize(width: 300, height: 200))
        
        node3d.scnScene = scnScene
        node3d.autoenablesDefaultLighting = true // <-- set to true

I also re-enabled the code-line: MySceneView(scene: scnScene)...

in file: MySceneView.swift

struct MySceneView: UIViewRepresentable {
    var scene: SCNScene
//  var visibleSize: CGSize
    
    func makeUIView(context: Context) -> SCNView {
        //      SLog.print("DiceView.makeUIView size=\(visibleSize)")
        
        let scnView = context.coordinator
        scnView.scene = scene
        scnView.delegate = scnView
        scnView.autoenablesDefaultLighting = true // <-- set to true

The most important part comes here, which effectively fixed the issue in my testings.

You need to add a valid info.plist file to the project.

Add this content: SCNDisableLinearSpaceRendering = YES/true

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>SCNDisableLinearSpaceRendering</key>
    <true/>
</dict>
</plist>

SCNDisableLinearSpaceRendering set to YES

Note: you will not see this setting listed here:

Setting not visible on the Info tab

And this is how it looks like on my iPad mini:

Both scenes look the same

Further adjustments: As already mentioned, you could manage the Lighting manually.

I hope this resolves the issue with the dark scene.

Upvotes: 1

Related Questions