Metal bir gölgelendirici içine beslenen bazı konumların hesaplanması için bir Metal hesaplama gölgelendiricisi kullanmak istiyorum. Düz ileriye doğru geliyor, ancak MTLBuffer veriyi Metal tabanlı SCNProgram'a almakta sorun yaşıyorum.Metal tamponun SceneKit gölgelendiricisine geçilmesi
İşlem çekirdeği şu şekildedir, bu örnekte üç 3B vektörü (her iki arabellekte) çekmektedir.
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);
}
Bu çekirdek fonksiyonu zaman SCNSceneRendererDelegate
arasında - renderer:willRenderScene:atTime:
yönteminde her kare çalıştırılır. İki arabellek var ve her kareden sonra değiştiriliyorlar.
Arabellekler şu şekilde oluşturulur;
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)
}
ve işlem gölgelendirici kullanılarak çalıştırılır (willRenderScene
fonksiyon olarak), aşağıdaki;
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)
}
Bu çalışır ve benim shader miktarı y dizideki her vektörü için koordinat güncelliyor görebilirsiniz.
Bu sahne eşit aralıklı üç küreden oluşur. Köşe gölgelendirici, hesaplama gölgelendiricisinde hesaplanan pozisyonu alır ve her bir köşe konumuna ekler (yine de y bileşenini). Her bir küreye bir indeks verdim, vertex shader, hesaplanmış dizilimden uygun konumu çekmek için bu dizini kullanır.
Metal köşe işlevi aşağıda gösterilmiştir, bir SCNProgram
tarafından başvurulan ve her bir kürenin malzemesine ayarlanmıştır.
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 bir dizi ihtiva eden basit bir yapıdır.
struct MyPositions
{
float3 positions[3];
};
(Ayrıca willRenderScene
yöntemde yapılır), aşağıda gösterildiği gibi, her küre malzeme setValue
yöntemi kullanılarak tepe gölgelendiriciye veri geçen bir sorun vardır. Herşey beklendiği gibi çalışır (üç küre yukarı doğru hareket eder).
var i0:UInt32 = 0
let index0 = NSData(bytes: &i0, length: sizeof(UInt32))
sphere1Mat.setValue(index0, forKey: "index")
sphere1Mat.setValue(data, forKey: "myPos")
AMA bu veri GPU'ya CPU'ya GPU kopyalanan ve gerçekten ben çok önleyeceğini şeydir olması gerekir. Yani benim sorum ... Bir MTLBuffer'ı bir SCNProgram'a nasıl geçirebilirim?
willRenderScene
aşağıdaki çalıştı ama EXEC_BAD...
let renderCommandEncoder = renderer.currentRenderCommandEncoder!
renderCommandEncoder.setVertexBuffer(buffer2, offset: 0, atIndex: 2)
renderCommandEncoder.endEncoding()
Komple example is over on GitHub ama hiçbir şey elde ettiniz.
Okuma için teşekkürler, bununla mücadele ediyorum. Geçici çözüm, bir MTLBuffer yerine bir MTLTexture kullanmaktır, çünkü bunları yaygın bir mat prop üzerinden bir SCNProgram'a aktarabilirim.
ilgi Bunun cevabını bilmek, eğer mümkünse ... Şimdilik, köşe verimi depolamak için bir 'MTLBuffer' tarafından desteklenen bir 'SCNGeometrySource' yaratarak çalıştım. Verilmiş olan vertex verileri, daha sonra hesaplama gölgelendiricisi tarafından doğrudan değiştirilir. Özel bir köşe gölgelendiricisi yoktur ve dolayısıyla bir "MTLBuffer" içinde geçmeye gerek yoktur. – lock