简体   繁体   English

iOS Metal Shader - 纹理读写访问?

[英]iOS Metal Shader - Texture read and write access?

I'm using a metal shader to draw many particles onto the screen.我正在使用金属着色器在屏幕上绘制许多粒子。 Each particle has its own position (which can change) and often two particles have the same position.每个粒子都有自己的位置(可以改变),通常两个粒子有相同的位置。 How can I check if the texture2d I write into does not have a pixel at a certain position yet?如何检查我写入的texture2d在某个位置是否还没有像素? (I want to make sure that I only draw a particle at a certain position if there hasn't been drawn a particle yet, because I get an ugly flickering if many particles are drawn at the same positon) (如果还没有绘制粒子,我想确保我只在某个位置绘制一个粒子,因为如果在同一个位置绘制了许多粒子,我会得到一个难看的闪烁)

I've tried outTexture.read(particlePosition) , but this obviously doesn't work, because of the texture access qualifier, which is access::write .我已经尝试过outTexture.read(particlePosition) ,但这显然不起作用,因为纹理访问限定符是access::write

Is there a way I can have read and write access to a texture2d at the same time?有没有一种方法可以同时对texture2d进行读写访问? (If there isn't, how could I still solve my problem?) (如果没有,我怎么还能解决我的问题?)

There are several approaches that could work here.有几种方法可以在这里工作。 In concurrent systems programming, what you're talking about is termed first-write wins .在并发系统编程中,您所说的称为first-write wins

1) If the particles only need to preclude other particles from being drawn (and aren't potentially obscured by other elements in the scene in the same render pass), you can write a special value to the depth buffer to signify that a fragment has already been written to a particular coordinate. 1) 如果粒子只需要阻止其他粒子被绘制(并且在同一渲染通道中不会被场景中的其他元素潜在地遮挡),则可以向深度缓冲区写入一个特殊值以表示片段具有已经写入特定坐标。 For example, you'd turn on depth test (using the depth compare function Equal), clear the depth buffer to some distant value (like 1.0), and then write a value of 0.0 to the depth buffer in the fragment function.例如,您将打开深度测试(使用深度比较函数 Equal),将深度缓冲区清除为某个远值(如 1.0),然后将值 0.0 写入片段函数中的深度缓冲区。 Any subsequent write to a given pixel will fail to pass the depth test and will not be drawn.对给定像素的任何后续写入都将无法通过深度测试并且不会被绘制。

2) Use framebuffer read-back. 2) 使用帧缓冲回读。 On iOS, Metal allows you to read from the currently-bound primary renderbuffer by attributing a parameter to your fragment function with [[color(0)]] .在 iOS 上,Metal 允许您通过使用[[color(0)]]将参数分配给片段函数来读取当前绑定的主渲染缓冲区。 This parameter will contain the current color value in the renderbuffer, which you can test against to determine whether it has been written to.此参数将包含渲染缓冲区中的当前颜色值,您可以对其进行测试以确定它是否已被写入。 This does require you to clear the texture to a predetermined color that will never otherwise be produced by your fragment function, so it is more limited than the above approach, and possibly less performant.这确实需要您将纹理清除为预定颜色,否则您的片段函数永远不会产生这种颜色,因此它比上述方法更受限制,并且性能可能更低。

All of the above applies whether you're rendering to a drawable's texture for direct presentation to the screen, or to some offscreen texture.无论您是渲染可绘制对象的纹理以直接呈现给屏幕,还是渲染某些屏幕外纹理,以上所有内容都适用。

To answer the read and write part : you can specify a read/write access for the output texture as such :要回答读写部分:您可以为输出纹理指定读/写访问权限:

texture2d<float, access::read_write> outTexture [[texture(1)]],

Also, your texture descriptor must specify usage :此外,您的纹理描述符必须指定用法:

textureDescriptor?.usage = [.shaderRead, .shaderWrite]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM