gpt4 book ai didi

scenekit - 将 Metal 缓冲区传递给 SceneKit 着色器

转载 作者:行者123 更新时间:2023-12-04 16:13:55 26 4
gpt4 key购买 nike

我想使用 Metal 计算着色器来计算一些位置,然后将这些位置输入到 Metal 着色器中。听起来很简单,但我无法将 MTLBuffer 数据导入基于 Metal 的 SCNProgram。

计算内核如下,在这个人为的示例中,它采用三个 3D 向量(在两个缓冲区中)。

kernel void doSimple(const device float3 *inVector [[ buffer(0) ]],
device float3 *outVector [[ buffer(1) ]],
uint id [[ thread_position_in_grid ]]) {

float yDisplacement = 0;
. . . .

outVector[id] = float3(
inVector[id].x,
inVector[id].y + yDisplacement,
inVector[id].z);
}

此核函数在 - renderer:willRenderScene:atTime: 中的每一帧运行。我的方法 SCNSceneRendererDelegate .有两个缓冲区,它们在每一帧后切换。

缓冲区创建如下;
func setupBuffers() {
positions = [vector_float3(0,0,0), vector_float3(1,0,0), vector_float3(2,0,0)]

let bufferSize = sizeof(vector_float3) * positions.count
//copy same data into two different buffers for initialisation
buffer1 = device.newBufferWithBytes(&positions, length: bufferSize, options: .OptionCPUCacheModeDefault)
buffer2 = device.newBufferWithBytes(&positions, length: bufferSize, options: .OptionCPUCacheModeDefault)
}

并且计算着色器使用以下命令运行(在 willRenderScene 函数中);
    let computeCommandBuffer = commandQueue.commandBuffer()
let computeCommandEncoder = computeCommandBuffer.computeCommandEncoder()

computeCommandEncoder.setComputePipelineState(pipelineState)
computeCommandEncoder.setBuffer(buffer1, offset: 0, atIndex: 0)
computeCommandEncoder.setBuffer(buffer2, offset: 0, atIndex: 1)

computeCommandEncoder.dispatchThreadgroups(numThreadgroups, threadsPerThreadgroup: threadsPerGroup)
computeCommandEncoder.endEncoding()
computeCommandBuffer.commit()
computeCommandBuffer.waitUntilCompleted()

let bufferSize = positions.count*sizeof(vector_float3)
var data = NSData(bytesNoCopy: buffer2.contents(), length: bufferSize, freeWhenDone: false)
var resultArray = [vector_float3](count: positions.count, repeatedValue: vector_float3(0,0,0))
data.getBytes(&resultArray, length:bufferSize)

for outPos in resultArray {
print(outPos.x, ", ", outPos.y, ", ", outPos.z)
}

这可行,我可以看到我的计算着色器正在更新数组中每个向量的 y 坐标。

这个场景由三个均匀分布的球体组成。顶点着色器简单地获取在计算着色器中计算的位置并将其添加到每个顶点位置(无论如何都是 y 分量)。我给每个球体一个索引,顶点着色器使用这个索引从我的计算数组中拉出适当的位置。

Metal 顶点函数如下所示,它由 SCNProgram 引用并设置为每个球体的 Material 。
vertex SimpleVertex simpleVertex(SimpleVertexInput in [[ stage_in ]],
constant SCNSceneBuffer& scn_frame [[buffer(0)]],
constant MyNodeBuffer& scn_node [[buffer(1)]],
constant MyPositions &myPos [[buffer(2)]],
constant uint &index [[buffer(3)]]
)
{

SimpleVertex vert;
float3 posOffset = myPos.positions[index];
float3 pos = float3(in.position.x,
in.position.y + posOffset.y,
in.position.z);

vert.position = scn_node.modelViewProjectionTransform * float4(pos,1.0);

return vert;
}
MyPositions是一个包含 float3s 数组的简单结构。
struct MyPositions
{
float3 positions[3];
};

使用 setValue 将数据传递给顶点着色器没有问题每个球体 Material 的方法如下所示(也在 willRenderScene 方法中完成)。一切都按预期工作(三个球体向上移动)。
    var i0:UInt32 = 0
let index0 = NSData(bytes: &i0, length: sizeof(UInt32))
sphere1Mat.setValue(index0, forKey: "index")
sphere1Mat.setValue(data, forKey: "myPos")

但是 这需要将数据从 GPU 复制到 CPU 再到 GPU,这确实是我宁愿避免的事情。所以我的问题是... 如何将 MTLBuffer 传递给 SCNProgram?

已在 willRenderScene 中尝试过以下操作但除了 EXEC_BAD... 什么都得不到
let renderCommandEncoder = renderer.currentRenderCommandEncoder!
renderCommandEncoder.setVertexBuffer(buffer2, offset: 0, atIndex: 2)
renderCommandEncoder.endEncoding()

完成 example is over on GitHub .

感谢阅读,一直在努力解决这个问题。解决方法是使用 MTLTexture 代替 MTLBuffer,因为我已经能够通过漫反射垫 Prop 将它们传递到 SCNProgram。

最佳答案

只需一步一步地切换缓冲区的绑定(bind)。

第1步
computeCommandEncoder.setBuffer(buffer1, offset: 0, atIndex: 0 )
computeCommandEncoder.setBuffer(buffer2, offset: 0, atIndex: 1 )

第2步
computeCommandEncoder.setBuffer(buffer1, offset: 0, atIndex: 1 )
computeCommandEncoder.setBuffer(buffer2, offset: 0, atIndex: 0 )

第三步
computeCommandEncoder.setBuffer(buffer1, offset: 0, atIndex: 0 )
computeCommandEncoder.setBuffer(buffer2, offset: 0, atIndex: 1 )

等等 ...

输出缓冲区成为新的缓冲区,反之亦然...

关于scenekit - 将 Metal 缓冲区传递给 SceneKit 着色器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33541922/

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