简体   繁体   中英

Transparent pixel in SKMutableTexture

I am using a SKMutableTexture to render destructable ground in a game. For all intents and purposes, this works great, except for when I want to render a transparent pixel into a position in the MutableTexture where there is already a non-transparent pixel.

I have created a struct for RGBAColor like so:

struct RGBAColor {

    var r: UInt8
    var g: UInt8
    var b: UInt8
    var a: UInt8


    static var clear    = RGBAColor(r: 0, g: 0, b: 0, a: 0)
}

I then modify the SKMutableTexture like so:

self.texture.modifyPixelData({ (voidptr, len) in

            let bytes = voidptr!.assumingMemoryBound(to: RGBAColor.self)

            for (index, color) in self.modifiedPixels {
                bytes[index] = color
                self.pixels[index] = color
            }

        })

.. where "modifiedPixels" is a dictionary like [Int : RGBAColor] (in order not to update all pixels within the texture - only the modified ones.

It works as I intended when the color has an alpha (a) > 0 .. but not when it is 0 (it is like the pixel is rendered on top of the existing texture .. and not like you are modifying the actual pixel data).

Am I doing something wrong? Or is this the intended behaviour?

From the SKMutableTexture documentation,

The color components you provide should have already been multiplied by the alpha value.

Normally, if you wanted a color that is red with an alpha of 0.5, you would use RGBA components

(red:1.0, green:0.0, blue:0.0, alpha:0.5)

The equivalent for a premultiplied-alpha color is

(red:0.5, green:0.0, blue:0.0, alpha:0.5)

where the RGB components have been multiplied by the alpha value.

For your specific case, you can add an initializer to the Color structure to perform the multiplication. Here's one way implement that...

First, define an extension to scale a UInt8 by a Float value by

extension UInt8 {
    func scaled(by value:Float) -> UInt8 {
        var scale = UInt(round(Float(self) * value))
        scale = Swift.min(scale, UInt(UInt8.max))
        return UInt8(scale)
    }
}

and then add an initializer that automatically multiples the components by the alpha value

struct Color {
    var red:UInt8
    var green:UInt8
    var blue:UInt8
    var alpha:UInt8

    init(red:UInt8,green:UInt8,blue:UInt8,alpha:UInt8) {
        let alphaScale = Float(alpha) / Float(UInt8.max)
        self.red = red.scaled(by: alphaScale)
        self.blue = blue.scaled(by: alphaScale)
        self.green = green.scaled(by: alphaScale)
        self.alpha = alpha
    }
}

You can then create a color that is red with alpha = 0.5 by

let color = Color(red:255, green:0, blue:0, alpha:127)

and a completely transparent color with

let color = Color(red:255, green:0, blue:0, alpha:0)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM