Reputation: 213
I'm having a problem when creating an SKSpriteNode from pixelData.
Below is my code.
var pixelData: [UInt32] = [UInt32](count: 256, repeatedValue: 0xff0000ff)
pixelData.appendContentsOf([UInt32](count: 256, repeatedValue: 0xff00ff00))
pixelData.appendContentsOf([UInt32](count: 256, repeatedValue: 0xffff0000))
pixelData.appendContentsOf([UInt32](count: 256, repeatedValue: 0x000000ff))
let data = NSData(bytes: pixelData, length: pixelData.count * sizeof(UInt32))
let texture = SKTexture(data: data, size: CGSize(width: 32, height: 32))
let node = SKSpriteNode(texture: texture, size: CGSize(width: 32, height: 32))
node.position.x = self.frame.midX
node.position.y = self.frame.midY
self.addChild(node)
It went as I wish for the three bottom rows (which is the first 3 parts in the pixelData array, 0xff0000ff
, 0xff00ff00
, 0xffff0000
: Red, Green, and Blue).
However, I expected the top row to be totally transparent: 0x000000ff
, which should mean rgba(1, 0, 0, 0). But it appeared as this:
I don't know why this happen. Is my understanding of pixelData wrong? Or is it a bug or something in SpriteKit?
Thank you very much for your help!
Upvotes: 3
Views: 360
Reputation: 12753
From the documentation for the convenience method to convert pixel data to an SKTexture
,
The color components should have been already multiplied by the alpha value.
Consequently, the value 0x000000ff
is undefined, since the red component cannot be 0xff
if the alpha value is 0. Also, it is somewhat non-intuitive to represent a pixel color with a hexadecimal value particularly when the components are in reversed order.
Alternatively, you can define a data structure to represent a color and then pre-multiply each color component by the alpha value during initialization:
struct Color {
var red:UInt8
var green:UInt8
var blue:UInt8
var alpha:UInt8
// You can omit the parameters that have default values.
init(red:UInt8=0, green:UInt8=0, blue:UInt8=0, alpha:UInt8=UInt8.max) {
let alphaValue:Float = Float(alpha) / 255
self.red = UInt8(round(Float(red) * alphaValue))
self.green = UInt8(round(Float(blue) * alphaValue))
self.blue = UInt8(round(Float(green) * alphaValue))
self.alpha = alpha
}
}
You can then define and initialize a pixelData
array with the "same" values as your code by
var pixelData:[Color] = [Color](count: 256, repeatedValue: Color(red: UInt8.max))
pixelData += [Color](count:256, repeatedValue: Color(green: UInt8.max))
pixelData += [Color](count:256, repeatedValue: Color(blue: UInt8.max))
pixelData += [Color](count:256, repeatedValue: Color(red: UInt8.max, alpha: 0))
and create the NSData
object with
let data = NSData(bytes: pixelData, length: pixelData.count * sizeof(Color))
Upvotes: 1