GLSL片段着色器中曲线旋转与平移的正确实现方法
如何在GLSL片段着色器中实现曲线的旋转与平移
我来帮你搞定这个问题——在GLSL片段着色器里实现曲线的旋转和平移,核心思路其实和你在MATLAB里的思路反过来,因为片段着色器是逐像素计算的,不能直接像CPU那样遍历曲线点绘制,得用逆变换来判断当前像素是否属于变换后的曲线。
核心逻辑梳理
你想要的流程是:局部坐标系定义曲线 → 旋转 → 平移 → 输出到屏幕,但在片段着色器中,我们需要逆着这个流程处理:
- 把当前屏幕像素坐标转换为归一化设备坐标(NDC)
- 对该坐标做逆平移(减去平移量)
- 再做逆旋转(旋转负角度,因为旋转矩阵是正交矩阵,逆矩阵等于转置或负角度旋转)
- 得到局部坐标系下的坐标后,判断它是否符合你定义的曲线方程
完整实现代码
下面是一个可以直接在Book of Shaders Editor中运行的示例,模拟随时间旋转平移的正弦曲线:
precision highp float; uniform vec2 resolution; uniform float time; // 生成旋转矩阵(输入弧度角度) mat2 rotate(float a) { float c = cos(a); float s = sin(a); return mat2(c, -s, s, c); } void main() { // 1. 将屏幕像素坐标转为归一化设备坐标(NDC),保持宽高比避免拉伸 vec2 uv = (gl_FragCoord.xy * 2.0 - resolution.xy) / min(resolution.x, resolution.y); // 2. 定义变换参数(这里用time实现动画,和MATLAB的动画逻辑对齐) vec2 translate = vec2(cos(time * 0.5) * 0.3, sin(time * 0.5) * 0.3); // 随时间平移 float angle = time * 0.3; // 随时间旋转 // 3. 逆变换:将NDC坐标转回局部坐标系 vec2 local_uv = rotate(-angle) * (uv - translate); // 4. 局部坐标系中的曲线定义:这里是正弦曲线,5.0是频率控制波的密度 float curve_y = sin(local_uv.x * 5.0); // 5. 判断当前像素是否在曲线附近,用smoothstep实现抗锯齿边缘 float distance_to_curve = abs(local_uv.y - curve_y); float line_width = 0.01; // 曲线宽度 float alpha = smoothstep(line_width, line_width * 0.5, distance_to_curve); // 6. 输出颜色:红色曲线,黑色背景 vec3 color = vec3(1.0, 0.0, 0.0) * alpha; gl_FragColor = vec4(color, 1.0); }
常见错误排查
你之前尝试没达到预期,大概率是踩了这些坑:
- 搞反变换顺序:如果先做逆旋转再逆平移,旋转中心会变成屏幕原点,而不是你局部曲线的原点,必须先逆平移再逆旋转
- 没有保持宽高比:直接用
resolution.x或y归一化会导致曲线拉伸,一定要用min(resolution.x, resolution.y)来统一缩放 - 直接变换曲线点:片段着色器是逐像素计算的,不能像MATLAB那样生成曲线点再变换,必须用逆变换判断当前像素是否属于变换后的曲线
- 缺少抗锯齿:直接用
step函数会让曲线边缘有严重锯齿,smoothstep可以实现平滑过渡
扩展到其他曲线
如果要实现其他曲线,只需要修改局部坐标系的曲线定义即可:
- 抛物线:
float curve_y = local_uv.x * local_uv.x; - 圆(局部坐标系下单位圆的上半部分):
float curve_y = sqrt(1.0 - local_uv.x * local_uv.x);
内容的提问来源于stack exchange,提问作者remi
相关产品推荐
相关产品推荐

