在 Metal 中复制 OpenGL 混合
Replicate OpenGL Blending in Metal
我一直致力于将使用固定功能管道编写的开源游戏移植到 Metal。
我已经能够重做所有的投影变换并绘制了东西其中它们应该用正确的纹理和顶点信息绘制,但我遇到了很多麻烦让片段着色器匹配 OpenGL 混合,纹理看起来正确但混合和亮度关闭。
这是我要匹配的内容:
这是当前的渲染方式:
我看到的控制 GL 混合的代码如下所示:
glShadeModel(GL_SMOOTH);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.0f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
它在禁用混合的情况下绘制主要纹理,然后在它们之间的小三角形(在我的版本中非常明显)上启用它。还为每个顶点提供了 RGB 颜色。
可能还有其他改变状态的调用,但我不确定还要寻找什么。
鉴于所有这些,我将其转换为两种管道状态,一种禁用混合,另一种启用混合。混合的设置如下:
pipelineStateDescriptor.fragmentFunction = viewer.library.makeFunction(name: "borderFragment")!
pipelineStateDescriptor.colorAttachments[0].isBlendingEnabled = true
pipelineStateDescriptor.colorAttachments[0].rgbBlendOperation = .add
pipelineStateDescriptor.colorAttachments[0].alphaBlendOperation = .add
pipelineStateDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
pipelineStateDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha
pipelineStateDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
pipelineStateDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha
我发现了问题,问题在于纹理的创建方式,而不是混合的设置方式,这是正确的。在一组上使用 MetalKit 创建纹理时,我使用了以下选项:
[MTKTextureLoaderOptionSRGB: NSNumber(value:0)]
而另一方没有。当它们都设置为相同(1 或 0)时,它们匹配并且混合工作正常。
着色器最终成为:
fragment float4 terrainFragment(FragmentIn inFrag [[stage_in]],
texture2d<float, access::sample> colorTexture [[ texture(0) ]],
sampler colorSampler [[ sampler(0) ]]) {
float4 color = colorTexture.sample(colorSampler, inFrag.uv * 1.33);
color *= float4(inFrag.shadow,inFrag.shadow,inFrag.shadow,1);
return color * 4;
}
我一直致力于将使用固定功能管道编写的开源游戏移植到 Metal。
我已经能够重做所有的投影变换并绘制了东西其中它们应该用正确的纹理和顶点信息绘制,但我遇到了很多麻烦让片段着色器匹配 OpenGL 混合,纹理看起来正确但混合和亮度关闭。
这是我要匹配的内容:
这是当前的渲染方式:
我看到的控制 GL 混合的代码如下所示:
glShadeModel(GL_SMOOTH);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.0f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
它在禁用混合的情况下绘制主要纹理,然后在它们之间的小三角形(在我的版本中非常明显)上启用它。还为每个顶点提供了 RGB 颜色。
可能还有其他改变状态的调用,但我不确定还要寻找什么。
鉴于所有这些,我将其转换为两种管道状态,一种禁用混合,另一种启用混合。混合的设置如下:
pipelineStateDescriptor.fragmentFunction = viewer.library.makeFunction(name: "borderFragment")!
pipelineStateDescriptor.colorAttachments[0].isBlendingEnabled = true
pipelineStateDescriptor.colorAttachments[0].rgbBlendOperation = .add
pipelineStateDescriptor.colorAttachments[0].alphaBlendOperation = .add
pipelineStateDescriptor.colorAttachments[0].sourceRGBBlendFactor = .sourceAlpha
pipelineStateDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .sourceAlpha
pipelineStateDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
pipelineStateDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .oneMinusSourceAlpha
我发现了问题,问题在于纹理的创建方式,而不是混合的设置方式,这是正确的。在一组上使用 MetalKit 创建纹理时,我使用了以下选项:
[MTKTextureLoaderOptionSRGB: NSNumber(value:0)]
而另一方没有。当它们都设置为相同(1 或 0)时,它们匹配并且混合工作正常。
着色器最终成为:
fragment float4 terrainFragment(FragmentIn inFrag [[stage_in]],
texture2d<float, access::sample> colorTexture [[ texture(0) ]],
sampler colorSampler [[ sampler(0) ]]) {
float4 color = colorTexture.sample(colorSampler, inFrag.uv * 1.33);
color *= float4(inFrag.shadow,inFrag.shadow,inFrag.shadow,1);
return color * 4;
}