При преобразовании этого шейдера я старался максимально приблизиться к духу и структуре оригинала. Но, поскольку между GLSL и MSL есть существенные различия, мне пришлось взять на себя некоторые свободы:
- Предположим, что униформа и другие глобалы будут поступать в виде
constant
буферов - Передавайте параметры из фрагментного шейдера в служебные функции, а не обращайтесь к ним как к глобальным
С учетом вышесказанного, моя лучшая попытка использовать металлический шейдер, который выполняет желаемый эффект масштабирования:
struct VertexIn {
float2 position [[attribute(0)]];
float2 texCoords [[attribute(1)]];
};
struct VertexOut {
float4 position [[position]];
float2 texCoords;
};
float4 getColor(texture2d<float, access::sample> tex2d, float2 uv) {
constexpr sampler sampler2d(coord::normalized,
address::clamp_to_edge,
filter::linear,
mip_filter::linear);
return tex2d.sample(sampler2d, float2(uv.x, 1.0f - uv.y));
}
float2 zoom(float2 uv, float amount) {
return 0.5f + ((uv - 0.5f) * (1.0f - amount));
}
float4 transition (texture2d<float, access::sample> fromTexture,
texture2d<float, access::sample> toTexture,
float nQuick,
float progress,
float2 uv)
{
float4 fromColor = getColor(fromTexture, zoom(uv, smoothstep(0.0f, nQuick, progress)));
float4 toColor = getColor(toTexture, uv);
return mix(fromColor, toColor, smoothstep(nQuick - 0.2f, 1.0f, progress));
}
vertex VertexOut textured_vertex(VertexIn in [[stage_in]]) {
VertexOut out;
out.position = float4(in.position, 0.0f, 1.0f);
out.texCoords = in.texCoords;
return out;
}
fragment float4 zoomed_textured_fragment(VertexOut in [[stage_in]],
constant float& zoom_quickness [[buffer(0)]],
constant float& progress [[buffer(1)]],
texture2d<float, access::sample> fromTexture [[texture(0)]],
texture2d<float, access::sample> toTexture [[texture(1)]])
{
float nQuick = clamp(zoom_quickness, 0.2 , 1.0);
return transition(fromTexture, toTexture, nQuick, progress, in.texCoords);
}
Похоже, у вас уже есть код рендеринга, поэтому я просто отмечу, что я передаю параметры в виде отдельных константных буферов, используя следующий код Swift:
var zoomSpeed: Float = 0.5
renderCommandEncoder.setFragmentBytes(&zoomSpeed, length: MemoryLayout<Float>.size, index: 0)
renderCommandEncoder.setFragmentBytes(&progress, length: MemoryLayout<Float>.size, index: 1)
, где progress
- это Float
var, который изменяется со временем для выполнения анимации масштабирования.