1

我正在尝试用值手动填充一维纹理并将该纹理传递给计算着色器(这些是我想通过代码设置的 2 个像素,它们不代表任何图像)。

由于当前少量的 Metal 示例,我能找到的所有示例都处理通过将加载的字节数据转换为原始字节数据来加载纹理的2D 纹理UIImage,但创建一个虚拟UIImage对象对我来说就像是 hack。

这是我开始的“天真”方式 -

...
var manualTextureData: [Float] = [ 1.0, 0.0, 0.0, 1.0,
                                   0.0, 0.0, 1.0, 1.0 ];
let region: MTLRegion = MTLRegionMake1D(0, textureDescriptor.width);
myTexture.replaceRegion(region, mipmapLevel: 0, withBytes: &manualTextureData, bytesPerRow: 0);

但 Metal 无法识别着色器中的这些值(它得到一个空纹理,第一个值除外)。

我很快意识到 Float 数组可能必须转换为字节数组(例如UInt8),但找不到从任何一个转换[Float]为的[UInt8]方法。

我考虑的另一个可能的选择是使用CVPixelBuffer对象,但这也感觉像是解决问题的方法。

那么解决这个问题的正确方法是什么?

提前致谢。

  • 请注意我不熟悉Objective-C,因此我不确定使用CVPixelBuffer/是否UIImage被夸大了一些应该直截了当的东西。
4

4 回答 4

1

请原谅我简短的回复,但您可能会发现看看我对 Swift 和 Metal 的实验很有用。我在 Swift 中创建了一个粒子系统,它作为粒子结构的一维数组传递给 Metal 计算着色器。通过使用 posix_memalign,我能够消除在 Metal 和 Swift 之间传递数组所造成的瓶颈。

我已经写了很多关于这个的博客:http: //flexmonkey.blogspot.co.uk/search/label/Metal

我希望这有帮助。

西蒙

于 2015-02-13T09:49:40.000 回答
0

我认为您没有任何理由使用 1D 纹理传递数据。相反,我会只传递一个缓冲区。像这样:

var dataBuffer:MTLBuffer? = device.newBufferWithBytes(&manualTextureData, length: sizeOf(manualTextureData), options: MTLResourceOptions.OptionCPUCacheModeDefault)

然后你renderCommandEncoder像这样把它挂在你的身上:

renderCommandEncoder.setFragmentBuffer(dataBuffer, offset: 0, atIndex: 1)//Note that if you want this buffer to be passed to you vertex shader you should use setVertexBuffer

然后在你的着色器中,你应该添加这样的参数const device float* bufferPassed [[ buffer(1) ]]

然后在着色器实现中像这样使用它:

float firstFloat = bufferPassed[0];

这将完成工作。

于 2014-11-03T11:16:20.520 回答
0

没有真正回答您的问题,但您可以在金属着色器中定义一个数组,而不是将值作为纹理传递。

就像是:

constant float manualData[8] = { 1.0, 0.0, 0.0, 1.0,
                               0.0, 0.0, 1.0, 1.0 };

vertex float4 world_vertex(unsigned int vid[[vertex_id]], ...) {
    int manualIndex = vid % 8;
    float manualValue = manualData[manualIndex];
    // something deep and meaningful here...
    return float4(manualValue);
}
于 2014-11-05T17:29:49.157 回答
0

如果你想要一个浮点纹理 bytesPerRow 应该是宽度的 4 倍,因为浮点数的大小为 4 个字节。Metal 复制内存并且不关心值。那是你的任务;-)

就像是:

myTexture.replaceRegion(region, mipmapLevel: 0, withBytes: &manualTextureData, bytesPerRow: manualTextureData.count * sizeof(Float));
于 2014-11-03T08:15:01.060 回答