如何用GLSL实现边框模糊效果?求助解决边角斜线问题
解决边缘向内模糊着色器的边角斜线问题及优化思路
一、修复现有着色器的核心问题
边角的斜线通常是矩形边缘距离计算错误或采样边界未约束导致的,直接修改这两点就能解决:
1. 替换错误的边缘距离计算
如果之前用的是圆形距离(比如length(vUv - 0.5)),会在矩形边角处产生距离突变,换成矩形最短边缘距离计算:
// 计算从当前UV到最近矩形边缘的距离,边角处不会突变 float getEdgeDistance(vec2 uv) { vec2 distToEdge = min(uv, 1.0 - uv); return min(distToEdge.x, distToEdge.y); }
2. 约束采样UV范围+优化模糊采样
采样时必须把UV限制在[0,1]区间,避免取到纹理外的错误像素;同时根据边缘距离动态控制模糊强度:
完整片元着色器示例(配合简单顶点着色器):
// 顶点着色器 varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }
// 片元着色器 uniform sampler2D uTexture; uniform float uBlurRadius; uniform vec2 uResolution; // 传入纹理分辨率,比如vec2(1024, 1024) varying vec2 vUv; float getEdgeDistance(vec2 uv) { vec2 distToEdge = min(uv, 1.0 - uv); return min(distToEdge.x, distToEdge.y); } void main() { // 获取边缘距离,距离越小越靠近边缘 float edgeDist = getEdgeDistance(vUv); // 控制模糊强度:边缘处模糊最强,向内逐渐减弱(0.2是过渡宽度,可自行调整) float blurStrength = 1.0 - smoothstep(0.0, 0.2, edgeDist); // 高斯模糊采样,带权重计算 vec3 finalColor = vec3(0.0); float totalWeight = 0.0; const int sampleNum = 5; // 采样次数,越多越平滑性能越低 for(int x = -sampleNum; x <= sampleNum; x++) { for(int y = -sampleNum; y <= sampleNum; y++) { float weight = exp(-(x*x + y*y)/(2.0*uBlurRadius*uBlurRadius)); vec2 sampleOffset = vec2(x, y) * uBlurRadius * blurStrength / uResolution; // 约束UV在0-1之间,避免采样到纹理外 vec2 sampleUv = clamp(vUv + sampleOffset, 0.0, 1.0); finalColor += texture2D(uTexture, sampleUv).rgb * weight; totalWeight += weight; } } finalColor /= totalWeight; gl_FragColor = vec4(finalColor, 1.0); }
二、更自然的边缘模糊实现思路
如果不想在RawShaderMaterial里硬写模糊,推荐用后处理+遮罩混合的方式,性能更好、效果更可控:
- 第一步:把需要添加光束投影效果的场景/物体渲染到RenderTexture
- 第二步:对这个RenderTexture做高斯模糊(可以用Three.js自带的
UnrealBloomPass或自定义高斯模糊后处理) - 第三步:写一个简单的混合着色器,根据UV的边缘距离,将原清晰纹理和模糊纹理混合——边缘区域显示模糊后的画面,中心区域保留清晰画面
- 额外优化:可以给边缘遮罩加平滑过渡曲线,比如用
smoothstep或自定义的缓动函数,让模糊过渡更自然
内容的提问来源于stack exchange,提问作者small wombat
相关产品推荐
相关产品推荐

