Capture Bild / Screenshot von SCNView mit SCNNode ausgeblendet: drawViewHierarchyInRect afterScreenUpdates funktioniert nicht

8

Der folgende Code fängt einen Screenshot von SCNView1 ein, funktioniert aber nicht ganz.

SCNView1 enthält Knoten1. Ziel ist es, SCNView1 ohne Node1 zu erfassen.

Die Einstellung von afterScreenUpdates auf true (oder false) hilft jedoch nicht: Der Screenshot enthält Node1, egal was passiert.

Was ist das Problem?

%Vor%     
Crashalot 28.04.2016, 00:15
quelle

1 Antwort

9

Wir haben es hier mit zwei verschiedenen Systemen zu tun, die nicht unbedingt kommunizieren: die Rendering-Engine SceneKit und das Zeichensystem UIKit / CoreGraphics , das versucht, den Screenshot zu erfassen. Wenn Sie SCNNode ausblenden, wird die Ansicht nicht sofort für das Neuzeichnen ungültig, wie das Ausblenden einer UIView -Unteransicht, daher hat das Festlegen von afterScreenUpdates auf true zu diesem Zeitpunkt keine Wirkung. Nachdem der Knoten als verborgen markiert wurde, nachdem wir wissen, dass die Rendering-Schleife SceneKit einmal abgeschlossen wurde und nachdem die Ansicht bereit ist, auf dem Bildschirm neu gezeichnet zu werden, können wir den Screenshot aufnehmen. Wir können Ereignisse in der Render-Schleife anhören, indem wir ein SCNSceneRendererDelegate für das SCNView ( SCNSceneRendererDelegate ). Wir können die Delegate-Methode renderer:didRenderScene:atTime: implementieren.

Weisen Sie Ihrer Szenenansicht einen Delegaten zu ( scnView.delegate = self ). Wenn Sie Ihre Bildschirmaufzeichnung durchführen möchten, blenden Sie den Knoten aus und setzen Sie ein boolesches Flag, das sich im selben Bereich wie der Delegat befindet, auf true :

%Vor%

Dann werden Sie Ihren Delegierten implementieren:

%Vor%

Diese Delegiertenmethode ist für uns nicht perfekt, da die Szene zwar gerendert wird, aber noch nicht bereit ist, die Ansicht auf dem Bildschirm neu zu zeichnen, da diese Delegatenmethode uns die Möglichkeit gibt, ein beliebiges benutzerdefiniertes Rendering durchzuführen. Wenn Sie versuchen, drawViewHierarchyInRect:afterScreenUpdates: oder snapshot aufzurufen, wird das SceneKit-Rendering vollständig beendet (sowohl im Simulator als auch auf dem Gerät für iOS 9.3), was möglicherweise ein SceneKit-Fehler ist. Wir haben keine bessere Option für Delegate-Methoden, aber meine Lösung besteht darin, einen asynchronen Aufruf an die Hauptwarteschlange zu senden, der ausgeführt wird, nachdem die Rendering-Schleife von SceneKit vollständig abgeschlossen wurde und das gerenderte Bild bereit ist, auf dem Bildschirm neu gezeichnet zu werden. Wenn Sie drawViewHierarchyInRect:afterScreenUpdates: verwenden, stellen Sie sicher, dass afterScreenUpdates auf true eingestellt ist, da zu diesem Zeitpunkt die tatsächliche Zeichnung noch nicht ausgeführt wurde. Und wie Sie sicher wissen, vergewissern Sie sich, dass der asynchrone Aufruf auf dem Hauptthread ausgeführt wird, da UIKit -Objekte nie von einem anderen Thread berührt werden sollten.

Übrigens habe ich Ihr Problem repliziert und meine Lösung mit der Standard-SceneKit-Projektvorlage von Xcode 7.3 gefunden (die mit dem rotierenden Schiff). Ich blende die versteckte Eigenschaft des Schiffs jedes Mal, wenn die Szenenansicht angetippt wird, und setze dann die Flagge, um einen Screenshot aufzunehmen. Wir können diese Vorlage bei Bedarf als Grundlage für weitere Diskussionen verwenden.

    
Christopher Whidden 01.05.2016, 20:57
quelle