我正在研究一个AR渲染3D模型的应用程序。
点击子节点后,我通过使用 CALayer 创建动画并在 diffuse.contents 中加载它来显示GIF图像,方法是跟随此线程Set contents of CALayer to animated GIF? < / p>
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的右下角部分只能看到)。我尝试了以下步骤来纠正这个问题,但仍然徒劳无功。
任何人都可以帮我解决如何使用CALayer在SCNPlane中渲染完整的GIF图像。
答案 0 :(得分:5)
作为一种解决方法,我按照以下步骤正确加载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;
}
答案 1 :(得分:0)
对于其他任何遇到此问题的人,这确实是一个锚点问题。像这样简单地更新锚点
let layer = CALayer()
layer.bounds = CGRect(x: 0, y: 0, width: 900, height: 900)
layer.anchorPoint = CGPoint(x:0.0,y:1.0)
...