Nil*_*sen 5 shader compute-shader swift metal metalkit
我想使用计算着色器来修改我的顶点,然后将它们传递给顶点着色器.我找不到任何这样的例子或解释,除了这里似乎提到:金属模拟使用计算着色器的几何着色器.这对我没有帮助,因为它没有解释它的CPU部分.
我已经看过许多在计算着色器中读取和写入纹理缓冲区的示例,但我需要读取和修改顶点缓冲区,其中包含带法线的自定义顶点结构,并由MDLMesh创建.我将永远感谢一些示例代码!
背景
我真正想要实现的是能够修改GPU上的顶点法线.另一种选择是,如果我可以从顶点着色器访问整个三角形,就像在链接的答案中一样.出于某种原因,我只能使用stage_in属性访问单个顶点.在这种特殊情况下,使用整个缓冲区对我来说不起作用,这可能与使用Model I/O和MDLMesh提供的网格有关.当我手动创建顶点时,我能够访问顶点缓冲区数组.话虽如此,使用该解决方案,我将不得不为每个三角形计算新的顶点法线向量三次,这似乎是浪费,并且无论如何我希望能够将计算着色器应用于顶点缓冲区!
感谢肯·托马斯的评论,我设法找到了解决方案。他让我意识到这很简单:
我使用的顶点结构如下所示:
// Metal side
struct Vertex {
float4 position;
float4 normal;
float4 color;
};
// Swift side
struct Vertex {
var position: float4
var normal: float4
var color: float4
}
Run Code Online (Sandbox Code Playgroud)
在设置过程中,我通常创建顶点缓冲区、索引缓冲区和渲染管道状态,现在我还创建计算管道状态:
// Vertex buffer
let dataSize = vertexData.count*MemoryLayout<Vertex>.stride
vertexBuffer = device.makeBuffer(bytes: vertexData, length: dataSize, options: [])!
// Index buffer
indexCount = indices.count
let indexSize = indexCount*MemoryLayout<UInt16>.stride
indexBuffer = device.makeBuffer(bytes: indices, length: indexSize, options: [])!
// Compute pipeline state
let adjustmentFunction = library.makeFunction(name: "adjustment_func")!
cps = try! device.makeComputePipelineState(function: adjustmentFunction)
// Render pipeline state
let rpld = MTLRenderPipelineDescriptor()
rpld.vertexFunction = library.makeFunction(name: "vertex_func")
rpld.fragmentFunction = library.makeFunction(name: "fragment_func")
rpld.colorAttachments[0].pixelFormat = .bgra8Unorm
rps = try! device.makeRenderPipelineState(descriptor: rpld)
commandQueue = device.makeCommandQueue()!
Run Code Online (Sandbox Code Playgroud)
然后我的渲染函数如下所示:
let black = MTLClearColor(red: 0, green: 0, blue: 0, alpha: 1)
rpd.colorAttachments[0].texture = drawable.texture
rpd.colorAttachments[0].clearColor = black
rpd.colorAttachments[0].loadAction = .clear
let commandBuffer = commandQueue.makeCommandBuffer()!
let computeCommandEncoder = commandBuffer.makeComputeCommandEncoder()!
computeCommandEncoder.setComputePipelineState(cps)
computeCommandEncoder.setBuffer(vertexBuffer, offset: 0, index: 0)
computeCommandEncoder.dispatchThreadgroups(MTLSize(width: meshSize*meshSize, height: 1, depth: 1), threadsPerThreadgroup: MTLSize(width: 4, height: 1, depth: 1))
computeCommandEncoder.endEncoding()
let renderCommandEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: rpd)!
renderCommandEncoder.setRenderPipelineState(rps)
renderCommandEncoder.setFrontFacing(.counterClockwise)
renderCommandEncoder.setCullMode(.back)
updateUniforms(aspect: Float(size.width/size.height))
renderCommandEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
renderCommandEncoder.setVertexBuffer(uniformBuffer, offset: 0, index: 1)
renderCommandEncoder.setFragmentBuffer(uniformBuffer, offset: 0, index: 1)
renderCommandEncoder.drawIndexedPrimitives(type: .triangle, indexCount: indexCount, indexType: .uint16, indexBuffer: indexBuffer, indexBufferOffset: 0)
renderCommandEncoder.endEncoding()
commandBuffer.present(drawable)
commandBuffer.commit()
Run Code Online (Sandbox Code Playgroud)
最后我的计算着色器如下所示:
kernel void adjustment_func(const device Vertex *vertices [[buffer(0)]], uint2 gid [[thread_position_in_grid]]) {
vertices[gid.x].position = function(pos.xyz);
}
Run Code Online (Sandbox Code Playgroud)
这是我的顶点函数的签名:
vertex VertexOut vertex_func(const device Vertex *vertices [[buffer(0)]], uint i [[vertex_id]], constant Uniforms &uniforms [[buffer(1)]])
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
297 次 |
| 最近记录: |