Ios 延迟屏幕空间金属贴花

Ios 延迟屏幕空间金属贴花,ios,metal,metalkit,Ios,Metal,Metalkit,尝试通过以下操作创建延迟屏幕空间贴花以金属渲染。虽然我似乎不明白 这些是贴花的边界 实际结果 潜在问题 显然,它并不认为贴花与网格相交,我对深度值进行了正确采样,但在计算3D空间中像素的实际位置时,有些东西不符合要求 代码 渲染管道定义为 let stencilDescriptor = MTLDepthStencilDescriptor() stencilDescriptor.depthCompareFunction = .less stencilDescriptor.isDepthWrit

尝试通过以下操作创建延迟屏幕空间贴花以金属渲染。虽然我似乎不明白

这些是贴花的边界

实际结果

潜在问题 显然,它并不认为贴花与网格相交,我对深度值进行了正确采样,但在计算3D空间中像素的实际位置时,有些东西不符合要求

代码 渲染管道定义为

let stencilDescriptor = MTLDepthStencilDescriptor()
stencilDescriptor.depthCompareFunction = .less
stencilDescriptor.isDepthWriteEnabled = false
let renderPipelineDescriptor = MTLRenderPipelineDescriptor()
renderPipelineDescriptor.vertexDescriptor = vertexDescriptor

renderPipelineDescriptor.vertexFunction = vertexLibrary.makeFunction(name: "vertex_decal")
renderPipelineDescriptor.fragmentFunction = fragmentLibrary.makeFunction(name: "fragment_decal")

if let colorAttachment = renderPipelineDescriptor.colorAttachments[0] {
    colorAttachment.pixelFormat = .bgra8Unorm
    colorAttachment.isBlendingEnabled = true
    colorAttachment.rgbBlendOperation = .add
    colorAttachment.sourceRGBBlendFactor = .sourceAlpha
    colorAttachment.destinationRGBBlendFactor = .oneMinusSourceAlpha
}

renderPipelineDescriptor.colorAttachments[1].pixelFormat = .bgra8Unorm
renderPipelineDescriptor.depthAttachmentPixelFormat = .depth32Float
因此,当前的问题是,它只丢弃其投影到的网格之外的像素,而不是“高于”图标球体表面的所有像素

新着色器代码
fragment float4 fragment_贴花(
[stage_in]]中的常量顶点输出,
固定贴花制服和制服[[缓冲区(3)],
深度2D深度纹理[[纹理(0)]]
) {
constexpr采样器纹理采样器(mag_filter::nearest,min_filter::nearest);
float2分辨率=float2(
depthTexture.get_width(),
depthTexture.get_height()
);
float2纹理坐标=in.position.xy/分辨率;
浮动深度=深度纹理.sample(纹理采样器,纹理坐标);
float3屏幕位置=float3(纹理坐标*2-1,深度);
float4 viewPosition=uniforms.inverseProjectionMatrix*float4(屏幕位置,1);
float4 worldPosition=制服。反转设备矩阵*视图位置;
float3 objectPosition=(uniforms.inverseModelMatrix*worldPosition).xyz;
如果(abs(worldPosition.x)>0.5 | | abs(worldPosition.y)>0.5 | | abs(worldPosition.z)>0.5){
丢弃_片段();
}否则{
返回浮动4(1,0,0,0.5);
}
}

最终设法使其正常工作,因此最终的着色器代码是

最新着色器存在的问题是

  • 屏幕位置上翻转的Y轴
  • 不将objectPosition转换为NDC空间(
    localPosition
fragment float4 fragment_贴花(
[stage_in]]中的常量顶点输出,
固定贴花制服和制服[[缓冲区(3)],
depth2d depthTexture[[纹理(0)],
纹理2D彩色纹理[[纹理(1)]]
) {
constexpr取样器深度取样器(mag_过滤器::线性,min_过滤器::线性);
float2分辨率=float2(
depthTexture.get_width(),
depthTexture.get_height()
);
float2深度坐标=in.position.xy/分辨率;
浮动深度=depthTexture.sample(depthSampler,depthCoordinate);
float3屏幕位置=float3((depthCoordinate.x*2-1),-(depthCoordinate.y*2-1),深度);
float4 viewPosition=uniforms.inverseProjectionMatrix*float4(屏幕位置,1);
float4 worldPosition=制服。反转设备矩阵*视图位置;
float4 objectPosition=uniforms.inverseModelMatrix*worldPosition;
float3 localPosition=objectPosition.xyz/objectPosition.w;
如果(abs(localPosition.x)>0.5 | | abs(localPosition.y)>0.5 | | abs(localPosition.z)>0.5){
丢弃_片段();
}否则{
float2 textureCoordinate=localPosition.xy+0.5;
float4 color=colorTexture.sample(深度采样器,纹理坐标);
返回float4(color.rgb,1);
}
}
最终结果如下所示(红色为保留的像素,蓝色为丢弃的像素)


这里肯定没有足够的代码来确定发生了什么。另外,是将渲染的深度纹理绑定到其中,还是将其作为单独的纹理?JustSomeGuy,编辑了问题以添加更多细节,此外还取得了一些进展,这里也提到了。。。这够了吗?谢谢至于深度纹理,它是icosphere的深度纹理,贴花着色器不会写入depthTexture我的意思是,深度纹理在读取时是否作为深度附件绑定?是的,它的绑定也作为深度附件在金属中不能这样做,从附加的纹理采样是未定义的行为。它可能在某些机器上工作,但在其他机器上会以不可预知的方式出现故障。
let renderPipelineDescriptor = MTLRenderPipelineDescriptor()
renderPipelineDescriptor.vertexDescriptor = vertexDescriptor

renderPipelineDescriptor.vertexFunction = vertexLibrary.makeFunction(name: "vertex_decal")
renderPipelineDescriptor.fragmentFunction = fragmentLibrary.makeFunction(name: "fragment_decal")

if let colorAttachment = renderPipelineDescriptor.colorAttachments[0] {
    colorAttachment.pixelFormat = .bgra8Unorm
    colorAttachment.isBlendingEnabled = true
    colorAttachment.rgbBlendOperation = .add
    colorAttachment.sourceRGBBlendFactor = .sourceAlpha
    colorAttachment.destinationRGBBlendFactor = .oneMinusSourceAlpha
}

renderPipelineDescriptor.colorAttachments[1].pixelFormat = .bgra8Unorm
renderPipelineDescriptor.depthAttachmentPixelFormat = .depth32Float
fragment float4 fragment_decal(
    const VertexOut in [[ stage_in ]],
    constant DecalFragmentUniforms &uniforms [[ buffer(3) ]],
    depth2d<float, access::sample> depthTexture [[ texture(0) ]]
) {
    constexpr sampler textureSampler (mag_filter::nearest, min_filter::nearest);

    float2 resolution = float2(
        depthTexture.get_width(),
        depthTexture.get_height()
    );
        
    float2 textureCoordinate = in.position.xy / resolution;
    float depth = depthTexture.sample(textureSampler, textureCoordinate);
    
    float3 screenPosition = float3(textureCoordinate * 2 - 1, depth);
    float4 viewPosition = uniforms.inverseProjectionMatrix * float4(screenPosition, 1);
    float4 worldPosition = uniforms.inverseViewMatrix * viewPosition;
    float3 objectPosition = (uniforms.inverseModelMatrix * worldPosition).xyz;
    
    if(abs(worldPosition.x) > 0.5 || abs(worldPosition.y) > 0.5 || abs(worldPosition.z) > 0.5) {
        discard_fragment();
    } else {
        return float4(1, 0, 0, 0.5);
    }
}
fragment float4 fragment_decal(
    const VertexOut in [[ stage_in ]],
    constant DecalFragmentUniforms &uniforms [[ buffer(3) ]],
    depth2d<float, access::sample> depthTexture [[ texture(0) ]],
    texture2d<float, access::sample> colorTexture [[ texture(1) ]]
) {
    constexpr sampler depthSampler (mag_filter::linear, min_filter::linear);

    float2 resolution = float2(
        depthTexture.get_width(),
        depthTexture.get_height()
    );
        
    float2 depthCoordinate = in.position.xy / resolution;
    float depth = depthTexture.sample(depthSampler, depthCoordinate);
    
    float3 screenPosition = float3((depthCoordinate.x * 2 - 1), -(depthCoordinate.y * 2 - 1), depth);
    float4 viewPosition = uniforms.inverseProjectionMatrix * float4(screenPosition, 1);
    float4 worldPosition = uniforms.inverseViewMatrix * viewPosition;
    float4 objectPosition = uniforms.inverseModelMatrix * worldPosition;
    float3 localPosition = objectPosition.xyz / objectPosition.w;
    
    if(abs(localPosition.x) > 0.5 || abs(localPosition.y) > 0.5 || abs(localPosition.z) > 0.5) {
        discard_fragment();
    } else {
        float2 textureCoordinate = localPosition.xy + 0.5;
        float4 color = colorTexture.sample(depthSampler, textureCoordinate);
        
        return float4(color.rgb, 1);
    }
}