gpt4 book ai didi

xcode - Metal 中的Alpha混合未达到预期的结果

转载 作者:行者123 更新时间:2023-12-04 14:38:02 27 4
gpt4 key购买 nike

我在Metal中渲染半透明 Sprite 时遇到问题。我已经在Apple的论坛上阅读了this questionthis questionthis onethis thread以及其他内容,但是还不能完全起作用,因此请先继续阅读,然后再将此问题标记为重复的

我的引用纹理有四行四列。这些行分别是完全饱和的红色,绿色,蓝色和黑色。列的不透明度从100%不透明到25%不透明(依次为1、0.75、0.5、0.25 alpha)变化。

在Pixelmator(我创建它的地方)上,它看起来像这样:

enter image description here

如果在导出之前插入完全不透明的白色背景,它将看起来像这样:

enter image description here

... 但是,当我将其纹理映射到Metal中的四边形上,并在将背景清除为不透明的白色(255、255、255、255)后进行渲染时,我得到了:

enter image description here

...显然比不透明的片段中的暗(应使后面的亮白色“渗出”),比不透明的片段中的暗。

实现细节

我将png文件作为纹理 Assets 导入到Xcode中,作为我应用程序 Assets 目录中的纹理 Assets ,并在运行时使用MTKTextureLoader加载了该文件。 .SRGB选项似乎没有什么不同。

就我所知,着色器代码没有做任何花哨的事情,但仅供引用:

#include <metal_stdlib>
using namespace metal;

struct Constants {
float4x4 modelViewProjection;
};

struct VertexIn {
float4 position [[ attribute(0) ]];
float2 texCoords [[ attribute(1) ]];
};

struct VertexOut {
float4 position [[position]];
float2 texCoords;
};

vertex VertexOut sprite_vertex_transform(device VertexIn *vertices [[buffer(0)]],
constant Constants &uniforms [[buffer(1)]],
uint vertexId [[vertex_id]]) {

float4 modelPosition = vertices[vertexId].position;
VertexOut out;

out.position = uniforms.modelViewProjection * modelPosition;
out.texCoords = vertices[vertexId].texCoords;

return out;
}

fragment float4 sprite_fragment_textured(VertexOut fragmentIn [[stage_in]],
texture2d<float, access::sample> tex2d [[texture(0)]],
constant Constants &uniforms [[buffer(1)]],
sampler sampler2d [[sampler(0)]]) {

float4 surfaceColor = tex2d.sample(sampler2d, fragmentIn.texCoords);

return surfaceColor;
}

在应用程序方面,我在渲染过程描述符上使用以下(相当标准的)混合因子和操作:
descriptor.colorAttachments[0].rgbBlendOperation = .add
descriptor.colorAttachments[0].alphaBlendOperation = .add

descriptor.colorAttachments[0].sourceRGBBlendFactor = .one
descriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha

descriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
descriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha

(我尝试将 sourceRGBBlendFactor.one更改为 .sourceAlpha,使它变暗了。)

如果我在 红色背景(255、0、0、255)上渲染图像,则会得到以下信息:

enter image description here

请注意,第一行向右逐渐变暗。 整个都应该是相同的颜色,因为它混合了具有相同RGB分量(255、0、0)的两种颜色。

我已经将我的应用程序剥离到最低限度,并添加了 demo project on Github;完整的Metal设置可以在存储库的源代码中看到。也许有一些我没有提到的原因导致了这种情况,但是我无法完全弄清楚是什么原因...

编辑:

正如@KenThomases在评论中所建议的那样,我将 MTKView属性 colorPixelFormat的值从默认 .bgra8Unorm更改为 bgra8Unorm_srgb,并将 colorSpace属性设置为与 view.window?.colorSpace?.cgColorSpace相同。 现在,半透明的片段看起来暗了很多,但仍然不是预期的颜色:

enter image description here

(第一行应在红色背景上从左到右完全“不可见”。)

附录

我碰到了 Apple's docs on using the Shader Debugger,所以我决定看看当我的应用程序绘制 Sprite 右上角的片段之一(在25%的不透明度下被完全饱和的红色)时,片段着色器中会发生什么。

有趣的是,片段着色器返回的值(然后根据颜色缓冲区的当前颜色和混合因子/函数将对其应用alpha混合)是 [0.314, 0.0, 0.0, 0.596]:

enter image description here

RGBt值似乎不受 MTKTextureLoader.Option.SRGBtruefalse或不存在的影响。

请注意, 红色组件( 0.314)和 alpha 组件( 0.596)的 不等于,但是(如果我没记错的话) 应当是,对于带全饱和的alpha来说是红色的。

我想这意味着我已将问题缩小到纹理加载阶段...?

也许我应该放弃方便的 MTKTextureLoader并弄脏我的手...?

最佳答案

好吧,事实证明问题确实在纹理加载阶段,但是没有我可能可以调整的任何代码(至少在坚持MTKTextureLoader的情况下没有)。

似乎我需要在Xcode中对 Assets 目录的Attributes Inspector进行一些更改(但至少现在我可以用Xcode标记我的原始问题:距离铜牌更近了一步!)。

具体来说,我不得不将纹理集的解释属性从默认选项“颜色”更改为“颜色(未预乘)”:

enter image description here

显然,这些 Assets 目录纹理集在设计时考虑了更传统的纹理图像格式,例如TGA,不是PNG(根据规范正式未预乘)。

我以某种方式期望MTKTextureLoader足够聪明,可以在加载时为我执行此操作。显然,这不是一条可以从(例如)PNG文件的元数据/标题中可靠读取的信息。

现在,我的引用纹理以其所有的辉煌呈现:

enter image description here

作为最终的更严格的测试,我可以确认所有4种颜色在等效的RGB背景下都会“消失”,而不管纹理像素的不透明度如何:

enter image description here

关于xcode - Metal 中的Alpha混合未达到预期的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55604226/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com