我一直在努力使用opengl编写的以下着色器以迅捷的速度工作: https://github.com/gl-transitions/gl-transitions/blob/master/transitions/SimpleZoom.glsl 我在着色器函数中使用内核方法,以下是所得视频的一个输出帧。 Image frame during zoom
我也写了其他一些可以成功工作的着色器,但是在此着色器上停留了5个多小时。
当前代码:
#include <metal_stdlib>
using namespace metal;
float2 zoom(float2 uv, float amount)
{
return 0.5f + ((uv - 0.5f) * (1.0f - amount));
}
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));
}
float4 transition(texture2d<float, access::sample> fromTexture,
texture2d<float, access::sample> toTexture,
float nQuick,
float progress,
float2 uv
)
{
uv.x /= fromTexture.get_width();
uv.y /= fromTexture.get_height();
uv.y = 1.0f - uv.y;
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));
}
kernel void transition_simplezoom(texture2d<float, access::sample> inTexture [[ texture(0) ]],
texture2d<float, access::sample> inTexture2 [[ texture(1) ]],
texture2d<float, access::write> outTexture [[ texture(2) ]],
device const float *progress [[ buffer(1) ]],
device float *result [[buffer(0)]],
device const float *zoom_quickness [[buffer(2)]],
uint2 gid [[ thread_position_in_grid ]])
{
float zoomQuickness = *zoom_quickness;
float prog = *progress;
prog = 1.0 - prog;
float2 ngid = float2(gid);``
float nQuick = clamp(zoomQuickness, 0.2, 1.0);
return outTexture.write(transition(inTexture, inTexture2, nQuick, prog, float2(ngid)),
gid);
}
调度线程组:
guard let commandBuffer = commandQueue.makeCommandBuffer(), let computeCommandEncoder = commandBuffer.makeComputeCommandEncoder() else {
return nil
}
// Set the compute pipeline state for the command encoder.
computeCommandEncoder.setComputePipelineState(computePipelineState)
// Set the input and output textures for the compute shader.
computeCommandEncoder.setTexture(inputTexture, index: 0)
computeCommandEncoder.setTexture(inputTexture1, index: 1)
computeCommandEncoder.setTexture(inputTexture2, index: 2)
let threadGroupCount = MTLSizeMake(1, 1, 1)
let threadGroups: MTLSize = {
MTLSizeMake(Int(1280) / threadGroupCount.width, Int(720) / threadGroupCount.height, 1)
}()
computeCommandEncoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount)
答案 0 :(得分:2)
在转换此着色器时,我尝试保持尽可能接近原始材质的精神和结构。但是,由于GLSL和MSL之间存在显着差异,因此我不得不采取一些自由措施:
constant
缓冲区的形式到达话虽如此,这是我最好的尝试,它可以实现您所需的缩放效果的Metal着色器:
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
变量,随时间变化以执行缩放动画。