【问题标题】:ARKit – Loading GIF image in SCNNode using CALayer not rendering properlyARKit - 使用 CALayer 在 SCNNode 中加载 GIF 图像无法正确渲染
【发布时间】:2018-03-21 18:02:12
【问题描述】:

我正在开发一个用于渲染 3D 模型的 AR 应用程序。

点击子节点后,我通过使用 CALayer 创建动画并按照此线程 Set contents of CALayer to animated GIF?

将其加载到 diffuse.contents 中来显示 GIF 图像>
let animation : CAKeyframeAnimation = createGIFAnimation(url: gifImageURL!)!
let layer = CALayer()
layer.bounds = CGRect(x: 0, y: 0, width:600, height:200)
layer.add(animation, forKey: "contents")

let newMaterial = SCNMaterial()
newMaterial.isDoubleSided = true
newMaterial.diffuse.contents = layer
let plane = SCNPlane(width: 5, height: 5)
plane.materials = [newMaterial]
let node = SCNNode(geometry: plane)
self.sceneView.scene.rootNode.addChildNode(node)

我可以在 SCNNode 中渲染 gif 图像,但它只显示了四分之一(GIF 的右下角大部分仅可见)。我尝试了以下步骤来纠正这个问题,但仍然是徒劳的。

  1. 改变平面的宽度/高度
  2. 改变 CALayer 的边界
  3. 尝试了不同大小的 gif 图片

请任何人帮助我如何使用 CALayer 在 SCNPlane 中渲染完整的 gif 图像。

【问题讨论】:

  • 图片的一半还是图片的四分之一?因为四分之一的图像听起来像是锚点/原点问题
  • 是的,只有四分之一的图像可见。这可能是什么问题?

标签: swift ios11 scenekit augmented-reality arkit


【解决方案1】:

作为一种解决方法,我按照以下步骤正确加载 GIF:

let plane = SCNPlane(width: 2, height: 2)

let bundleURL = Bundle.main.url(forResource: "engine", withExtension: "gif")
let animation : CAKeyframeAnimation = createGIFAnimation(url: bundleURL!)!
let layer = CALayer()
layer.bounds = CGRect(x: 0, y: 0, width: 900, height: 900)

layer.add(animation, forKey: "contents")
let tempView = UIView.init(frame: CGRect(x: 0, y: 0, width: 900, height: 900))
tempView.layer.bounds = CGRect(x: -450, y: -450, width: tempView.frame.size.width, height: tempView.frame.size.height)
tempView.layer.addSublayer(layer)

let newMaterial = SCNMaterial()
newMaterial.isDoubleSided = true
newMaterial.diffuse.contents = tempView.layer
plane.materials = [newMaterial]
let node = SCNNode(geometry: plane)
node.name = "engineGif"
let gifImagePosition = SCNVector3Make((self.virtualObjectInteraction.selectedObject?.childNodes[0].position.x)! + 2, 
                                      (self.virtualObjectInteraction.selectedObject?.childNodes[0].position.y)! + 4, 
                                      (self.virtualObjectInteraction.selectedObject?.childNodes[0].position.z)! - 2)
node.position = gifImagePosition
self.virtualObjectInteraction.selectedObject?.childNodes[0].addChildNode(node)

createGIFAnimation 在哪里创建所需的动画,

func createGIFAnimation(url:URL) -> CAKeyframeAnimation? {

    guard let src = CGImageSourceCreateWithURL(url as CFURL, nil) else { return nil }
    let frameCount = CGImageSourceGetCount(src)

    // Total loop time
    var time : Float = 0

    // Arrays
    var framesArray = [AnyObject]()
    var tempTimesArray = [NSNumber]()

    // Loop
    for i in 0..<frameCount {

        // Frame default duration
        var frameDuration : Float = 0.1;

        let cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(src, i, nil)
        guard let framePrpoerties = cfFrameProperties as? [String:AnyObject] else {return nil}
        guard let gifProperties = framePrpoerties[kCGImagePropertyGIFDictionary as String] as? [String:AnyObject]
            else { return nil }

        // Use kCGImagePropertyGIFUnclampedDelayTime or kCGImagePropertyGIFDelayTime
        if let delayTimeUnclampedProp = gifProperties[kCGImagePropertyGIFUnclampedDelayTime as String] as? NSNumber {
            frameDuration = delayTimeUnclampedProp.floatValue
        } else {
            if let delayTimeProp = gifProperties[kCGImagePropertyGIFDelayTime as String] as? NSNumber {
                frameDuration = delayTimeProp.floatValue
            }
        }

        // Make sure its not too small
        if frameDuration < 0.011 {
            frameDuration = 0.100;
        }

        // Add frame to array of frames
        if let frame = CGImageSourceCreateImageAtIndex(src, i, nil) {
            tempTimesArray.append(NSNumber(value: frameDuration))
            framesArray.append(frame)
        }

        // Compile total loop time
        time = time + frameDuration
    }

    var timesArray = [NSNumber]()
    var base : Float = 0
    for duration in tempTimesArray {
        timesArray.append(NSNumber(value: base))
        base += ( duration.floatValue / time )
    }

    // From documentation of 'CAKeyframeAnimation':
    // the first value in the array must be 0.0 and the last value must be 1.0.
    // The array should have one more entry than appears in the values array.
    // For example, if there are two values, there should be three key times.
    timesArray.append(NSNumber(value: 1.0))

    // Create animation
    let animation = CAKeyframeAnimation(keyPath: "contents")

    animation.beginTime = AVCoreAnimationBeginTimeAtZero
    animation.duration = CFTimeInterval(time)
    animation.repeatCount = Float.greatestFiniteMagnitude;
    animation.isRemovedOnCompletion = false
    animation.fillMode = kCAFillModeForwards
    animation.values = framesArray
    animation.keyTimes = timesArray
    //animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
    animation.calculationMode = kCAAnimationDiscrete

    return animation;
}

【讨论】:

  • 这个::createGIFAnimation 是什么意思?
【解决方案2】:

对于遇到此问题的其他人来说,这确实是一个锚点问题。只需像这样更新锚点

let layer = CALayer()
layer.bounds = CGRect(x: 0, y: 0, width: 900, height: 900)
layer.anchorPoint = CGPoint(x:0.0,y:1.0)
...

【讨论】:

    猜你喜欢
    • 2019-04-23
    • 2020-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-22
    • 2013-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多