Metal Compute Shader中输出纹理缩放操作实现疑问
在Metal Compute Shader中实现输出纹理缩放
嘿,看你的代码,现在是直接把输入纹理的每个像素对应到输出纹理的同位置线程,但这没法实现缩放——毕竟缩放时输出和输入纹理的尺寸肯定不一样,线程网格的逻辑得调整下。我给你捋清楚核心逻辑,再改改代码:
核心思路
- 线程网格的尺寸要和输出纹理的宽高匹配,每个线程负责输出纹理的一个像素
- 把输出纹理上的线程位置转换成输入纹理的归一化坐标,这样不管是放大还是缩小,都能精准映射到输入的对应区域
- 用
sample方法代替read来采样,还能开启纹理过滤(比如线性插值),让缩放后的画面没那么多锯齿
修改后的完整示例代码
#include <metal_stdlib> using namespace metal; kernel void scaledCompute( texture2d<half, access::read> inputTexture [[ texture(0) ]], texture2d<half, access::write> outputTexture [[ texture(1) ]], uint2 gid [[thread_position_in_grid]], constant float2& sizeRatio [[ buffer(0) ]] // 传入输入/输出的尺寸比例:(输入宽/输出宽, 输入高/输出高) ) { // 先判断当前线程是否在输出纹理范围内,超出就直接返回 if (gid.x >= outputTexture.get_width() || gid.y >= outputTexture.get_height()) { return; } // 1. 把输出线程位置转成归一化坐标(0~1范围,对应输出纹理的整个区域) float2 outputUV = float2(gid) / float2(outputTexture.get_width(), outputTexture.get_height()); // 2. 转换为输入纹理的归一化坐标——这里用传入的尺寸比例做映射 // 比如输出比输入大(放大),比例会小于1,inputUV会覆盖输入的完整区域;缩小则反之 float2 inputUV = outputUV * sizeRatio; // 3. 配置采样器:用线性过滤让缩放更平滑,超出边界的部分 clamp 到边缘 constexpr sampler s(coord::normalized, filter::linear, address::clamp_to_edge); half4 inputColor = inputTexture.sample(s, inputUV); // 4. 写入输出纹理(这里可以加你自己的颜色处理逻辑,比如你之前写的取红通道之类的) half4 outputColor = half4(inputColor.rgb, inputColor.a); outputTexture.write(outputColor, gid); }
关键细节要注意
- 线程网格配置:在CPU端设置Compute Pipeline的线程网格时,一定要传输出纹理的宽高,比如
MTLSizeMake(outputWidth, outputHeight, 1),不然线程数量不对,缩放肯定出问题 - 尺寸比例计算:
sizeRatio要在CPU端算好传入,比如输入宽100、输出宽200,那x分量就是100.0/200.0=0.5;如果是等比例缩放,直接用同一个比例就行 - 采样器选择:如果要硬边缘的像素风格缩放,可以把
filter::linear改成filter::nearest,但线性过滤的平滑效果更适合大多数场景 - 你之前代码里
half4 outputColor = half4(inputColor.r, 0.0...没写完,我这里保留了原颜色,你可以根据需求修改,比如只保留红通道的话就写成half4(inputColor.r, 0.0, 0.0, inputColor.a)就行
内容的提问来源于stack exchange,提问作者Deepak Sharma
相关产品推荐
相关产品推荐

