Error loading WebView CALayer in SCNNode

I am looking for help to figure out how to approach this problem. SceneKit allows you to set CALayer as the contents of an SCNNode appearance. Is it possible to get a CALayer from a UIWebView and display it as the contents of SCNMaterial?

I am trying to change the diffuse content of SCNNode to the WebView level in the function - (void) webViewDidFinishLoad: (UIWebView *) webView terminates, but the code crashes.

But I get this error: 43282] bool _WebTryThreadLock (bool), 0x7fae33f33680: I tried to get a web lock from a thread other than the main thread or the web thread. This may be the result of calling UIKit from the secondary stream. Crash now ...

Here is my code for reference

//
//  GameViewController.h
//  WebViewLayerTest
//

#import <UIKit/UIKit.h>
#import <SceneKit/SceneKit.h>

@interface GameViewController : UIViewController <UIWebViewDelegate,SCNNodeRendererDelegate>
@property (nonatomic, retain) IBOutlet UIWebView *webView;
@property (nonatomic,retain) SCNBox *box;
-(void) storeLayer;
@end



//
//  GameViewController.m
//  WebViewLayerTest
//
//

#import "GameViewController.h"
#import <QuartzCore/QuartzCore.h>

@implementation GameViewController 

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.webView = [[UIWebView alloc] initWithFrame:CGRectMake(10, 10, self.view.bounds.size.width-20.0, self.view.bounds.size.height-30.0)];
    
    NSString *urlAddress = @"https://www.google.com/";
    NSURL *url = [NSURL URLWithString:urlAddress];
    NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
    [self.webView loadRequest:requestObj];
    
    self.webView.delegate = self;

    // create a new scene

    SCNScene *scene = [SCNScene scene];

    // create and add a camera to the scene
    SCNNode *cameraNode = [SCNNode node];
    cameraNode.camera = [SCNCamera camera];
    [scene.rootNode addChildNode:cameraNode];
 
    //    // place the camera
    cameraNode.position = SCNVector3Make(0, 0, 15);

    // create and add a light to the scene
    SCNNode *lightNode = [SCNNode node];
    lightNode.light = [SCNLight light];
    lightNode.light.type = SCNLightTypeOmni;
    lightNode.position = SCNVector3Make(0, 10, 10);
    [scene.rootNode addChildNode:lightNode];
  
    // create and add an ambient light to the scene
    SCNNode *ambientLightNode = [SCNNode node];
    ambientLightNode.light = [SCNLight light];
    ambientLightNode.light.type = SCNLightTypeAmbient;
    ambientLightNode.light.color = [UIColor darkGrayColor];
    [scene.rootNode addChildNode:ambientLightNode];
   
    
    self.box = [SCNBox boxWithWidth:1.0 height:1.0 length:1.0 chamferRadius:0.05];
    self.box.firstMaterial.diffuse.contents = [UIColor blueColor];
    
    SCNNode* ship = [SCNNode nodeWithGeometry:self.box];
    //    // animate the 3d object
    [ship runAction:[SCNAction repeatActionForever:[SCNAction rotateByX:0 y:2 z:0 duration:1]]];
    //
    //    // retrieve the SCNView
    SCNView *scnView = (SCNView *)self.view;
    //
    
    [scene.rootNode addChildNode:ship];
    //    // set the scene to the view
    scnView.scene = scene;
    
    // allows the user to manipulate the camera
    scnView.allowsCameraControl = YES;
    
    // show statistics such as fps and timing information
    scnView.showsStatistics = YES;
    
    // configure the view
    scnView.backgroundColor = [UIColor blackColor];
    
    
   
    
    // add a tap gesture recognizer
//    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
//    NSMutableArray *gestureRecognizers = [NSMutableArray array];
//    [gestureRecognizers addObject:tapGesture];
//    [gestureRecognizers addObjectsFromArray:scnView.gestureRecognizers];
//    scnView.gestureRecognizers = gestureRecognizers;
}

- (void) handleTap:(UIGestureRecognizer*)gestureRecognize
{
    // retrieve the SCNView
    SCNView *scnView = (SCNView *)self.view;
    
    // check what nodes are tapped
    CGPoint p = [gestureRecognize locationInView:scnView];
    NSArray *hitResults = [scnView hitTest:p options:nil];
    
    // check that we clicked on at least one object
    if([hitResults count] > 0){
        // retrieved the first clicked object
        SCNHitTestResult *result = [hitResults objectAtIndex:0];
        
        // get its material
        SCNMaterial *material = result.node.geometry.firstMaterial;
        
        // highlight it
        [SCNTransaction begin];
        [SCNTransaction setAnimationDuration:0.5];
        
        // on completion - unhighlight
        [SCNTransaction setCompletionBlock:^{
            [SCNTransaction begin];
            [SCNTransaction setAnimationDuration:0.5];
            
            material.emission.contents = [UIColor blackColor];
            
            [SCNTransaction commit];
        }];
        
        material.emission.contents = [UIColor redColor];
        
        [SCNTransaction commit];
    }
}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    
    NSLog(@"Finished Loading");
    
//    self.box.firstMaterial.diffuse.contents = _webView.layer;

    dispatch_async(dispatch_get_main_queue(),^ {
        self.box.firstMaterial.diffuse.contents = _webView.layer;
    } );
//    [self performSelectorOnMainThread:@selector(storeLayer) withObject:nil waitUntilDone:YES];

}

-(void) storeLayer{
    self.box.firstMaterial.diffuse.contents = _webView.layer;
}

- (BOOL)shouldAutorotate
{
    return YES;
}

- (BOOL)prefersStatusBarHidden {
    return YES;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        return UIInterfaceOrientationMaskAllButUpsideDown;
    } else {
        return UIInterfaceOrientationMaskAll;
    }
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

@end
Run codeHide result
+4
1

, .

1. , CALayer diffuse.contents, UIView

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        guard let imageAnchor = anchor as? ARImageAnchor else { return }
        let testLayer = CALayer()
        testLayer.frame = self.view.bounds
        testLayer.backgroundColor = UIColor.blue.cgColor

        let referenceImage = imageAnchor.referenceImage
        let plane = SCNPlane(width: referenceImage.physicalSize.width,
                             height: referenceImage.physicalSize.height)
        plane.firstMaterial?.diffuse.contents = testLayer
        let planeNode = SCNNode(geometry: plane)
        planeNode.eulerAngles.x = -.pi / 2

        node.addChildNode(planeNode)
    }

}

2. webview, - .

func captureWebview() -> UIImage{
    var image : UIImage!
    UIGraphicsBeginImageContextWithOptions(webView.scrollView.contentSize, webView.scrollView.isOpaque, 0.0)
    let savedContentOffset = webView.scrollView.contentOffset
    let savedFrame = webView.scrollView.frame
    webView.scrollView.contentOffset = CGPoint.zero
    webView.scrollView.frame = CGRect(x: 0, y: 0, width: webView.scrollView.contentSize.width,height: webView.scrollView.contentSize.height)

    webView.scrollView.layer.render(in: UIGraphicsGetCurrentContext()!)
    image = UIGraphicsGetImageFromCurrentImageContext()

    webView.scrollView.contentOffset = savedContentOffset
    webView.scrollView.frame = savedFrame

    UIGraphicsEndImageContext()

    return image
}

3. webview diffuse.contents

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
     guard let imageAnchor = anchor as? ARImageAnchor else { return }

        let referenceImage = imageAnchor.referenceImage
        let plane = SCNPlane(width: referenceImage.physicalSize.width,
                             height: referenceImage.physicalSize.height)
        plane.firstMaterial?.diffuse.contents = self.testImage
        let planeNode = SCNNode(geometry: plane)
        planeNode.eulerAngles.x = -.pi / 2

        node.addChildNode(planeNode)


}
0

Source: https://habr.com/ru/post/1667831/


All Articles