2017-10-31 32 views
3

나는 iOS/OSX 용 메탈을 배우기 시작했고, 나는 레이 웬델 리치 (Ray Wenderlich) 튜토리얼 (https://www.raywenderlich.com/146414/metal-tutorial-swift-3-part-1-getting-started)을 따라 시작했다. 이 자습서는 잘 작동하지만 MTLVertexAttributeDescriptors에 대한 언급이 없습니다.MTLVertexAttributeDescriptors가 필요합니까? 왜 그들이 필요합니까?

이제 내 자신의 앱을 개발하고 있는데 이상한 결함이 생기고 MTLVertexAttributeDescriptors를 사용하지 않는다는 사실이 문제와 관련이 있는지 궁금해하고 있습니다.

그들은 어떤 차이가 있습니까? 다양한 버텍스 구조를 가진 다양한 쉐이더를 만들 수 있었고 이런 것들을 전혀 알지 못했습니다.

셰이더에서 사용하기 위해 꼭지점 구성 요소의 레이아웃을 설명하는 데 사용하는 것으로 알고 있습니다. 예를 들어 셰이더는이 구조체를 정점에 사용할 수 있으며, 아래 기능의 정점 설명자에 설정됩니다.

typedef struct 
{ 
    float3 position [[attribute(T_VertexAttributePosition)]]; 
    float2 texCoord [[attribute(T_VertexAttributeTexcoord)]]; 
} Vertex; 

class func buildMetalVertexDescriptor() -> MTLVertexDescriptor { 

    let mtlVertexDescriptor = MTLVertexDescriptor() 

    mtlVertexDescriptor.attributes[T_VertexAttribute.position.rawValue].format = MTLVertexFormat.float3 
    mtlVertexDescriptor.attributes[T_VertexAttribute.position.rawValue].offset = 0 
    mtlVertexDescriptor.attributes[T_VertexAttribute.position.rawValue].bufferIndex = T_BufferIndex.meshPositions.rawValue 

    mtlVertexDescriptor.attributes[T_VertexAttribute.texcoord.rawValue].format = MTLVertexFormat.float2 
    mtlVertexDescriptor.attributes[T_VertexAttribute.texcoord.rawValue].offset = 0 
    mtlVertexDescriptor.attributes[T_VertexAttribute.texcoord.rawValue].bufferIndex = T_BufferIndex.meshGenerics.rawValue 

    mtlVertexDescriptor.layouts[T_BufferIndex.meshPositions.rawValue].stride = 12 
    mtlVertexDescriptor.layouts[T_BufferIndex.meshPositions.rawValue].stepRate = 1 
    mtlVertexDescriptor.layouts[T_BufferIndex.meshPositions.rawValue].stepFunction = MTLVertexStepFunction.perVertex 

    mtlVertexDescriptor.layouts[T_BufferIndex.meshGenerics.rawValue].stride = 8 
    mtlVertexDescriptor.layouts[T_BufferIndex.meshGenerics.rawValue].stepRate = 1 
    mtlVertexDescriptor.layouts[T_BufferIndex.meshGenerics.rawValue].stepFunction = MTLVertexStepFunction.perVertex 

    return mtlVertexDescriptor 
} 

그러나 심지어 MTLVertexDescriptor 설치없이

는 쉐이더 이미 배열 정점의 정점 버퍼 위치/TEXCOORD 요소를 액세스 할 수있다. 정점 버퍼를 설정하는 것만으로 셰이더는 모든 구성 요소에 액세스 할 수 있습니다. 그러면 디스크립터는 어떤 점에서 좋은 점이 있습니까?

답변

3

물론 여러 가지 방법이 있습니다. 정점 기술자는 그 중 하나에 대해서만 사용됩니다.

는 예를 들어, 정점의 기능은 다음과 같이 선언 될 수 있습니다

vertex MyVertexOut vertex_func(device const float3 *positions [[buffer(0)]], 
           device const float2 *texCoords [[buffer(1)]], 
           uint vid [[vertex_id]]) 
{ 
    // use positions[vid] and texCoords[vid] to fill in and return a MyVertexOut structure 
} 

이 정점 속성은 별도의 버퍼에 제공 할 것을 지시, 특정 레이아웃의 각.

당신은 할 수 :

struct MyVertexIn 
{ 
    float3 position; 
    float2 texCoord; 
}; 
vertex MyVertexOut vertex_func(device const MyVertexIn *vertexes [[buffer(0)]], 
           uint vid [[vertex_id]]) 
{ 
    // use vertexes[vid].position and vertexes[vid].texCoord to fill in and return a MyVertexOut structure 
} 

이 정점 속성이 MyVertexIn의 레이아웃을 일치 구조체의 단일 버퍼에 제공 할 것을 지시한다.

위의 어느 것도 버텍스 설명자를 필요로하거나 사용하지 않습니다. 그것은 완전히 부적절합니다.

그러나, 당신은 또한이 작업을 수행 할 수 있습니다

struct MyVertexIn 
{ 
    float3 position [[attribute(0)]]; 
    float2 texCoord [[attribute(1)]]; 
}; 
vertex MyVertexOut vertex_func(MyVertexIn vertex [[stage_in]]) 
{ 
    // use vertex.position and vertex.texCoord to fill in and return a MyVertexOut structure 
} 

주에게 attribute(n)stage_in 속성의 사용을. 이것은 정점 속성이 제공되는 방법을 지정하지 않습니다. 오히려, 버텍스 디스크립터는 하나 이상의 버퍼에서 버텍스 속성으로의 매핑을 설명합니다. 매핑은 변환 및 확장을 수행 할 수도 있습니다. 예를 들어, 위의 셰이더 코드는 필드가 이지만 버퍼에 half3 값 (또는 다양한 다른 유형)을 포함 할 수 있으며 (포함되어 있다고 설명 될 수 있음), Metal은 자동으로 변환을 수행합니다.

동일한 셰이더를 다른 정점 설명자와 함께 사용할 수 있으므로 버퍼 전반에 걸쳐 정점 특성 분포가 다릅니다. 이는 다양한 시나리오에 대한 유연성을 제공합니다. 일부는 정점 속성이 다른 버퍼 (첫 번째 예제와 비슷 함)와 다른 버퍼로 분리되어 있습니다 (두 번째 예제와 유사). 기타

유연성과 추가 수준의 추상화가 필요하지 않으면 꼭지점 설명자를 다룰 필요가 없습니다. 그들은 그것을 필요로하는 사람들을 위해 있습니다.

+0

감사합니다. [[stage_in]] 구문과 [[buffer]] 구문의 차이점에 대해 궁금합니다. 불행히도 이것은 또한 꼭지점 기술자의 부족이 아마도 글리치가 발생하지 않는다는 것을 의미합니다. – bsabiston