You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

鼠标位置周围鱼眼变形片元着色器问题求助

解决鱼眼效果的定位问题&新手着色器改进建议

嘿,作为第一个着色器项目,能写出这样的代码已经很棒了!咱们先搞定你的鱼眼定位问题,再给你一些实用的改进小技巧~

核心问题:坐标转换逻辑错误

你的代码里,UV坐标的偏移计算和最终的位置叠加出现了问题,导致缩放效果的中心和预期不符。咱们拆解一下错误点:

  1. 偏移坐标归一化错误:vec2 xy = 2.0 * (myUV - u_mouse) - 1.0; 这段把相对于鼠标的偏移强制拉伸到了(-2, 2)范围,但没有结合你设定的u_radius做归一化,导致畸变的比例和鼠标位置脱节。
  2. UV位置叠加重复偏移:最后计算myUV时,你同时加了0.5和u_mouse.x/y,相当于把鼠标位置又偏移了半个纹理单位,直接打乱了中心定位。
  3. 未关联半径的距离计算:d = length(xy * maxFactor); 里的maxFactor如果没有和u_radius绑定,会导致畸变强度和你设定的生效范围不匹配。

修正后的鱼眼实现代码

下面是调整后的代码,我会逐行标注说明:

// 先确保u_mouse是0-1范围的纹理坐标(和myUV匹配)
#define PI 3.14159265359

uniform vec2 u_mouse;
uniform float u_radius; // 鱼眼生效的半径(0-1范围,比如0.2)
uniform float u_strength; // 畸变强度:<1是凸鱼眼(中心放大),>1是凹鱼眼(中心收缩)

void main() {
    vec2 myUV = gl_FragCoord.xy / resolution.xy; // 假设resolution是屏幕分辨率uniform
    vec2 texSize = vec2(textureSize(tMap, 0));
    myUV = (gl_FragCoord.xy - 0.5 * texSize) / texSize; // 可选:如果纹理和屏幕尺寸不一致,做适配

    // 计算到鼠标的偏移和距离
    vec2 offset = myUV - u_mouse;
    float distSq = dot(offset, offset);
    float radiusSq = u_radius * u_radius;

    // 避免分支语句,用smoothstep做平滑过渡(性能更好)
    float mask = smoothstep(radiusSq, radiusSq + 0.005, distSq); // 边缘平滑过渡
    vec2 distortedUV = myUV;

    if(distSq <= radiusSq) {
        float dist = sqrt(distSq);
        float normDist = dist / u_radius; // 归一化到0-1范围

        // 鱼眼畸变核心公式:用pow控制强度,替换你原来的atan逻辑(更直观易调)
        float distortedNormDist = pow(normDist, u_strength);
        float distortedDist = distortedNormDist * u_radius;

        // 计算方向向量,得到畸变后的UV
        vec2 dir = offset / dist;
        distortedUV = u_mouse + dir * distortedDist;
    }

    // 平滑混合原UV和畸变UV,避免生硬边缘
    vec2 finalUV = mix(distortedUV, myUV, mask);
    // 限制UV在0-1范围内,避免采样到纹理外
    finalUV = clamp(finalUV, 0.0, 1.0);

    vec3 tex = texture2D(tMap, finalUV).rgb;
    gl_FragColor = vec4(tex, 1.0);
}

新手着色器实用改进建议

  • 避免分支语句:GPU对分支语句的处理效率不高,用smoothstep或mix替代if,既能实现平滑过渡,又能提升性能。
  • 统一坐标范围:确保所有坐标(鼠标、UV)都在0-1的纹理空间内,如果鼠标是屏幕像素坐标,记得除以屏幕分辨率转换。
  • 添加可调节参数:把畸变强度、半径做成uniform变量,这样你可以实时调整效果,不用每次修改代码重新编译。
  • 纹理边界处理:用clamp(finalUV, 0.0, 1.0)限制UV范围,避免采样到纹理外的无效内容。
  • 定义常量:用#define PI 3.14159265359定义常量,避免重复写数值,也减少拼写错误。

如果还是想保留你原来的atan畸变逻辑,只需要把核心畸变部分替换成:

float d = length(offset / u_radius); // 归一化到单位圆内
float z = sqrt(1.0 - d * d);
float r = atan(d, z) / (PI/2.0); // 映射到0-1范围
vec2 dir = normalize(offset);
distortedUV = u_mouse + dir * r * u_radius;

这样就能得到和你参考示例类似的鱼眼变形效果啦!

内容的提问来源于stack exchange,提问作者Zach Saucier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 23:42:31