区块链技术博客
www.b2bchain.cn

基础部分(六)分析GPUImage3中的MSL–编写自己的滤镜求职学习资料

本文介绍了基础部分(六)分析GPUImage3中的MSL–编写自己的滤镜求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

原因

问题:Metal中的vertex shader、fragment shader该如何编写?
我发现很难在网络中找到相关的话题,MSL的介绍也比较少,之前翻译过MSL指南,坚持不下去,时间久了感觉收获不大,不会的依旧还是不会。本文以实例分析,达到先回用,再学原理。

本文目标

  • 能看懂GPUImage3中的绝大部分滤镜
  • 能实现一个自己想要的滤镜

常用类型

  • half : 一个16-bit浮点数,符合IEEE754的16位二进制浮点数存储格式规范
  • half4 :向量数据类型,4分量为half
  • half4x4:矩阵数据类型
  • constexpr sampler 采样器
  • texture2d 2d纹理

更多参考这篇文章: https://xiaozhuanlan.com/topic/1568709324

常用函数

  • dot 点击
  • mix 将值限制在两个其他值之间并做融合,常用于颜色混合:mix(x,y,a) = x(1-a)+ya
  • floor 向下取整
  • ceil 向上取整
  • clamp 用来将某个值“钳”住、限制在某个区间(minVal~maxVal)
  • max 最大值
  • atan2 反正切
  • sqrt 平方根
  • sin 正弦函数
  • cos 余弦函数
  • pow 指数函数
  • step 阈值函数

知识回顾

之前我们已经完成过画一个矩形,以及渲染一张图,用到过vertex shader、fragmentshader;

  • vertex shader :负责顶点坐标,纹理坐标
  • fragment shader : 负责每个像素的颜色;

Metal的使用流程搭建好之后(自己实现一张图的显示,然后看GPUImage3框架),我们只需编码vertex shader、fragment shader即可实现想要的效果;

注意:vertex shader 的输出是fragment shader的输入参数之一;

有没有注释版本的GPUImage?

答:https://github.com/Tliens/GPUImageByMetal

我几乎把整个工程都加上了中文注释,目前还剩下一部分滤镜没有完成,应该可以帮到你,喜欢不要吝啬star🌟。

GPUImage的滤镜效果来源于哪里?灵感吗?我想绝大部分是photoshop的算法。如:ContrastAdjustment

photoshop调节对比度的公式 nRGB = RGB + (RGB - Threshold) * Contrast

fragment half4 contrastFragment(SingleInputVertexIO fragmentInput [[stage_in]],                                 texture2d<half> inputTexture [[texture(0)]],                                 constant ContrastUniform& uniform [[ buffer(1) ]]) {     constexpr sampler quadSampler;     half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);     // photoshop调节对比度的公式 nRGB = RGB + (RGB - Threshold) * Contrast     // Threshold是平均亮度 默认选0.5     return half4(((color.rgb + (color.rgb - half3(0.5)) * uniform.contrast)), color.a); }

因此,想要什么样的效果需要先在PS中调整,然后将相关算法翻译成shader

一、颜色翻转滤镜

颜色翻转?其实就是(1.0 - color.rgb),这就是算法,转成shader

fragment half4 colorInversionFragment(SingleInputVertexIO fragmentInput [[stage_in]],                                  texture2d<half> inputTexture [[texture(0)]]) {     constexpr sampler quadSampler;     half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);      return half4((1.0 - color.rgb), color.a); }
// 单输入顶点 struct SingleInputVertexIO {     float4 position [[position]];     float2 textureCoordinate [[user(texturecoord)]]; };
  • half4先理解成4个float
  • constexpr sampler quadSampler 采样器
  • half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate); 根据纹理、纹理坐标获取该点颜色
  • return half4((1.0 - color.rgb), color.a);返回值为half4
现在你可以动手实现一个滤镜了,比如当r 大于 0.5时, r = 1.0 - r,其他不变,试一试效果吧!

如下:

 half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);     if (color.r > 0.5) {           return half4(1-color.r, color.g, color.b, color.a);     } else{         return half4((1.0 - color.rgb), color.a);   }

二、luminance

在此之前我们看一个数学公式。
点积dot
dot 两个数组点积、点乘 [1,2,3]·[4,5,6] = 1×1 + 2×3 + 3×6 = 1+6+18 = 25

上代码:

fragment half4 luminanceFragment(SingleInputVertexIO fragmentInput [[stage_in]],                                   texture2d<half> inputTexture [[texture(0)]]) {     constexpr sampler quadSampler;     half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);     //dot 两个数组点积、点乘 [1,2,3]·[4,5,6] = 1*1 + 2*3 + 3*6 = 1+6+18 = 25     //luminanceWeighting为亮度常量     half luminance = dot(color.rgb, luminanceWeighting);      return half4(half3(luminance), color.a); }

luminance滤镜 实际上是dot(color.rgb, luminanceWeighting)

luminanceWeighting = half3(0.2125, 0.7154, 0.0721)

这是一个亮度常量,滤镜为什么这么写?算法是怎么来的?为何用点积?

答:这是公认的一种效果,调节时就按照现有方式调节。

thresholdFragment

能不能有个动态的滤镜,可以根据外界值进行变化?

typedef struct {     float threshold; } ThresholdUniform;  // 阈值滤镜  阈值的大小是动态的设置的 fragment half4 thresholdFragment(SingleInputVertexIO fragmentInput [[stage_in]],                                   texture2d<half> inputTexture [[texture(0)]],                                   constant ThresholdUniform& uniform [[ buffer(1) ]]) {     constexpr sampler quadSampler;     half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);      half luminance = dot(color.rgb, luminanceWeighting);     // step luminance >= half(uniform.threshold) 的值为1,小于则为0     half thresholdResult = step(half(uniform.threshold), luminance);      return half4(half3(thresholdResult), color.w); }

threshold就是个可变的值。

原因

问题:Metal中的vertex shader、fragment shader该如何编写?
我发现很难在网络中找到相关的话题,MSL的介绍也比较少,之前翻译过MSL指南,坚持不下去,时间久了感觉收获不大,不会的依旧还是不会。本文以实例分析,达到先回用,再学原理。

本文目标

  • 能看懂GPUImage3中的绝大部分滤镜
  • 能实现一个自己想要的滤镜

常用类型

  • half : 一个16-bit浮点数,符合IEEE754的16位二进制浮点数存储格式规范
  • half4 :向量数据类型,4分量为half
  • half4x4:矩阵数据类型
  • constexpr sampler 采样器
  • texture2d 2d纹理

更多参考这篇文章: https://xiaozhuanlan.com/topic/1568709324

常用函数

  • dot 点击
  • mix 将值限制在两个其他值之间并做融合,常用于颜色混合:mix(x,y,a) = x(1-a)+ya
  • floor 向下取整
  • ceil 向上取整
  • clamp 用来将某个值“钳”住、限制在某个区间(minVal~maxVal)
  • max 最大值
  • atan2 反正切
  • sqrt 平方根
  • sin 正弦函数
  • cos 余弦函数
  • pow 指数函数
  • step 阈值函数

知识回顾

之前我们已经完成过画一个矩形,以及渲染一张图,用到过vertex shader、fragmentshader;

  • vertex shader :负责顶点坐标,纹理坐标
  • fragment shader : 负责每个像素的颜色;

Metal的使用流程搭建好之后(自己实现一张图的显示,然后看GPUImage3框架),我们只需编码vertex shader、fragment shader即可实现想要的效果;

注意:vertex shader 的输出是fragment shader的输入参数之一;

有没有注释版本的GPUImage?

答:https://github.com/Tliens/GPUImageByMetal

我几乎把整个工程都加上了中文注释,目前还剩下一部分滤镜没有完成,应该可以帮到你,喜欢不要吝啬star🌟。

GPUImage的滤镜效果来源于哪里?灵感吗?我想绝大部分是photoshop的算法。如:ContrastAdjustment

photoshop调节对比度的公式 nRGB = RGB + (RGB - Threshold) * Contrast

fragment half4 contrastFragment(SingleInputVertexIO fragmentInput [[stage_in]],                                 texture2d<half> inputTexture [[texture(0)]],                                 constant ContrastUniform& uniform [[ buffer(1) ]]) {     constexpr sampler quadSampler;     half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);     // photoshop调节对比度的公式 nRGB = RGB + (RGB - Threshold) * Contrast     // Threshold是平均亮度 默认选0.5     return half4(((color.rgb + (color.rgb - half3(0.5)) * uniform.contrast)), color.a); }

因此,想要什么样的效果需要先在PS中调整,然后将相关算法翻译成shader

一、颜色翻转滤镜

颜色翻转?其实就是(1.0 - color.rgb),这就是算法,转成shader

fragment half4 colorInversionFragment(SingleInputVertexIO fragmentInput [[stage_in]],                                  texture2d<half> inputTexture [[texture(0)]]) {     constexpr sampler quadSampler;     half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);      return half4((1.0 - color.rgb), color.a); }
// 单输入顶点 struct SingleInputVertexIO {     float4 position [[position]];     float2 textureCoordinate [[user(texturecoord)]]; };
  • half4先理解成4个float
  • constexpr sampler quadSampler 采样器
  • half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate); 根据纹理、纹理坐标获取该点颜色
  • return half4((1.0 - color.rgb), color.a);返回值为half4
现在你可以动手实现一个滤镜了,比如当r 大于 0.5时, r = 1.0 - r,其他不变,试一试效果吧!

如下:

 half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);     if (color.r > 0.5) {           return half4(1-color.r, color.g, color.b, color.a);     } else{         return half4((1.0 - color.rgb), color.a);   }

二、luminance

在此之前我们看一个数学公式。
点积dot
dot 两个数组点积、点乘 [1,2,3]·[4,5,6] = 1×1 + 2×3 + 3×6 = 1+6+18 = 25

上代码:

fragment half4 luminanceFragment(SingleInputVertexIO fragmentInput [[stage_in]],                                   texture2d<half> inputTexture [[texture(0)]]) {     constexpr sampler quadSampler;     half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);     //dot 两个数组点积、点乘 [1,2,3]·[4,5,6] = 1*1 + 2*3 + 3*6 = 1+6+18 = 25     //luminanceWeighting为亮度常量     half luminance = dot(color.rgb, luminanceWeighting);      return half4(half3(luminance), color.a); }

luminance滤镜 实际上是dot(color.rgb, luminanceWeighting)

luminanceWeighting = half3(0.2125, 0.7154, 0.0721)

这是一个亮度常量,滤镜为什么这么写?算法是怎么来的?为何用点积?

答:这是公认的一种效果,调节时就按照现有方式调节。

thresholdFragment

能不能有个动态的滤镜,可以根据外界值进行变化?

typedef struct {     float threshold; } ThresholdUniform;  // 阈值滤镜  阈值的大小是动态的设置的 fragment half4 thresholdFragment(SingleInputVertexIO fragmentInput [[stage_in]],                                   texture2d<half> inputTexture [[texture(0)]],                                   constant ThresholdUniform& uniform [[ buffer(1) ]]) {     constexpr sampler quadSampler;     half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);      half luminance = dot(color.rgb, luminanceWeighting);     // step luminance >= half(uniform.threshold) 的值为1,小于则为0     half thresholdResult = step(half(uniform.threshold), luminance);      return half4(half3(thresholdResult), color.w); }

threshold就是个可变的值。

原因

问题:Metal中的vertex shader、fragment shader该如何编写?
我发现很难在网络中找到相关的话题,MSL的介绍也比较少,之前翻译过MSL指南,坚持不下去,时间久了感觉收获不大,不会的依旧还是不会。本文以实例分析,达到先回用,再学原理。

本文目标

  • 能看懂GPUImage3中的绝大部分滤镜
  • 能实现一个自己想要的滤镜

常用类型

  • half : 一个16-bit浮点数,符合IEEE754的16位二进制浮点数存储格式规范
  • half4 :向量数据类型,4分量为half
  • half4x4:矩阵数据类型
  • constexpr sampler 采样器
  • texture2d 2d纹理

更多参考这篇文章: https://xiaozhuanlan.com/topic/1568709324

常用函数

  • dot 点击
  • mix 将值限制在两个其他值之间并做融合,常用于颜色混合:mix(x,y,a) = x(1-a)+ya
  • floor 向下取整
  • ceil 向上取整
  • clamp 用来将某个值“钳”住、限制在某个区间(minVal~maxVal)
  • max 最大值
  • atan2 反正切
  • sqrt 平方根
  • sin 正弦函数
  • cos 余弦函数
  • pow 指数函数
  • step 阈值函数

知识回顾

之前我们已经完成过画一个矩形,以及渲染一张图,用到过vertex shader、fragmentshader;

  • vertex shader :负责顶点坐标,纹理坐标
  • fragment shader : 负责每个像素的颜色;

Metal的使用流程搭建好之后(自己实现一张图的显示,然后看GPUImage3框架),我们只需编码vertex shader、fragment shader即可实现想要的效果;

注意:vertex shader 的输出是fragment shader的输入参数之一;

有没有注释版本的GPUImage?

答:https://github.com/Tliens/GPUImageByMetal

我几乎把整个工程都加上了中文注释,目前还剩下一部分滤镜没有完成,应该可以帮到你,喜欢不要吝啬star🌟。

GPUImage的滤镜效果来源于哪里?灵感吗?我想绝大部分是photoshop的算法。如:ContrastAdjustment

photoshop调节对比度的公式 nRGB = RGB + (RGB - Threshold) * Contrast

fragment half4 contrastFragment(SingleInputVertexIO fragmentInput [[stage_in]],                                 texture2d<half> inputTexture [[texture(0)]],                                 constant ContrastUniform& uniform [[ buffer(1) ]]) {     constexpr sampler quadSampler;     half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);     // photoshop调节对比度的公式 nRGB = RGB + (RGB - Threshold) * Contrast     // Threshold是平均亮度 默认选0.5     return half4(((color.rgb + (color.rgb - half3(0.5)) * uniform.contrast)), color.a); }

因此,想要什么样的效果需要先在PS中调整,然后将相关算法翻译成shader

一、颜色翻转滤镜

颜色翻转?其实就是(1.0 - color.rgb),这就是算法,转成shader

fragment half4 colorInversionFragment(SingleInputVertexIO fragmentInput [[stage_in]],                                  texture2d<half> inputTexture [[texture(0)]]) {     constexpr sampler quadSampler;     half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);      return half4((1.0 - color.rgb), color.a); }
// 单输入顶点 struct SingleInputVertexIO {     float4 position [[position]];     float2 textureCoordinate [[user(texturecoord)]]; };
  • half4先理解成4个float
  • constexpr sampler quadSampler 采样器
  • half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate); 根据纹理、纹理坐标获取该点颜色
  • return half4((1.0 - color.rgb), color.a);返回值为half4
现在你可以动手实现一个滤镜了,比如当r 大于 0.5时, r = 1.0 - r,其他不变,试一试效果吧!

如下:

 half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);     if (color.r > 0.5) {           return half4(1-color.r, color.g, color.b, color.a);     } else{         return half4((1.0 - color.rgb), color.a);   }

二、luminance

在此之前我们看一个数学公式。
点积dot
dot 两个数组点积、点乘 [1,2,3]·[4,5,6] = 1×1 + 2×3 + 3×6 = 1+6+18 = 25

上代码:

fragment half4 luminanceFragment(SingleInputVertexIO fragmentInput [[stage_in]],                                   texture2d<half> inputTexture [[texture(0)]]) {     constexpr sampler quadSampler;     half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);     //dot 两个数组点积、点乘 [1,2,3]·[4,5,6] = 1*1 + 2*3 + 3*6 = 1+6+18 = 25     //luminanceWeighting为亮度常量     half luminance = dot(color.rgb, luminanceWeighting);      return half4(half3(luminance), color.a); }

luminance滤镜 实际上是dot(color.rgb, luminanceWeighting)

luminanceWeighting = half3(0.2125, 0.7154, 0.0721)

这是一个亮度常量,滤镜为什么这么写?算法是怎么来的?为何用点积?

答:这是公认的一种效果,调节时就按照现有方式调节。

thresholdFragment

能不能有个动态的滤镜,可以根据外界值进行变化?

typedef struct {     float threshold; } ThresholdUniform;  // 阈值滤镜  阈值的大小是动态的设置的 fragment half4 thresholdFragment(SingleInputVertexIO fragmentInput [[stage_in]],                                   texture2d<half> inputTexture [[texture(0)]],                                   constant ThresholdUniform& uniform [[ buffer(1) ]]) {     constexpr sampler quadSampler;     half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate);      half luminance = dot(color.rgb, luminanceWeighting);     // step luminance >= half(uniform.threshold) 的值为1,小于则为0     half thresholdResult = step(half(uniform.threshold), luminance);      return half4(half3(thresholdResult), color.w); }

threshold就是个可变的值。

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » 基础部分(六)分析GPUImage3中的MSL–编写自己的滤镜求职学习资料
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们