前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OpenGL & Metal Shader 编程:解决图片拉伸变形问题

OpenGL & Metal Shader 编程:解决图片拉伸变形问题

作者头像
字节流动
发布2023-09-04 17:56:52
4210
发布2023-09-04 17:56:52
举报
文章被收录于专栏:字节流动字节流动

前面发了一些关于 Shader 编程的文章,有读者反馈太碎片化了,希望这里能整理出来一个系列,方便系统的学习一下 Shader 编程。

由于主流的 Shader 编程网站,如 ShaderToy, gl-transitions 都是基于 GLSL 开发 Shader ,加上 MSL 和 GLSL 语法上差别不大,后面系列文章将以 GLSL 为主来介绍 Shader 编程。

后面 Shader 编程将使用 VSCode + ShaderToy 插件作为编程环境,步骤如下:

  1. 下载安装 VSCode https://code.visualstudio.com/download;
  2. 安装 ShaderToy 插件;
  1. 新建以 .frag 为后缀名的文件,复制粘贴本文的代码;
  2. 当前代码,点击鼠标右键,选择 ShaderToy:Show GLSL Preview , 然后就可以愉快地调试特效了。

图片拉伸变形问题

代码语言:javascript
复制
#iChannel0 "https://img-baofun.zhhainiao.com/pcwallpaper_ugc_mobile/static/2ddf8479959f1f3d9f52d0d561d281fe.jpg"

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    fragColor = texture2D(iChannel0, uv);
}

我们使用上述代码对纹理通道进行采样,渲染一张图像,可以看到当调整窗口尺寸(iResolution)的时候,图像会因为铺满整个窗口而产生拉伸变形情况。

变形的原因这里其实就很好理解了,就是图片宽高比和窗口(视口)的宽高比不同导致的,图像在横轴和纵轴方向产生不同的 resize 强度,最终渲染出来的结果会有拉伸或者压缩的感觉

iChannelResolution 纹理尺寸

vec3 iChannelResolution[4] 表示各个纹理通道的分辨率(宽度、高度和深度)。通道0对应sampler2D iChannel0,通道1对应sampler2D iChannel1,以此类推。

这个 ShaderToy 全局变量单独拿出来讲,因为纹理尺寸在实际开发中会频繁用到,主要用来解决图像的拉伸问题。

有了纹理尺寸,我们就可以在窗口中找一块宽高比和图像一样的区域,只让图像渲染到这块区域,从而避免图像拉伸。

代码语言:javascript
复制
#iChannel0 "https://img-baofun.zhhainiao.com/pcwallpaper_ugc_mobile/static/2ddf8479959f1f3d9f52d0d561d281fe.jpg"

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;

    //纹理尺寸
    vec2 imgSize = iChannelResolution[0].xy;
    //窗口尺寸
    vec2 viewPort = iResolution.xy;

    //图像宽高比
    float imgRatio = imgSize.x / imgSize.y;
    //窗口宽高比
    float screenRatio = viewPort.x / viewPort.y;

    //resizeTarget 表示窗口中与图像宽高比保持一致的区域大小
    vec2 resizeTarget = viewPort;

    //窗口中与图像宽高比保持一致的区域的位置
    vec2 startPos = vec2(0.0);
    //与窗口的一个边对齐,使图像渲染在窗口中央
    if(imgRatio > screenRatio) {
        resizeTarget.x = viewPort.x;
        resizeTarget.y = resizeTarget.x / imgRatio;
        startPos.y = (viewPort.y - resizeTarget.y) / 2.0;
    } else {
        resizeTarget.y = viewPort.y;
        resizeTarget.x = resizeTarget.y * imgRatio;
        startPos.x = (viewPort.x - resizeTarget.x) / 2.0;
    }

    //窗口中与图像宽高比保持一致的区域内渲染图像
    if(fragCoord.x >= startPos.x && fragCoord.x <= startPos.x + resizeTarget.x 
    && fragCoord.y >= startPos.y && fragCoord.y <= startPos.y + resizeTarget.y) {
        uv.x = (fragCoord.x - startPos.x) / resizeTarget.x;
        uv.y = (fragCoord.y - startPos.y) / resizeTarget.y;
        fragColor = texture2D(iChannel0, uv);
    } else {
        fragColor = vec4(0.0);
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-06-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 字节流动 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 图片拉伸变形问题
  • iChannelResolution 纹理尺寸
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档