@@ -0,0 +1,86 @@
// Gradient Shader for arbitrary gradient stops, three gradient types and rotation
// For the details please visit: https://mtldoc.com/metal/2022/08/04/shaders-explained-gradients.html
// MARK: - Gradient Texture
struct GradientTextureVertex {
float4 position [[ position ]];
float4 color;
};
[[ vertex ]]
GradientTextureVertex gradientTextureVertex (constant float * positions [[ buffer(0 ) ]],
constant float4* colors [[ buffer(1 ) ]],
const ushort vid [[ vertex_id ]]) {
return {
.position = float4 (fma (positions[vid], 2 .0f , -1 .0f ), 0 .0f , 0 .0f , 1 .0f ),
.color = colors[vid]
};
}
[[ fragment ]]
float4 gradientTextureFragment (GradientTextureVertex in [[ stage_in ]]) {
return in.color ;
}
// MARK: - Gradient
enum GradientType: uchar {
kLinear ,
kRadial ,
kAngular
};
struct GradientVertex {
float4 position [[ position ]];
float2 uv;
};
constant float2 positions[4 ] {
{ -1 .0f , 1 .0f },
{ -1 .0f , -1 .0f },
{ 1 .0f , 1 .0f },
{ 1 .0f , -1 .0f }
};
constant float2 uvs[4 ] {
{ 0 .0f , 0 .0f },
{ 0 .0f , 1 .0f },
{ 1 .0f , 0 .0f },
{ 1 .0f , 1 .0f }
};
constant float PI = 3 .1415926f ;
[[ vertex ]]
GradientVertex gradientVertex (constant float2x2& rotationTransform [[ buffer(0 ) ]],
const ushort vid [[ vertex_id ]]) {
return {
.position = float4 (positions[vid], 0 .0f , 1 .0f ),
.uv = (uvs[vid] - float2 (0 .5f )) * rotationTransform + float2 (0 .5f )
};
}
[[ fragment ]]
float4 gradientFragment (GradientVertex in [[ stage_in ]],
texture2d<float , access::sample> gradientTexture [[ texture(0 ) ]],
constant GradientType& gradientType [[ buffer(0 ) ]]) {
constexpr sampler s (filter::linear, coord::normalized, address::clamp_to_edge);
float2 texCoords;
switch (gradientType) {
case kLinear :
texCoords = in.uv ;
break ;
case kRadial :
texCoords = length (in.uv - float2 (0 .5f )) * 2 .0f ;
break ;
case kAngular :
const float2 offsetUV = in.uv - float2 (0 .5f );
const float angle = atan2 (offsetUV.y , offsetUV.x );
texCoords = float2 (fma (angle / PI, 0 .5f , 0 .5f ), 0 .0f );
break ;
}
return gradientTexture.sample (s, texCoords);
}