gpt4 book ai didi

metal - 如何在 Metal 顶点着色器 MTL 顶点属性描述符中描述 packed_float3?

转载 作者:行者123 更新时间:2023-12-04 14:52:30 24 4
gpt4 key购买 nike

我正在将一个结构数组传递给我的 Metal 着色器顶点函数。该结构如下所示:

struct Vertex {

var x,y,z: Float // position data
var r,g,b,a: Float // color data
var s,t: Float // texture coordinates
var nX,nY,nZ: Float // normal

func floatBuffer() -> [Float] {
return [x,y,z,r,g,b,a,s,t,nX,nY,nZ]
}

};

floatBuffer 函数用于将顶点组装成一个大的 Floats 数组。我可以通过使用使用“打包”数据类型的结构定义将它传递到我的着色器函数中,如下所示:

struct VertexIn {
packed_float3 position;
packed_float4 color;
packed_float2 texCoord;
packed_float3 normal;
};


vertex VertexOut basic_vertex(
const device VertexIn* vertex_array [[ buffer(0) ]],
.
.
.

这行得通。但是,我想知道如何使用 MTLVertexAttributeDescriptors 和相关语法来做同样的事情。现在我得到了损坏的多边形,大概是因为 float3 和 packed_float3 的字节对齐差异?

这就是我现在尝试定义它并获取垃圾多边形的方式。我收到“packed_float3”对属性无效的错误,所以我想弄清楚如何使常规 float3、float4 等工作。

struct VertexIn {
float3 position [[attribute(RayVertexAttributePosition)]];
float4 color [[attribute(RayVertexAttributeColor)]];
float2 texCoord [[attribute(RayVertexAttributeTexCoord)]];
float3 normal [[attribute(RayVertexAttributeNormal)]];
};

class func buildMetalVertexDescriptor() -> MTLVertexDescriptor {

let mtlVertexDescriptor = MTLVertexDescriptor()
var offset = 0

mtlVertexDescriptor.attributes[RayVertexAttribute.position.rawValue].format = MTLVertexFormat.float3
mtlVertexDescriptor.attributes[RayVertexAttribute.position.rawValue].offset = offset
mtlVertexDescriptor.attributes[RayVertexAttribute.position.rawValue].bufferIndex = RayBufferIndex.positions.rawValue
offset += 3*MemoryLayout<Float>.stride

mtlVertexDescriptor.attributes[RayVertexAttribute.color.rawValue].format = MTLVertexFormat.float4
mtlVertexDescriptor.attributes[RayVertexAttribute.color.rawValue].offset = offset
mtlVertexDescriptor.attributes[RayVertexAttribute.color.rawValue].bufferIndex = RayBufferIndex.positions.rawValue
offset += MemoryLayout<float4>.stride

mtlVertexDescriptor.attributes[RayVertexAttribute.texCoord.rawValue].format = MTLVertexFormat.float2
mtlVertexDescriptor.attributes[RayVertexAttribute.texCoord.rawValue].offset = offset
mtlVertexDescriptor.attributes[RayVertexAttribute.texCoord.rawValue].bufferIndex = RayBufferIndex.positions.rawValue
offset += MemoryLayout<float2>.stride

mtlVertexDescriptor.attributes[RayVertexAttribute.normal.rawValue].format = MTLVertexFormat.float3
mtlVertexDescriptor.attributes[RayVertexAttribute.normal.rawValue].offset = offset
mtlVertexDescriptor.attributes[RayVertexAttribute.normal.rawValue].bufferIndex = RayBufferIndex.positions.rawValue
offset += 3*MemoryLayout<Float>.stride

print("stride \(offset)")
mtlVertexDescriptor.layouts[RayBufferIndex.positions.rawValue].stride = offset
mtlVertexDescriptor.layouts[RayBufferIndex.positions.rawValue].stepRate = 1
mtlVertexDescriptor.layouts[RayBufferIndex.positions.rawValue].stepFunction = MTLVertexStepFunction.perVertex


return mtlVertexDescriptor
}

请注意,我将第一个属性指定为 float3,但我指定了 3 个 float 的偏移量,而不是 float3 通常使用的 4 个 float 。但显然这还不够。我想知道如何设置 MTLVertexDescriptor 和带有属性的着色器结构,以便它处理来 self 的结构的“打包”数据?

非常感谢。

最佳答案

关键在于您问题的这一部分:“请注意,我将第一个属性指定为 float3,但我指定了 3 个 float 的偏移量,而不是 float3 通常使用的 4 个 float ”。

SIMD float3 类型占用 16 个字节,它与非打包的 Metal float3 类型具有相同的内存布局。因此,当您将偏移量设置为仅 3*MemoryLayout.stride 时,您会丢失仍然存在的最后 4 个字节,从而导致下一个字段从这些额外字节中提取并偏移其余数据。

要真正使用打包类型将数据传输到 Metal(或任何图形 API),您要么必须坚持之前所做的并在数组中的三个单独的 Floats 中指定 x、y、z,要么必须定义你自己的结构是这样的:

struct Vector3 {
var x: Float
var y: Float
var z: Float
}

Swift 不保证这个结构将是三个 Float 紧密打包在一起,但在现在和可预见的 future 它可以工作,并且在大多数平台上大小为 12 字节。

如果您希望能够对这样的结构进行向量运算,那么我建议您寻找一个定义此类类型的库,以节省您一些时间,因为您也会遇到与 3x3 矩阵相同类型的问题.

我遇到了同样的问题,所以我最终推出了自己的: https://github.com/jkolb/Swiftish

关于metal - 如何在 Metal 顶点着色器 MTL 顶点属性描述符中描述 packed_float3?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47061717/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com