Swift金属计算着色器提供意想不到的混合效果

jk9hmnmh  于 2022-10-31  发布在  Swift
关注(0)|答案(1)|浏览(137)

我正在学习金属和创建一个小应用程序在我的iPhone XR与XCode 13.4.1(iOS目标15.5)。
我渲染了一个简单的球体,并试图创建一个“发光”或“绽放”效果,如本文所述:https://weblog.jamisbuck.org/2016/2/27/bloom-effect-in-metal.html
我成功地使用金属性能着色器执行高斯模糊和渲染到一个纹理只有'模糊'的轮廓我的球体。纹理尺寸的输出这个过程匹配我目前的'可绘制'的尺寸以及。
我的问题是,当我稍后使用计算着色器将高斯纹理与我的场景纹理混合时,输出纹理被合并,但奇怪的是高斯输入纹理似乎被缩小到输入大小的25%,因此只覆盖了我的场景的左上角。请查看所附的屏幕截图以获得更好的描述。
为什么混合是这样工作的,只渲染在左上角象限?我该如何解决它?谢谢任何帮助。
我已经粘贴了相关的代码在这里的一切后,我的3d场景渲染,通过计算着色器混合,并介绍到屏幕上。

// Do the drawing of the 3d scene
        commandEncoder.endEncoding()

        print("Before Texture: \(drawable.texture.width) \(drawable.texture.height)")

        if true {

            // Now create a compute shader to blend the blurred mask texture
            // with the framebuffer
            let computeFunction = self.computeLibrary.makeFunction(name: "ComputeBlender")

            // Setup compute encoder
            let computePipelineState = try? device.makeComputePipelineState(function: computeFunction!)
            let computeEncoder = commandBuffer.makeComputeCommandEncoder()
            computeEncoder?.setComputePipelineState(computePipelineState!)

            // input one -- primary texture
            computeEncoder?.setTexture(drawable.texture, index: 0)
            // input two -- mask texture
            computeEncoder?.setTexture(self.debugImageA, index: 1)
            // output texture
            computeEncoder?.setTexture(drawable.texture, index: 2)

            if false {
                let threadsPerGroup = MTLSizeMake(1, 1, 1)
                let w = Int(view.drawableSize.width)
                let h = Int(view.drawableSize.height)
                let threadsPerGrid = MTLSizeMake(w, h, 1)
                computeEncoder?.dispatchThreads(threadsPerGrid, threadsPerThreadgroup: threadsPerGroup)
            } else {
                let viewWidth = Int(view.bounds.size.width)
                let viewHeight = Int(view.bounds.size.height)

                // set up an 8x8 group of threads
                let threadGroupSize = MTLSize(width: 1, height: 1, depth: 1)

                // define the number of such groups needed to process the textures
                let numGroups = MTLSize(
                  width: viewWidth/threadGroupSize.width+1,
                  height: viewHeight/threadGroupSize.height+1,
                  depth: 1)

                computeEncoder?.dispatchThreadgroups(numGroups,
                  threadsPerThreadgroup: threadGroupSize)
            }

            computeEncoder?.endEncoding()

        }

        // Capture debug texture
        self.debugImageB = drawable.texture

        // Present the final/blended image
        commandBuffer.present(drawable)
        commandBuffer.commit()
        commandBuffer.waitUntilCompleted()

        print("After Texture: \(self.debugImageB.width) \(self.debugImageB.height)")

下面是与post匹配的着色器-请注意,我重新排列了颜色,使最终图像显示不正确的混合:


# include <metal_stdlib>

using namespace metal;

kernel void ComputeBlender(

  texture2d<float, access::read> source [[ texture(0) ]],
  texture2d<float, access::read> mask [[ texture(1) ]],
  texture2d<float, access::write> dest [[ texture(2) ]],
  uint2 gid [[ thread_position_in_grid ]])
{
  float4 source_color = source.read(gid);
  float4 mask_color = mask.read(gid);
  float4 result_color = source_color + mask_color;

  result_color = float4(result_color.g, result_color.b, result_color.r, 1.0);

  dest.write(result_color, gid);

}

zqdjd7g9

zqdjd7g91#

您的线程位置逻辑在着色器中未正确实现。您应该考虑纹理的大小。

uint2 uv = uint2(gid.x + mask.get_width(), gid.y + mask.get_height());
dest.write(result_color, uv);

相关问题