2015-04-23 26 views
5

Podczas korzystania z Apple's texture importer, lub moje własne, białe kółko o miękkim brzegu rysowane w oprogramowaniu (z przezroczystym bg) lub w Photoshopie (zapisane jako PNG), gdy renderowane półprzezroczyste kolory zostaną zastąpione czarnymi po wprowadzeniu do metalu.Metal MTLTexture zastępuje półprzezroczyste obszary kolorem czarnym, gdy wartości alfa nie są równe 1 lub 0

Poniżej znajduje się zrzut ekranu z debuggera Metal Xcode, możesz zobaczyć teksturę przed wysłaniem do shaderów.

Image located here (I'm not high ranked enough to embed)

w Xcode, celownik, a gdy umieścić w UIImageView, tekstury źródło nie posiada pierścień. Ale gdzieś wzdłuż procesu UIImage -> CGContex -> MTLTexture (myślę szczególnie o części MTLTexture) sekcje tranparentne są przyciemnione.

Uderzyłem głową w ścianę, zmieniając wszystko, co mogłem przez kilka ostatnich dni, ale nie mogę tego rozgryźć.

Aby być przejrzyste (ha), tu jest mój osobisty kod import

import UIKit 
import CoreGraphics 

class MetalTexture { 

    class func imageToTexture(imageNamed: String, device: MTLDevice) -> MTLTexture { 
     let bytesPerPixel = 4 
     let bitsPerComponent = 8 

     var image = UIImage(named: imageNamed)! 

     let width = Int(image.size.width) 
     let height = Int(image.size.height) 
     let bounds = CGRectMake(0, 0, CGFloat(width), CGFloat(height)) 

     var rowBytes = width * bytesPerPixel 
     var colorSpace = CGColorSpaceCreateDeviceRGB() 

     let context = CGBitmapContextCreate(nil, width, height, bitsPerComponent, rowBytes, colorSpace, CGBitmapInfo(CGImageAlphaInfo.PremultipliedLast.rawValue)) 

     CGContextClearRect(context, bounds) 
     CGContextTranslateCTM(context, CGFloat(width), CGFloat(height)) 
     CGContextScaleCTM(context, -1.0, -1.0) 
     CGContextDrawImage(context, bounds, image.CGImage) 

     var texDescriptor = MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.RGBA8Unorm, width: width, height: height, mipmapped: false) 

     var texture = device.newTextureWithDescriptor(texDescriptor) 
     texture.label = imageNamed 

     var pixelsData = CGBitmapContextGetData(context) 

     var region = MTLRegionMake2D(0, 0, width, height) 
     texture.replaceRegion(region, mipmapLevel: 0, withBytes: pixelsData, bytesPerRow: rowBytes) 

     return texture 
    } 
} 

Ale nie sądzę, że jest problem (ponieważ jest to kopia Apple w Swift i użyłem ich kompetencji zamiast bez różnic).

Dowolne przewody w ogóle będą bardzo pomocne.

+0

To nie jest tak naprawdę "czarne", widzisz. Jest biały, pomnożony przez kanał alfa obrazu, dwukrotnie, z tłem pomnożonym przez odwrotność alfa i dodanym do wyniku. Pomyślałem, że CGImageAlphaInfo.Last rozwiąże problem, ale nie zostanie zaimplementowany na sprzęcie. Czy możesz wdrożyć premilpowane miksowanie alfa, dopóki nie dowiemy się, jak uzyskać nieprzemnożone dane? – Jessy

+1

Aha! Poprowadziłeś mnie właściwą drogą. Zamieszczam teraz moją odpowiedź. –

Odpowiedz

2

Dzięki Jessy postanowiłem przejrzeć, jak łączę moje alfy i udało mi się to ustalić. Moja tekstura nadal wygląda ciemniej w debugerze GPU, ale w samej aplikacji wszystko wygląda poprawnie. Wprowadziłem zmiany do mojego deskryptora stanu potoku, który można zobaczyć poniżej.

pipelineStateDescriptor.colorAttachments[0].blendingEnabled = true 
pipelineStateDescriptor.colorAttachments[0].rgbBlendOperation = .Add 
pipelineStateDescriptor.colorAttachments[0].alphaBlendOperation = .Add 
pipelineStateDescriptor.colorAttachments[0].sourceRGBBlendFactor = .DestinationAlpha 
pipelineStateDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .DestinationAlpha 
pipelineStateDescriptor.colorAttachments[0].destinationRGBBlendFactor = .OneMinusSourceAlpha 
pipelineStateDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .OneMinusBlendAlpha 
1

Ponieważ używasz CGContext który jest skonfigurowany do korzystania kolory premultiplied z kanałem alfa, przy użyciu standardowego RGB = src.rgb * src.a + dst.rgb * (1-src.a) spowoduje zaciemnione obszary ponieważ wartości src.rgbpremultiplied z już src.a. Oznacza to, że to, co chcesz, jest src.rgb + dst.rgb * (1-src.a) który jest skonfigurowany tak:

pipeline.colorAttachments[0].isBlendingEnabled = true 
pipeline.colorAttachments[0].rgbBlendOperation = .add 
pipeline.colorAttachments[0].alphaBlendOperation = .add 
pipeline.colorAttachments[0].sourceRGBBlendFactor = .one 
pipeline.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha 
pipeline.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha 
pipeline.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha 

.one oznacza opuścić RGB jak jest. Powodem wstępnego pomnożenia kolorów jest to, że wystarczy pomnożyć kolory tylko raz podczas tworzenia, w przeciwieństwie do każdego mieszania. Twoja konfiguracja również to osiąga, ale pośrednio.