在 Metal Shading Language 中,sample() 是否总是 return RGBA 格式的 float4?
Does sample() always return float4 in RGBA format in Metal Shading Language?
我有一个 RGBA8Unorm 格式的 MTLTexture 和一个 BGRA8Unorm 格式(反转)的屏幕纹理(在 MTKView 中)。在 Metal 着色器中,当我使用 sample() 从该纹理中采样时,我得到 float4。我在metal shader中写texture的时候,也写了float4。似乎当我在着色器代码中时,float4 总是表示组件 RGBA 的相同顺序,而不管纹理的原始格式如何([0] 表示红色,[1] 表示绿色,[2] 表示蓝色,[ 3] 阿尔法)。 sampled/written float4 的组件的含义在着色器 中总是相同的,无论纹理的存储格式是什么,我的结论是否正确?
更新:我使用以下代码写入 RGBA8Unnorm 格式的纹理:
kernel void
computeColourMap(constant Uniforms &uniforms [[buffer(0)]],
constant array<float, 120> &s [[buffer(1)]],
constant array<float, 120> &red [[buffer(2)]],
constant array<float, 120> &green [[buffer(3)]],
constant array<float, 120> &blue [[buffer(4)]],
texture2d<float, access::write> output [[texture(0)]],
uint2 id [[thread_position_in_grid]])
{
if (id.x >= output.get_width() || id.y >= output.get_height()) {
return;
}
uint i = id.x % 120;
float4 col (0, 0, 0, 1);
col.x += amps[i] * red[i];
col.y += amps[i] * green[i];
col.z += amps[i] * blue[i];
output.write(col, id);
}
然后我在渲染阶段使用以下着色器:
vertex VertexOut
vertexShader(const device VertexIn *vertexArray [[buffer(0)]],
unsigned int vid [[vertex_id]])
{
VertexIn vertex_in = vertexArray[vid];
VertexOut vertex_out;
vertex_out.position = vertex_in.position;
vertex_out.textureCoord = vertex_in.textureCoord;
return vertex_out;
}
fragment float4
fragmentShader(VertexOut interpolated [[stage_in]],
texture2d<float> colorTexture [[ texture(0) ]])
{
const float4 colorSample = colorTexture.sample(nearestSampler,
interpolated.textureCoord);
return colorSample;
}
其中 colourTexture
传入片段着色器的是我以 RGBA8Unorm 格式生成的,在 Swift 中我有:
let renderPipelineDescriptor = MTLRenderPipelineDescriptor()
renderPipelineDescriptor.vertexFunction = library.makeFunction(name: "vertexShader")!
renderPipelineDescriptor.fragmentFunction = library.makeFunction(name: "fragmentShader")!
renderPipelineDescriptor.colorAttachments[0].pixelFormat = colorPixelFormat
MTKView的colorPixelFormat
是BGRA8Unorm(相对于贴图反转),和我的贴图不一样,但是屏幕上显示的颜色是正确的。
更新 2:在着色器中 float4 表示的颜色始终具有 rgba 顺序的另一个指针是:float4 类型实际上具有名为 v.r 的访问器,v.g, v.b, v.rgb, 等...
向量总是有4个分量,但分量的类型不一定是float
。声明纹理时,将组件类型指定为模板参数(代码中的texture2d<float ...>
)。
例如,来自金属着色语言规范 v2.1,第 5.10.1 节:
The following member functions can be used to sample from a 1D
texture.
Tv sample(sampler s, float coord) const
Tv is a 4-component vector type based on the templated type used
to declare the texture type. If T is float, Tv is float4. If T is half,
Tv is half4. If T is int, Tv is int4. If T is uint, Tv is uint4. If T
is short, Tv is short4 and if T is ushort, Tv is ushort4.
write()
的声明中使用了相同的 Tv 类型。其他纹理类型的函数以类似的方式记录。
而且,是的,组件 .r
始终包含红色组件(如果存在)等。并且 [0]
始终对应于 .r
(或 .x
)。
我有一个 RGBA8Unorm 格式的 MTLTexture 和一个 BGRA8Unorm 格式(反转)的屏幕纹理(在 MTKView 中)。在 Metal 着色器中,当我使用 sample() 从该纹理中采样时,我得到 float4。我在metal shader中写texture的时候,也写了float4。似乎当我在着色器代码中时,float4 总是表示组件 RGBA 的相同顺序,而不管纹理的原始格式如何([0] 表示红色,[1] 表示绿色,[2] 表示蓝色,[ 3] 阿尔法)。 sampled/written float4 的组件的含义在着色器 中总是相同的,无论纹理的存储格式是什么,我的结论是否正确?
更新:我使用以下代码写入 RGBA8Unnorm 格式的纹理:
kernel void
computeColourMap(constant Uniforms &uniforms [[buffer(0)]],
constant array<float, 120> &s [[buffer(1)]],
constant array<float, 120> &red [[buffer(2)]],
constant array<float, 120> &green [[buffer(3)]],
constant array<float, 120> &blue [[buffer(4)]],
texture2d<float, access::write> output [[texture(0)]],
uint2 id [[thread_position_in_grid]])
{
if (id.x >= output.get_width() || id.y >= output.get_height()) {
return;
}
uint i = id.x % 120;
float4 col (0, 0, 0, 1);
col.x += amps[i] * red[i];
col.y += amps[i] * green[i];
col.z += amps[i] * blue[i];
output.write(col, id);
}
然后我在渲染阶段使用以下着色器:
vertex VertexOut
vertexShader(const device VertexIn *vertexArray [[buffer(0)]],
unsigned int vid [[vertex_id]])
{
VertexIn vertex_in = vertexArray[vid];
VertexOut vertex_out;
vertex_out.position = vertex_in.position;
vertex_out.textureCoord = vertex_in.textureCoord;
return vertex_out;
}
fragment float4
fragmentShader(VertexOut interpolated [[stage_in]],
texture2d<float> colorTexture [[ texture(0) ]])
{
const float4 colorSample = colorTexture.sample(nearestSampler,
interpolated.textureCoord);
return colorSample;
}
其中 colourTexture
传入片段着色器的是我以 RGBA8Unorm 格式生成的,在 Swift 中我有:
let renderPipelineDescriptor = MTLRenderPipelineDescriptor()
renderPipelineDescriptor.vertexFunction = library.makeFunction(name: "vertexShader")!
renderPipelineDescriptor.fragmentFunction = library.makeFunction(name: "fragmentShader")!
renderPipelineDescriptor.colorAttachments[0].pixelFormat = colorPixelFormat
MTKView的colorPixelFormat
是BGRA8Unorm(相对于贴图反转),和我的贴图不一样,但是屏幕上显示的颜色是正确的。
更新 2:在着色器中 float4 表示的颜色始终具有 rgba 顺序的另一个指针是:float4 类型实际上具有名为 v.r 的访问器,v.g, v.b, v.rgb, 等...
向量总是有4个分量,但分量的类型不一定是float
。声明纹理时,将组件类型指定为模板参数(代码中的texture2d<float ...>
)。
例如,来自金属着色语言规范 v2.1,第 5.10.1 节:
The following member functions can be used to sample from a 1D texture.
Tv sample(sampler s, float coord) const
Tv is a 4-component vector type based on the templated type used to declare the texture type. If T is float, Tv is float4. If T is half, Tv is half4. If T is int, Tv is int4. If T is uint, Tv is uint4. If T is short, Tv is short4 and if T is ushort, Tv is ushort4.
write()
的声明中使用了相同的 Tv 类型。其他纹理类型的函数以类似的方式记录。
而且,是的,组件 .r
始终包含红色组件(如果存在)等。并且 [0]
始终对应于 .r
(或 .x
)。