shader - Metal:如何将图像附加到着色器而不进行颜色/ Gamma 转换?

标签 shader scenekit metal color-space gamma

是否可以将图像发送到 Metal 着色器(来自场景套件)而不进行任何颜色/ Gamma 校正?

我有一个数据纹理,其中每个 channel 对应于我希望能够测试的特定值。这是一张世界地图,其中绿色 channel 映射到国家/地区索引。如果该国家/地区处于“事件”状态,则该国家/地区将呈现为红色,否则呈现为灰色。

这是我正在使用的代码示例:

sphereNode = SCNNode(geometry: sphereGeometry)
scene.rootNode.addChildNode(sphereNode)

let program = SCNProgram()
program.vertexFunctionName = "sliceVertex"       
program.fragmentFunctionName = "sliceFragment"
sphereNode.geometry?.firstMaterial?.program = program

let imageProperty = SCNMaterialProperty(contents: UIImage(named: "art.scnassets/Textures/earth-data-map-2k.png")!)
mageProperty.mipFilter = SCNFilterMode.none 
sphereNode.geometry?.firstMaterial?.setValue(imageProperty, forKey: "dataTexture")

片段着色器:

fragment float4 sliceFragment(
    Vertex in [[stage_in]],
    texture2d<float, access::sample> dataTexture [[texture(0)]]
){
    constexpr sampler quadSampler(coord::normalized, filter::linear, address::repeat);
    float4 color = dataTexture.sample(quadSampler, in.texCoords);
    int index = int(color.g * 255.0);
    float active = index == 81 ? 1.0 : 0.0;
    float3 col = mix(float3(color.g,color.g,color.g), float3(1.0,0.0,0.0), active);
    return float4(col.r, col.g, col.b, 1);
}

问题是我用于纹理的 UIImage 似乎已转换为线性空间,但我想在着色器中使用不变的图像数据。

最佳答案

Metal 始终在着色器中使用线性 RGB 来处理纹理数据。如果纹理是 sRGB 而不是线性,则读取和采样将从 sRGB 转换为线性,写入从线性转换为 sRGB。

纹理像素格式告诉 Metal 支持纹理的数据是线性还是 sRGB。大多数像素格式都是线性的,但有些格式的名称以 _sRGB 结尾,并且是 sRGB。

在幕后(没有双关语),SCNMaterialPropertyUIImage 将解释图像数据并使用源颜色配置文件来选择像素格式。如果 PNG 的颜色配置文件指定了线性或 sRGB 以外的其他颜色,则它可能会被转换为其中之一。如果它没有颜色配置文件,则可能会假定为 SRGB。

表示非图像数据的 PNG 应带有指定其采用线性 RGB 的颜色配置文件。如果您无法修改 PNG 并且它被解释为 sRGB,您可能需要通过 CGImage 并使用 copy(colorSpace:) 创建一个新的图像对象相同的数据并覆盖其颜色配置文件。您可以使用 CGColorSpace(.genericRGBLinear) 获得所需的色彩空间。

此外,您应该为着色器的采样器使用 filter::nearest 。合并相邻国家指数是没有意义的。

不过,比这一切更好的可能是在应用程序的资源中使用数据文件格式而不是图像文件格式。然后将其传递给缓冲区中的着色器而不是纹理。

关于shader - Metal:如何将图像附加到着色器而不进行颜色/ Gamma 转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51787845/

相关文章:

shader - SetInputLayout、VertexShader 和 PixelShader 之间不匹配

ios - 如何从 AVDepthData 制作 3D 模型?

3d - Vulkan 或 Metal 或这些图形 "APIs"到底是什么?

Qt 使用 ShaderEffect 进行 QImage 渲染

android - 将 OpenGL fragment 着色器设置为仅通过漫反射减少 vec4 颜色点的 RGB 值,而不是 alpha

ios - SceneKit 碰撞偶尔失败

macos - 强制 SCNView 使用 OpenGL

objective-c - 将 ObjC id<Protocol> 和类型对象转换为 C 指针 (void *) 然后将其转换回去是否安全?

ios - Metal 着色器纹理读取与样本

opengl - 将 Boost uBLAS 矩阵传递给 OpenGL 着色器