如何使用片段着色器实现类似Processing效果的鼠标拖拽轨迹
基于WebGL片段着色器实现Processing风格鼠标轨迹的解决方案
现有代码问题定位
- 混合系数错误:你当前使用的
stack*2.逻辑会让历史帧的颜色值不断超过1.0的有效范围,导致历史轨迹快速溢出丢失,仅鼠标附近的内容能正常显示 - 缺少数值钳制:计算得到的
pct可能出现负数,叠加后会抵消历史轨迹的正常颜色
核心实现逻辑
Processing不清除画布的堆叠绘制效果,本质是新绘制内容直接叠加到上一帧的画布结果。WebGL中可以通过ping-pong FBO(双离屏帧缓存)技术实现同样效果,不需要额外存储鼠标坐标历史数据:
- 创建两个相同尺寸的纹理和对应的帧缓存对象,交替作为「上一帧结果输入」和「当前帧渲染输出」
- 每帧先读取上一帧的纹理作为背景,再叠加当前鼠标位置的画笔图形,输出到另一个帧缓存
- 最后将存储了完整轨迹的帧缓存纹理渲染到屏幕即可
修正后代码示例
# 离屏渲染Pass:叠加新内容到历史轨迹 void main(void) { float pct = 0.0; pct = distance(inData.v_texcoord.xy, vec2(mouse.x, 1.-mouse.y)) * SIZE; pct = 1.0 - pct - BRIGHTNESS; // 钳制数值避免负数 pct = max(pct, 0.0); vec3 blob = vec3(pct); // 读取上一帧轨迹 vec3 stack = texture(prevPass, inData.v_texcoord.xy).xyz; // 混合逻辑:完全保留历史轨迹 + 叠加当前画笔内容 // 如果需要轨迹缓慢消失,可以改为 stack * 0.99 + blob * 0.1 fragColor = vec4(stack + blob * 0.1, 1.0); }
# 屏幕输出Pass:把轨迹纹理渲染到画布 void main(void) { fragColor = texture(prevPass, inData.v_texcoord); }
注意事项
- 初始化的时候需要先将存储历史的纹理填充为背景色(对应你Processing示例里的
background(255)) - 渲染离屏Pass的时候不要开启颜色清除,否则上一帧的结果会被清空
- 如果要实现半透明轨迹的效果,可以调整
blob的透明度系数,或者给混合逻辑加alpha通道处理
内容的提问来源于stack exchange,提问作者msalla
相关产品推荐
相关产品推荐

