2

I'm working on a game that support both normal playing and VR using SceneKit. When playing normally I have a single SCNView, one camera which also corresponds to the view audio listener. When switching to VR mode I split the screen into two SCNView both playing the same scene from two different camera with the audio listener positioned between them, no problem here.

In my game I need positional audio so I use SCNAudioSuorce to play the sound effect using a SCNAction but since the same scene is playing in both view how can I mute one of them and have the audio only came from the other? I've searched the web and the documentation but found nothing about this.

iOS 11 Update: after testing my app on iOS 11 and trying to play a sound while in VR mode the app crashes on the rendering queue thread at __UpdateAudioTransform because I play that sound, removing it from the action (which includes other nodes transformations) makes the game run fine.

Update 1: Thanks to @rickster advice I tried implementing a SCNTechnique and following Apple documentation I got this

SCNTechnique(dictionary: [
    "passes" : [
        "leftView": [
            "draw": "DRAW_SCENE",
            "pointOfView": stereoCameraLeftName,
            "viewport": "(0, 0, 400, 400)"
        ],
        "rightView": [
            "draw": "DRAW_SCENE",
            "pointOfView": stereoCameraRightName,
            "viewport": "(200, 0, 400, 400)"
        ]
    ],
    "sequence": [ "leftView", "rightView" ]
    ])

where stereoCameraLeftName and stereoCameraRightName are defined elsewhere as strings and used as the names of the nodes containing the corresponding cameras and the viewports dimensions are just for testing. When I apply this technique to the scene it doesn't work and depending on how the scene pointOfView is set I either see the full scene filled with the background colour (pointOfView set to the camera used for non VR mode, no more linked to the scene graph) or the full size rendered using one of the two cameras (pointOfView set to nil), what am I missing?

Update 2: after some trail and error I found that the correct way to define a simple pass for a custom viewport is like this, with w and h defined as CGFloat:

let technique = SCNTechnique(dictionary: [
    "passes" : [
        "leftView": [
            "outputs": [ "color": "COLOR" ],
            "draw": "DRAW_SCENE",
            "colorStates": [
                "clear": true,
                "clearColor": "sceneBackground"
            ],
            "pointOfView": stereoCameraLeftName,
            "viewport": "0 0 \(w) \(h)"
        ],
        "rightView": [
            "outputs": [ "color": "COLOR" ],
            "draw": "DRAW_SCENE",
            "colorStates": [
                "clear": false
            ],
            "pointOfView": stereoCameraRightName,
            "viewport": "\(w) 0 \(w) \(h)",
            "blendStates": [
                "colorOp": "add",
                "alphaOp": "add"
            ]
        ]
    ],
    "sequence": [ "leftView", "rightView" ]
])

But there is a problem: when the second pass is rendered the left side of the screen remain black (clear colour) and the right side is rendered correctly, if I exclude this pass leaving only the first one the left side is correctly rendered and the right side appear with the scene background colour as expected. What's strange is that if instead of testing on my iPhone 6s running iOS 11 I test on a simulator (iOS 11) all seems to work fine, I'm sure I'm missing something in combining the two passes.

Update 2.1: removing blendStates from the second pass gives the same results.

Update 3: trying to recreate a MWE to recreate the problem I've found that my approach is correct, I'll try to investigate other parts of my projects to find where's the problem.

Final update: the problems seems to be caused by antialiasing being active on the view, disabling it make the SCNTechnique works fine, seems like a bug of iOS 11 and I've already filed a bug report.

Marco Boschi
  • 2,321
  • 1
  • 16
  • 30

1 Answers1

3

This is one of a number of issues with trying to render the same scene in multiple views. (Others include performance and concurrency.) Instead, it's probably a better choice to use only a single view, and use SCNTechnique to render the view's scene twice in it.

When you configure a technique, you can set the pointOfView separately for each draw pass — that'd probably be handy if you're looking for stereo separation.

You can also set the viewport for each pass. If you're doing some sort of stereo rendering, you'd use this to make one render pass cover one half of the view, and the other render pass cover the other half.

rickster
  • 124,678
  • 26
  • 272
  • 326
  • Thanks I'll look into it, do you have any tutorial/guide I should read about this? – Marco Boschi Sep 25 '17 at 20:36
  • I've made some progress in defining the technique as you can see in my question, I'm just one step short from making it to work. Do you have any idea why it's not working correctly? – Marco Boschi Sep 26 '17 at 09:02
  • Regarding your final update: on filing a bug about multisampling (antialiasing). Note that with techniques you can control multisampling on a per-pass basis, so part of the issue may involve conflicts between view-specific and pass-specific multisampling settings. – rickster Sep 26 '17 at 23:33
  • I thought of something like that but what’s strange is that on a simulator works fine so something is wrong, I’ll wait for Apple response. – Marco Boschi Sep 27 '17 at 05:37
  • 1
    SceneKit in the Simulator uses a software-based OpenGL renderer... it’s generally a bad idea to rely on it for anything beyond the basics of setting up a scene graph. – rickster Sep 28 '17 at 03:51
  • @MarcoBoschi did you ever get a response from Apple? I'm trying to use the same `SCNTechnique` approach on macOS Mojave, and I also get one of the views (Right) rendering completely blank. I tried setting `antialiasingMode` to `none` with no effect. – Oskar Sep 19 '18 at 19:11
  • Wow quick reply :) I slipped on my key and sent before finishing the message. See edit above. Do you have a link to the radar? Also, are you sure you didn't do anything else other than disable anti aliasing? – Oskar Sep 19 '18 at 19:15
  • @MarcoBoschi See example of the issue here: https://github.com/OskarGroth/TechniqueTest – Oskar Sep 19 '18 at 19:21
  • Nothing on the radar. This was an old project for experiments but if I recall correctly I just disabled antialiasing altogether. Launching the app on iOS 12 without recompiling with Xcode 10 is giving me problems like you report: both passes appear on the left side and the right is empty, but unfortunately I don't have the time to investigate further – Marco Boschi Sep 19 '18 at 19:30