You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Metal中实现水平最近邻、垂直线性的放大采样滤镜

Metal 内置的采样器不支持为水平、垂直两个轴单独配置不同的放大过滤规则,你可以通过手动计算采样的方式实现需求,修改后的片段着色器代码如下:

fragment float4
samplingShader(RasterizerData in [[stage_in]],
               texture2d<half> colorTexture [[ texture(AAPLTextureIndexBaseColor) ]])
{
    // 取纹理的像素尺寸
    uint texWidth = colorTexture.get_width();
    uint texHeight = colorTexture.get_height();
    
    // 将归一化UV转为像素坐标
    float2 pixelUV = in.textureCoordinate * float2(texWidth, texHeight);
    
    // 水平方向取最近整数值,实现nearest效果
    float xNearest = round(pixelUV.x);
    // 垂直方向保留小数,用于线性插值
    float yFloor = floor(pixelUV.y);
    float yFrac = pixelUV.y - yFloor;
    
    // 处理纹理边界(按钳位到边缘规则处理,可按需调整为重复等其他规则)
    xNearest = clamp(xNearest, 0.0f, float(texWidth - 1));
    yFloor = clamp(yFloor, 0.0f, float(texHeight - 2));
    
    // 分别采样垂直方向两个相邻纹素,水平方向统一用计算好的xNearest
    half4 sample0 = colorTexture.read(uint2(xNearest, yFloor));
    half4 sample1 = colorTexture.read(uint2(xNearest, yFloor + 1));
    
    // 垂直方向线性混合得到最终颜色
    half4 colorSample = mix(sample0, sample1, half(yFrac));

    return float4(colorSample);
}

上述实现的性能开销和原生线性采样基本一致,不会引入明显的性能损耗。如果需要适配其他纹理寻址模式,调整坐标边界处理的逻辑即可。

替代方案

如果你的应用场景中使用的是静态不变的纹理,也可以提前在CPU侧预先生成垂直方向做过线性插值处理的纹理,后续直接使用mag_filter::nearest的采样器采样即可,这种方案可以降低片段着色器的计算量,但仅适用于纹理内容不会动态更新的场景。

内容的提问来源于stack exchange,提问作者Scaroth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 20:21:01