我有一个SCNVector3
数组,每个顶点一个。
var terrainArray = [SCNVector3]()
我需要在片段着色器的每个顶点提供此数据。像这样:
struct TerrainVertexInput
{
float3 position [[attribute(SCNVertexSemanticPosition)]];
float4 color [[attribute(SCNVertexSemanticColor)]];
};
struct TerrainVertexOutput
{
float4 position [[position]];
float3 terrain;
float4 color;
};
vertex TerrainVertexOutput terrainVertex(TerrainVertexInput in [[stage_in]],
constant SCNSceneBuffer& scn_frame [[buffer(0)]],
constant MyNodeBuffer& scn_node [[buffer(1)]],
constant float3 terrain [[buffer(2)]])
{
TerrainVertexOutput v;
v.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0);
v.terrain = terrain;
v.color = in.color;
return v;
}
据我了解,我需要使用数组数据创建Data
对象,并将其提供给setValue(_:forKey:)
进行编程,但是我不确定顶点函数是否会为顶点获取正确的元素。
如何正确执行此操作?
答案 0 :(得分:0)
您处在正确的轨道上,但是您不想使用SCNVector3
来传递到Metal着色器中的数据。 SceneKit的矢量类型具有CGFloat
类型的组件,其大小取决于平台。
相反,您的数据应使用simd向量类型之一。在Swift和Metal中,这表示float3
或float4
。请注意,float3
实际上占用了16个字节的空间;末尾有一个虚拟元素用于对齐目的。如果要紧密打包数据,每个顶点使用3个浮点数,则可以在Metal中以packed_float3
的形式键入缓冲区,并为每个顶点将3个连续的浮点数写入数据缓冲区。 Swift中没有三元素压缩浮点向量类型。
有很多方法可以将SCNVector3
数组复制到适当类型的数据缓冲区中。这是一个:
// Allocate enough memory to store three floats per vertex, ensuring we free it later
let terrainBuffer = UnsafeMutableBufferPointer<Float>.allocate(capacity: terrainArray.count * 3)
defer {
terrainBuffer.deallocate()
}
// Copy each element of each vector into the buffer
terrainArray.enumerated().forEach { i, v in
terrainBuffer[i * 3 + 0] = Float(v.x)
terrainBuffer[i * 3 + 1] = Float(v.y)
terrainBuffer[i * 3 + 2] = Float(v.z)
}
// Copy the buffer data into a Data object, as expected by SceneKit
let terrainData = Data(buffer: terrainBuffer)
然后可以在几何图形或材质上使用setValue(:forKey:)
:
material.setValue(terrainData, forKey: "terrain")
与其在顶点函数中不使用单个float3
作为参数,而是将一个{em> pointer 指向packed_float3
并根据顶点ID对其进行索引:>
vertex TerrainVertexOutput terrainVertex(TerrainVertexInput in [[stage_in]],
constant SCNSceneBuffer& scn_frame [[buffer(0)]],
constant MyNodeBuffer& scn_node [[buffer(1)]],
constant packed_float3 *terrain [[buffer(2)]],
uint vid [[vertex_id]]) {
// ...
v.terrain = terrain[vid];
// ...
}
这假定几何图形中的顶点与terrain数据点之间存在确切的对应关系。当然,除了直接使用顶点ID外,您还可以执行任何形式的花式索引操作,以查找给定顶点的地形数据。