You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARKit中UIWebView显示异常及SKVideoNode卡顿问题求助

Fixing ARImageTracking Issues: WebView Display & Video Node Glitches

Hey there, let's tackle your two AR-related problems step by step. Both issues stem from specific quirks in how SceneKit interacts with UIKit/SpriteKit components, so let's break them down:


1. UIWebView/WKWebView Not Displaying Correctly Post-Image Detection

First off, UIWebView is deprecated—so switching to WKWebView is non-negotiable, but there are a few key mistakes in your current implementation that are causing the problem:

What's Going Wrong:

  • You're adding the web view node to rootNode instead of the tracked image's node, meaning it won't stay anchored to the detected image.
  • The xOffset variable is undefined in your code snippet—this is likely causing the plane to have an invalid size, leading to unexpected rendering.
  • Even with DispatchQueue.main.async, WKWebView requires proper configuration and size matching between the UI component and the SceneKit plane.

Fixed WKWebView Implementation:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    guard let imageAnchor = anchor as? ARImageAnchor else { return }
    updateQueue.async {
        let physicalWidth = imageAnchor.referenceImage.physicalSize.width
        let physicalHeight = imageAnchor.referenceImage.physicalSize.height
        
        // Create detection highlight plane
        let mainPlane = SCNPlane(width: physicalWidth, height: physicalHeight)
        mainPlane.firstMaterial?.colorBufferWriteMask = .alpha
        let mainNode = SCNNode(geometry: mainPlane)
        mainNode.eulerAngles.x = -.pi / 2
        mainNode.renderingOrder = -1
        node.addChildNode(mainNode)
        
        self.highlightDetection(on: mainNode, width: physicalWidth, height: physicalHeight, completionHandler: {
            DispatchQueue.main.async {
                // Define a pixel size for the web view (match your desired resolution)
                let webViewPixelSize = CGSize(width: 800, height: 1360)
                // Calculate plane size relative to the tracked image (adjust ratio as needed)
                let webPlaneWidth = physicalWidth * 1.1
                let webPlaneHeight = webPlaneWidth * (webViewPixelSize.height / webViewPixelSize.width)
                
                // Initialize WKWebView with proper configuration
                let webConfig = WKWebViewConfiguration()
                let webView = WKWebView(frame: CGRect(origin: .zero, size: webViewPixelSize), configuration: webConfig)
                webView.load(URLRequest(url: URL(string: "https://www.facebook.com/")!))
                
                // Create plane for web view
                let webViewPlane = SCNPlane(width: webPlaneWidth, height: webPlaneHeight)
                webViewPlane.cornerRadius = 0.05 // Adjust to a reasonable physical size (not too large)
                webViewPlane.firstMaterial?.diffuse.contents = webView
                webViewPlane.firstMaterial?.isDoubleSided = false
                
                // Create node and anchor it to the detected image's node
                let webViewNode = SCNNode(geometry: webViewPlane)
                webViewNode.position.z = -0.01 // Slightly in front of the detection plane
                webViewNode.opacity = 0
                
                // Add to the tracked image's node, not rootNode
                node.addChildNode(webViewNode)
                
                // Run your animation sequence
                webViewNode.runAction(.sequence([
                    .wait(duration: 3.0),
                    .fadeOpacity(to: 1.0, duration: 1.5),
                    .moveBy(x: webPlaneWidth * 1.1, y: 0, z: -0.05, duration: 1.5),
                    .moveBy(x: 0, y: 0, z: -0.05, duration: 0.2)
                ]))
            }
        })
    }
}

Key Fixes:

  • Anchored the web view node to the tracked image's node instead of rootNode to keep it aligned with the detected image.
  • Defined a clear pixel size for WKWebView and matched the SCNPlane's physical size to maintain aspect ratio.
  • Used a reasonable cornerRadius value (0.05m instead of 0.25m) to avoid excessive rendering overhead.
  • Removed unnecessary double-sided rendering for better performance.

2. SKVideoNode Glitches (Lag & Pixelation) with cornerRadius

The issue here is that SCNPlane.cornerRadius is computationally expensive for real-time content like video—especially when the radius is large relative to the plane size. This causes frame drops and rendering artifacts.

What's Going Wrong:

  • A cornerRadius of 0.25m is extremely large for most tracked images (e.g., a standard postcard is ~0.15m wide), forcing SceneKit to do heavy real-time masking.
  • Mismatched SKScene and video resolution can also contribute to pixelation and lag.

Fixed Video Node Implementation (Using Masking for Rounded Corners):

Instead of relying on SCNPlane.cornerRadius, use a mask node to create rounded corners without performance hits:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    guard let imageAnchor = anchor as? ARImageAnchor else { return }
    updateQueue.async {
        let physicalSize = imageAnchor.referenceImage.physicalSize
        
        // Create detection highlight plane
        let mainPlane = SCNPlane(width: physicalSize.width, height: physicalSize.height)
        mainPlane.firstMaterial?.colorBufferWriteMask = .alpha
        let mainNode = SCNNode(geometry: mainPlane)
        mainNode.eulerAngles.x = -.pi / 2
        mainNode.renderingOrder = -1
        node.addChildNode(mainNode)
        
        self.highlightDetection(on: mainNode, width: physicalSize.width, height: physicalSize.height, completionHandler: {
            // Initialize video node based on anchor name
            var videoNode: SKVideoNode!
            switch imageAnchor.name {
            case "Elephant-PostCard":
                videoNode = SKVideoNode(fileNamed: "Movies/cat.mp4")
            case "puppy":
                videoNode = SKVideoNode(fileNamed: "puppy.mov")
            default:
                return // Exit if no matching video
            }
            
            // Configure video
            videoNode.yScale = -1.0
            videoNode.play()
            
            // Match SKScene size to video resolution
            guard let videoAsset = videoNode.videoAsset else { return }
            let videoSize = CGSize(width: videoAsset.naturalSize.width, height: videoAsset.naturalSize.height)
            let videoScene = SKScene(size: videoSize)
            videoScene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
            videoScene.addChild(videoNode)
            
            // Create main video plane
            let videoPlane = SCNPlane(width: physicalSize.width, height: physicalSize.height)
            videoPlane.firstMaterial?.diffuse.contents = videoScene
            videoPlane.firstMaterial?.isDoubleSided = false
            let videoPlaneNode = SCNNode(geometry: videoPlane)
            
            // Create rounded mask plane
            let maskPlane = SCNPlane(width: physicalSize.width, height: physicalSize.height)
            maskPlane.cornerRadius = 0.05 // Use reasonable radius
            maskPlane.firstMaterial?.colorBufferWriteMask = .alpha
            maskPlane.firstMaterial?.diffuse.contents = UIColor.white
            let maskNode = SCNNode(geometry: maskPlane)
            
            // Apply mask to video node
            videoPlaneNode.maskNode = maskNode
            
            // Add to the main detection node
            mainNode.addChildNode(videoPlaneNode)
        })
    }
}

Key Fixes:

  • Used a separate mask node to create rounded corners—this is far more performant than applying cornerRadius directly to a video-backed plane.
  • Matched the SKScene size to the video's natural resolution to eliminate scaling artifacts.
  • Removed double-sided rendering to reduce GPU load.
  • Used a smaller, more realistic cornerRadius value (0.05m) for better performance.

内容的提问来源于stack exchange,提问作者jack87

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:13:50