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

Three.js Points与BufferGeometry:如何将点渲染为圆形

嘿,针对你在Three.js粒子球体上要把点改成圆形或纹理的需求,我整理了两种直接可行的方案,直接修改片元着色器就能实现:

方案一:渲染平滑圆形粒子

要让每个粒子变成圆润的圆点,核心是根据片元距离点中心的距离来控制透明度,超出半径的部分直接透明。修改你的片元着色器代码如下:

uniform float uTime;
varying vec3 vColor;
varying vec2 vUv;

precision mediump float;

void main() {
    // 计算当前片元到点中心的距离(gl_PointCoord的范围是0-1,中心在(0.5,0.5))
    vec2 toCenter = gl_PointCoord - vec2(0.5);
    float distanceToCenter = length(toCenter);
    
    // 定义圆形半径,0.5是填满整个点的大小,调小一点比如0.4会让边缘更柔和
    float radius = 0.5;
    // 用smoothstep做平滑过渡,避免硬边缘锯齿
    float alpha = smoothstep(radius, radius - 0.05, distanceToCenter);
    
    // 透明度太低的片元直接丢弃,节省性能
    if (alpha < 0.1) discard;
    
    // 最终颜色结合粒子自身颜色和透明度
    gl_FragColor = vec4(vColor, alpha);
}

关键细节说明:

  • gl_PointCoord是Three.js内置的变量,代表当前片元在点精灵里的坐标,范围从(0,0)到(1,1)
  • smoothstep函数能帮你生成平滑的透明度过渡,比直接用step函数的硬边缘好看很多
  • 用discard丢弃透明度过低的片元,避免这些无效片元占用渲染资源
方案二:渲染带纹理的粒子

如果要给粒子贴自定义纹理,需要先在JS代码里加载纹理并传给着色器,再修改片元着色器采样纹理:

第一步:在JS中加载并传递纹理

先把纹理加载好,作为uniform变量传给着色器材质:

// 用Three.js的TextureLoader加载纹理,替换成你的纹理路径
const textureLoader = new THREE.TextureLoader();
const particleTexture = textureLoader.load('your-texture.png');

// 创建着色器材质时传递纹理uniform
const particleMaterial = new THREE.ShaderMaterial({
    uniforms: {
        uTexture: { value: particleTexture },
        uTime: { value: 0 },
        // 保留你原本的其他uniform变量
    },
    vertexShader: 你的顶点着色器代码,
    fragmentShader: 下面的片元着色器代码,
    transparent: true, // 必须开启透明,因为纹理大概率有透明通道
    // 可选:如果需要粒子叠加效果,开启AdditiveBlending
    blending: THREE.AdditiveBlending,
});

第二步:修改片元着色器采样纹理

uniform sampler2D uTexture;
uniform float uTime;
varying vec3 vColor;
varying vec2 vUv;

precision mediump float;

void main() {
    // 用gl_PointCoord作为纹理坐标,采样纹理颜色
    vec4 textureColor = texture2D(uTexture, gl_PointCoord);
    
    // 纹理透明度过低的片元直接丢弃
    if (textureColor.a < 0.1) discard;
    
    // 可以把粒子自身颜色和纹理颜色混合,也可以直接用纹理颜色
    gl_FragColor = textureColor * vec4(vColor, 1.0);
}

额外玩法:给纹理加动画或重复效果

如果想让纹理动起来或者重复显示,可以加几个uniform变量调整:

uniform vec2 uRepeat; // 比如设为vec2(2.0, 2.0)让纹理重复2次
uniform float uTime;

void main() {
    // 让纹理水平滚动,同时重复显示
    vec2 textureUv = gl_PointCoord * uRepeat + vec2(uTime * 0.1, 0.0);
    vec4 textureColor = texture2D(uTexture, textureUv);
    
    if (textureColor.a < 0.1) discard;
    gl_FragColor = textureColor * vec4(vColor, 1.0);
}
注意事项
  • 不管用哪种方案,都要确保材质开启了transparent: true,否则透明效果不会生效
  • 如果粒子边缘有锯齿,可以尝试开启材质的alphaTest,或者调整smoothstep的参数让过渡更柔和
  • 用纹理的话,尽量选带透明通道的PNG格式,这样纹理的透明部分才能正常显示

内容的提问来源于stack exchange,提问作者Yuri Stiopin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:30:44