SKTextureAtlas不再在iOS 10中共享纹理

时间:2016-10-28 14:16:30

标签: swift sprite-kit ios10

似乎从纹理图集中提取纹理时,我现在正在生成新纹理,而不是使用iOS 10在不同精灵上使用相同纹理。在iOS 9上,这可以按预期工作。还有其他人遇到过这个问题吗?也许有一个我错过的步骤,现在是iOS 10的一部分。

注意:我创建了一个示例项目并创建了一个新的图集,然后在@ 1x中拖动了太空船,我也尝试了预加载,并且没有做任何事情。

代码:

  let atlas = SKTexturAtlas(named:"Sprites")
  var texture = atlas.textureNamed("Spaceship")
  print("\(Unmanaged.passUnretained(texture)),\(Unmanaged.passUnretained(texture).toOpaque())")

  texture = atlas.textureNamed("Spaceship")
  print("\(Unmanaged.passUnretained(texture)),\(Unmanaged.passUnretained(texture).toOpaque())")

编辑:为了解决比较问题,我使用description属性来比较2个纹理是否相等。为了使其工作,您无法使用2个地图集,每个地图集包含具有确切名称和大小的纹理。我永远不会遇到这种情况,但对于那里寻求帮助的人,请记住这一点。

3 个答案:

答案 0 :(得分:3)

我进行了同样的测试并得到了相同的结果。

我不确定100%,但似乎在开发Swift 3期间有一个提案here要更改非托管以使用 UnsafePointer

但如果你试图做:

func address<T: AnyObject>(o: T) -> String{
     let addr = unsafeBitCast(o, to: Int.self)
     return NSString(format: "%p", addr) as String
}

<强>用法

print(address(o: texture))

iOS9 中,您有正确的值, iOS10 错误的结果。

enter image description here

我认为你是对的,我们正面临着一个错误(另一个......)

答案 1 :(得分:1)

对于引用&#34;相同纹理的纹理具有不同的物理地址&#34;真的有问题吗?

我已经运行了默认的示例游戏项目,但是设置了Obj-C。我有一个纹理图集,如下图所示。但是,请注意我通过TexturePacker运行它。所以Xcode实际生成的图集是不同的。

enter image description here

我按照你说的做,并创建了2个同名的纹理。

self.myTextureAtlas = [SKTextureAtlas atlasNamed:@"MyTexture"];
self.tex0 = [self.myTextureAtlas textureNamed:@"tex0"];
self.tex1 = [self.myTextureAtlas textureNamed:@"tex0"];

正如您所说,tex0tex1的指针不同。所以至少Swift和Obj-C之间存在一致性。

但是,我不认为这是一个问题/错误。我怀疑他们改变了实现,所以返回的SKTexture是一个新的&#34;实例&#34;但是底层纹理仍然是相同的。

我会谈谈OpenGL,因为这就是我编写引擎的原因.Metal仍然会有相似之处。基本的子纹理实际上只有两个重要的属性:纹理名称(这是OpenGL纹理名称)和UV。如果你正在考虑什么将被视为&#34;平等&#34;为了符合Equatable,它很可能会测试这两个项目的平等性。纹理名称是atlas纹理名称,UV是atlas中的UV,表示特定子纹理的区域。

为了测试这个假设,我对此进行了GPU帧捕获。使用Xcode 8,这似乎很不错。使用Metal,它100%的时间都崩溃了。我强迫它使用OpenGL并设法获得帧捕获。正如预期的那样,当我查看所有纹理资源时,我只看到了一个纹理图集。

enter image description here

纹理#3是MyTexture。

如果我转储看起来像UV的textureRect,我可以看到它们是相同的:

  

Tex0 Rect 0.001618 0.793765 0.139159 0.203837

     

Tex1 Rect 0.001618 0.793765 0.139159 0.203837

基于此,似乎self.tex0self.tex1虽然具有不同的物理地址,但仍然指向相同的子纹理。

请注意,我不再使用SpriteKit。我当前的渲染器使用纹理句柄,但是,在检索时,您可以获得具有不同物理地址的句柄对象。它们仍然都取消引用真正的纹理,因为它们仍然引用相同的底层纹理实例。

我想,如果差异指针仍然引用相同的底层纹理(即不再分配纹理内存),我也不会真正看到问题指针。

答案 2 :(得分:1)

为了解决这个问题,我不得不想出一种缓存纹理的方法,以便它不会重复:

private var textureCache = [String: SKTexture]()
extension SKTextureAtlas
{
    func texturesWithNames(_ names:[String]) -> [SKTexture]
    {
        var textures = [SKTexture]()
        names.forEach({textures.append(textureNamed($0))})
        return textures
    }
    func cachedTextureWithName(_ name:String) -> SKTexture
    {
        if  textureCache[name] == nil
        {

            textureCache[name] = textureNamed(name)
        }

        return textureCache[name]!
    }
    func cachedTexturesWithNames(_ names:[String]) -> [SKTexture]
    {
        var textures = [SKTexture]()
        names.forEach({textures.append(cachedTextureWithName($0))})
        return textures
    }
    func clearCache()
    {
        textureCache = [String: SKTexture]()
    }
}


extension SKTexture
{

    var name : String
    {
        return self.description.slice(start: "'",to: "'")!
    }


}