2017-09-07 17 views
1

저는 금속으로 라이브 필터를 적용 할 때 texture2d_array를 사용하려고했습니다. 그러나 나는 적절한 결과를 얻지 못하고있다. Class MetalTextureArray :metal에서 texture2d_array 배열을 사용하는 방법은 무엇입니까?

임은이 같은 텍스처 배열,

코드를 생성.

class MetalTextureArray { 
private(set) var arrayTexture: MTLTexture 
private var width: Int 
private var height: Int 

init(_ width: Int, _ height: Int, _ arrayLength: Int, _ device: MTLDevice) { 
    self.width = width 
    self.height = height 

    let textureDescriptor = MTLTextureDescriptor() 

    textureDescriptor.textureType = .type2DArray 
    textureDescriptor.pixelFormat = .bgra8Unorm 
    textureDescriptor.width = width 
    textureDescriptor.height = height 
    textureDescriptor.arrayLength = arrayLength 

    arrayTexture = device.makeTexture(descriptor: textureDescriptor) 
} 

func append(_ texture: MTLTexture) -> Bool { 
    if let bytes = texture.buffer?.contents() { 
     let region = MTLRegion(origin: MTLOrigin(x: 0, y: 0, z: 0), size: MTLSize(width: width, height: height, depth: 1)) 

     arrayTexture.replace(region: region, mipmapLevel: 0, withBytes: bytes, bytesPerRow: texture.bufferBytesPerRow) 

     return true 
    } 

    return false 
} 

}

임 인코딩이 같은 renderEncoder에이 질감,

코드 :

let textureArray = MetalTextureArray.init(firstTexture!.width, firstTexture!.height, colorTextures.count, device) 

     _ = textureArray.append(colorTextures[0].texture) 
     _ = textureArray.append(colorTextures[1].texture) 
     _ = textureArray.append(colorTextures[2].texture) 
     _ = textureArray.append(colorTextures[3].texture) 
     _ = textureArray.append(colorTextures[4].texture) 

     renderEncoder.setFragmentTexture(textureArray.arrayTexture, at: 1) 

마지막으로 나는이 같은 조각 쉐이더에서 texture2d_array에 접근하고있어,

코드 :

I는 텍스처 배열에 추가하고있어 3,691,363,210
struct RasterizerData { 
    float4 clipSpacePosition [[position]]; 
    float2 textureCoordinate; 

}; 

    multipleShader(RasterizerData in [[stage_in]], 
       texture2d<half> colorTexture [[ texture(0) ]], 
       texture2d_array<half> texture2D [[ texture(1) ]]) 
{ 
    constexpr sampler textureSampler (mag_filter::linear, 
             min_filter::linear, 
             s_address::repeat, 
             t_address::repeat, 
             r_address::repeat); 

    // Sample the texture and return the color to colorSample 

    half4 colorSample = colorTexture.sample (textureSampler, in.textureCoordinate); 

    float4 outputColor; 

    half red = texture2D.sample(textureSampler, in.textureCoordinate, 2).r; 
    half green = texture2D.sample(textureSampler, in.textureCoordinate, 2).g; 
    half blue = texture2D.sample(textureSampler, in.textureCoordinate, 2).b; 

    outputColor = float4(colorSample.r * red, colorSample.g * green, colorSample.b * blue, colorSample.a); 

    // We return the color of the texture 
    return outputColor; 
} 

텍스쳐는 I 2로 마지막 인자 준 코드 half red = texture2D.sample(textureSampler, in.textureCoordinate, 2).r;에서 사이즈 256 * 1

이다 ACV 곡선 파일로부터 추출 된 텍스처 때문에 나는 그것을 접근 할 텍스쳐의 인덱스라고 생각했다. 그러나 나는 그것이 무엇을 의미하는지 모른다.

그러나이 모든 작업을 수행 한 후에 검은 색 화면이 나타납니다. 심지어 다른 조각 쉐이더도 있고 모두 잘 작동합니다. 하지만이 조각 셰이더에 검은 화면이 나타납니다. 나는이 코드 half blue = texture2D.sample(textureSampler, in.textureCoordinate, 2).b에 대해 모든 빨강, 초록 및 파랑 값에 대해 0을 얻고 있다고 생각합니다.

편집 1 :

으로 나는 질감과 여전히 결과를 복사 blitcommandEncoder을 사용 제안했다.

내 코드가 여기에 표시됩니다

,

내 MetalTextureArray 클래스는 수정왔다.

메소드 추가가 이렇게됩니다.

func append(_ texture: MTLTexture) -> Bool { 
    self.blitCommandEncoder.copy(from: texture, sourceSlice: 0, sourceLevel: 0, sourceOrigin: MTLOrigin(x: 0, y: 0, z: 0), sourceSize: MTLSize(width: texture.width, height: texture.height, depth: 1), to: self.arrayTexture, destinationSlice: count, destinationLevel: 0, destinationOrigin: MTLOrigin(x: 0, y: 0, z: 0)) 
    count += 1 
    return true 
} 

그리고 임이

let textureArray = MetalTextureArray.init(256, 1, colorTextures.count, device, blitCommandEncoder: blitcommandEncoder) 
for (index, filter) in colorTextures!.enumerated() { 
    _ = textureArray.append(colorTextures[index].texture) 
} 
renderEncoder.setFragmentTexture(textureArray.arrayTexture, at: 1) 

내 쉐이더 코드와 같은 질감을 추가이

multipleShader(RasterizerData in [[stage_in]], 
       texture2d<half> colorTexture [[ texture(0) ]], 
       texture2d_array<float> textureArray [[texture(1)]], 
       const device struct SliceDataSource &sliceData [[ buffer(2) ]]) 
{ 
    constexpr sampler textureSampler (mag_filter::linear, 
             min_filter::linear); 

    // Sample the texture and return the color to colorSample 
    half4 colorSample = colorTexture.sample (textureSampler, in.textureCoordinate); 

    float4 outputColor = float4(0,0,0,0); 

    int slice = 1; 


float red = textureArray.sample(textureSampler, in.textureCoordinate, slice).r; 
float blue = textureArray.sample(textureSampler, in.textureCoordinate, slice).b; 
float green = textureArray.sample(textureSampler, in.textureCoordinate, slice).g; 

outputColor = float4(colorSample.r * red, colorSample.g * green, colorSample.b * blue, colorSample.a); 

    // We return the color of the texture 
    return outputColor; 
} 

아직도 나는 검은 화면을 얻을처럼 간다.

textureArray.sample(textureSampler, in.textureCoordinate, slice); 메서드에서 세 번째 매개 변수는 무엇입니까? 나는 그것을 색인으로 사용하고 임의의 텍스쳐를 가져 오기 위해 임의의 색인을 주었다. 맞습니까?

편집 2 :

나는 마지막으로 수 제안을 구현하고 나는 다른 인코더를 구현하고 나는 ACV 부정적인 필터와 함께 다음과 같은 화면을 가지고 전에 endEncoding 방법을 사용하여 결과를 얻었다.

enter image description here.

누군가 나를 제안 할 수 있습니까?

감사합니다.

답변

1

텍스처 배열과 배열 텍스처간에 차이가 있습니다. 당신에게 텍스처 배열을 원하는 것처럼 들리는군요. 이 경우 texture2d_array을 사용하면 안됩니다. array<texture2d<half>, 5> texture_array [[texture(1)]]을 사용해야합니다.

setFragmentTexture()에 대한 호출을 여러 번 사용하여 순차 색인에 질감을 할당하거나 setFragmentTextures()을 사용하여 일련의 질감을 한꺼번에 색인의 범위에 할당 할 수 있습니다.

셰이더 코드에서 배열 첨자 구문을 사용하여 배열의 개별 텍스처를 참조 할 수 있습니다 (예 : texture_array[2]).

배열 텍스처를 실제로 사용하려면 append() 메서드를 변경해야 할 수 있습니다. 먼저 makeTexture(descriptor:offset:bytesPerRow:) 메서드가 MTLBuffertexture 인수가 생성되지 않은 경우 texture.buffer은 항상 nil이됩니다. 즉, 텍스처가 원래 버퍼에서 만들어진 경우에만 텍스처가 연결됩니다. 텍스처에서 텍스처로 복사하려면 blit 명령 인코더와 그 copy(from:sourceSlice:sourceLevel:sourceOrigin:sourceSize:to:destinationSlice:destinationLevel:destinationOrigin:) 메서드를 사용해야합니다.

둘째, 배열 텍스처의 특정 슬라이스 (배열 요소)에 대한 텍스처 데이터를 바꾸려면 해당 슬라이스 인덱스를 replace() 메서드의 인수로 전달해야합니다. 이를 위해서는 현재 replace(region:mipmapLevel:withBytes:bytesPerRow:)이 아니라 replace(region:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:) 방법을 사용해야합니다. 현재 코드는 첫 번째 슬라이스를 반복하여 (소스 텍스처가 실제로 버퍼와 연결되었다고 가정 할 때) 계속해서 대체합니다.

+0

''constant array , 5> texture_array [[texture (1)]]'을 사용했지만'Uknown type array' 오류가 발생했습니다. 사실 나는 그것을 전에 사용하려고했지만'texture2d_array'를 사용하게하는 같은 오류가 발생했습니다. 왜 이것이이 오류를 내고 있는지 제안 해 주시겠습니까? 컴파일러 때문인가요? 그리고 한 가지 더, 텍스처를'UnsafeMutablePointer'로 변환하는 방법을 알 수 있습니까? –

+0

어떤 SDK 및 배포 대상을 사용하고 있습니까? 타겟 빌드 설정의 경우 Metal 언어 개정판은 무엇입니까? 텍스처 배열은 GPU 제품군 3 이상 (MacOS 10.13 이상)의 iOS 10 이상에서만 사용할 수 있습니다. 어디에서 텍스처를'UnsafeMutablePointer'로 변환하고 싶습니까? 'setFragmentTextures()'를 생각하고 있다면 Swift 배열이나 텍스처를 전달하면 변환이 자동으로 처리됩니다. –

+0

iOS 9를 지원하려고합니다. 따라서 조각 쉐이더 내부에 텍스처와 같은 배열을 사용할 수 있습니다. 그리고'arrayTexture.replace (region : region, mipmapLevel : 0, slice : 4, withBytes : bytes, bytesPerRow : texture.bufferBytesPerRow, bytesPerImage : texture.bufferBytesPerRow * texture '메서드에서 텍스처를'UnsafeMutablePointer'로 변환하려고합니다. .height)'withBytes 인자는'UnsafeMutablePointer'를 기대하기 때문에. 그럼 나 한테 제안 해 줄래? –