I need to center it on a 2D texture when adjusting fit/fill texture in the view, but I can't configure uv coords.
When adjust fill, show the first part of the image not the center:
when adjust fit, not get the correct center:
float2 adjustPos(float2 size,
float2 uv) {
uv.x /= size.x;
uv.y /= size.y;
uv.y = 1.0f - uv.y;
return uv;
}
float2 scaleTexture(texture2d<float, access::sample> tex2d,
float2 size,
float2 uv,
int mode) {
int width = tex2d.get_width();
int height = tex2d.get_height();
float widthRatio = size.x/width;
float heightRatio = size.y/height;
float2 pos;
if (mode == 0) { // Aspect Fit
int2 newSize = int2(width*widthRatio, height*widthRatio);
pos = adjustPos(float2(newSize), uv);
float y = (uv.y/size.y) / 2.0;
y = y-pos.y;
y = 1.0f-y;
pos.y = y;
} else if (mode == 1) { // Aspect Fill
int2 newSize = int2(width*heightRatio, height*heightRatio);
pos = adjustPos(float2(newSize), uv);
if (newSize.x != size.x) {
pos.x = 0.5f + ((pos.x - 0.5f) * (1.0f - (heightRatio/100)));
}
} else {
float scale = min(widthRatio, heightRatio);
int2 newSize = int2(width*scale, height*scale);
pos = adjustPos(float2(newSize), uv);
}
return pos;
}
You can use this shader and customize it as per your requirements. This solution will let you make a texture fit fill within a given size.
The following metal shader takes a texture, an output size, expected content mode, and returns a fit/fill image within the given size.
fragment float4 fragment_aspect_fitfill(
VertexOut vertexIn [[stage_in]],
texture2d<float, access::sample> sourceTexture [[texture(0)]],
sampler sourceSampler [[sampler(0)]],
constant float2 &size [[ buffer(0) ]],
constant float &contentMode [[ buffer(1) ]])
{
float2 uv = vertexIn.textureCoordinate;
//Calculate Aspect Ration for both Texture and Expected output texture
float textureAspect = (float)sourceTexture.get_width() / (float)sourceTexture.get_height();
float frameAspect = (float)size.x / (float)size.y;
float scaleX = 1, scaleY = 1;
float textureFrameRatio = textureAspect / frameAspect;
bool portraitTexture = textureAspect < 1;
bool portraitFrame = frameAspect < 1;
// Content mode 0 is for aspect Fill, 1 is for Aspect Fit
if(contentMode == 0.0) {
if(portraitFrame)
scaleX = 1.f / textureFrameRatio;
else
scaleY = textureFrameRatio;
} else if(contentMode == 1.0) {
if(portraitFrame)
scaleY = textureFrameRatio;
else
scaleX = 1.f / textureFrameRatio;
}
float2 textureScale = float2(scaleX, scaleY);
float2 vTexCoordinate = textureScale * (uv - 0.5) + 0.5;
return sourceTexture.sample(sourceSampler, vTexCoordinate);
}
*Tips: This MSL uses some struct
of MetalPetal
.