如何在GL ES中让片元着色器生成的星芒渐变从黑色改为透明过渡
问题根源
- 片元着色器输出的alpha值固定为1.0,光晕边缘亮度较低的区域会输出深灰色甚至纯黑的不透明像素,多颗星叠加时深色边缘就会形成明显的黑边
- 未针对发光星点配置正确的混合模式,自发光物体叠加应该使用加性混合逻辑,避免变暗
- 硬discard低于阈值的像素会导致边缘出现锯齿,无法实现自然的透明度过渡
修复方案
1. 修改片元着色器
重新计算alpha通道,修复中心除零异常,实现边缘自然透明衰减:
varying vec3 vGlow; void main() { float starLuminosity = 250.0; float invRadius = 60.0; float invGlowRadius = 2.5; float alphaCutoff = 0.01; // 计算相对于点中心的坐标 vec2 position = gl_PointCoord - 0.5; float dist = length(position); // 加极小值避免中心距离为0时出现除零错误 float diskScale = dist * invRadius + 1e-6; // 艾里斑计算 vec3 glow = vGlow / pow(diskScale, invGlowRadius); glow *= starLuminosity; // 取RGB最大值作为透明度基准,也可替换为灰度计算适配不同星点颜色 float alpha = max(max(glow.r, glow.g), glow.b); // 平滑过渡边缘,避免硬切 alpha = smoothstep(alphaCutoff, 0.1, alpha); // 可选:丢弃透明度极低的像素,优化渲染性能 if (alpha < alphaCutoff) { discard; } gl_FragColor = vec4(glow, alpha); }
2. 调整Three.js材质配置
开启透明和加性混合,关闭深度写入避免透明区域遮挡错误:
const starMaterial = new THREE.ShaderMaterial({ vertexShader: 你的顶点着色器代码, fragmentShader: 修改后的片元着色器代码, transparent: true, // 加性混合适配发光效果,叠加时只会提升亮度不会出现暗边 blending: THREE.AdditiveBlending, // 关闭深度写入,避免近处星点的透明区域遮挡远处星点 depthWrite: false, // 保留深度测试保证星点会被行星等不透明天体遮挡 depthTest: true });
如果效果不符合预期,可以调整starLuminosity、invGlowRadius的数值控制光晕亮度和衰减速度,也可以调整smoothstep的两个阈值参数调整边缘过渡的软硬程度。
内容的提问来源于stack exchange,提问作者aggregate1166877
相关产品推荐
相关产品推荐

