是否需要MTLVertexAttributeDescriptor?为什么需要它们? [英] Are MTLVertexAttributeDescriptors necessary? Why are they needed?

查看:165
本文介绍了是否需要MTLVertexAttributeDescriptor?为什么需要它们?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在学习iOS/OSX的Metal,我首先遵循解决方案

当然,有多种处理方法.顶点描述符仅用于其中之一.

例如,顶点函数可以这样声明:

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属性.这并不决定如何提供顶点属性.而是,顶点描述符描述了从一个或多个缓冲区到顶点属性的映射.该映射还可以执行转换和扩展.例如,上面的着色器代码指定position字段是float3,但是缓冲区可能包含(并被描述为包含)half3值(或各种其他类型),并且Metal将自动进行转换. /p>

同一着色器可与不同的顶点描述符一起使用,因此,顶点属性在缓冲区中的分布不同.这为不同的场景提供了灵活性,其中一些顶点属性被分离到不同的缓冲区中(类似于我给出的第一个示例),而另一些顶点属性被交错在同一个缓冲区中(类似于第二个示例).等等.

如果不需要这种灵活性和额外的抽象级别,则不需要处理顶点描述符.它们在那里是那些确实需要它们的人.

I've been learning Metal for iOS / OSX, and I began by following a Ray Wenderlich tutorial. This tutorial works fine but it makes no mention of MTLVertexAttributeDescriptors.

Now that I'm developing my own app, I'm getting weird glitches and I'm wondering if the fact that I don't use MTLVertexAttributeDescriptors may be related to the problem.

What difference do they make? I've been able to make a variety of shaders with varying vertex structures and I never even knew about these things.

I know you use them to describe the layout of vertex components for use in a shader. For example a shader might use this structure for vertices, and it would be set up in a vertex descriptor in the function below.

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
}

But even without the MTLVertexDescriptor setup, the shader can already access the vertex buffer and the position / texCoord components of vertices in the array. Just by setting the vertex buffer, the shader has access to all of the components. So what good does the descriptor do?

解决方案

There are, of course, multiple ways of doing things. The vertex descriptor is only used for one of them.

For example, a vertex function might be declared like this:

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
}

This dictates that the vertex attributes be supplied in separate buffers, each of a specific layout.

You could also do:

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
}

This dictates that the vertex attributes be supplied in a single buffer of structs matching the layout of MyVertexIn.

Neither of the above require or make use of the vertex descriptor. It's completely irrelevant.

However, you can also do this:

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
}

Note the use of the attribute(n) and stage_in attributes. This does not dictate how the vertex attributes are supplied. Rather, the vertex descriptor describes a mapping from one or more buffers to the vertex attributes. The mapping can also perform conversions and expansions. For example, the shader code above specifies that the position field is a float3 but the buffers may contain (and be described as containing) half3 values (or various other types) and Metal will do the conversion automatically.

The same shader can be used with different vertex descriptors and, thus, different distribution of vertex attributes across buffers. That provides flexibility for different scenarios, some where the vertex attributes are separated out into different buffers (similar to the first example I gave) and others where they're interleaved in the same buffer (similar to the second example). Etc.

If you don't need that flexibility and the extra level of abstraction, then you don't need to deal with vertex descriptors. They're there for those who do need them.

这篇关于是否需要MTLVertexAttributeDescriptor?为什么需要它们?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆