This commit is contained in:
56
js/globe.js
56
js/globe.js
@@ -58,11 +58,12 @@
|
|||||||
return 1 - Math.pow(1 - t, 3);
|
return 1 - Math.pow(1 - t, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 准备粒子数据:startPositions / targetPositions / current positions
|
// 准备粒子数据:startPositions / targetPositions / current positions / size
|
||||||
var geometry = new THREE.BufferGeometry();
|
var geometry = new THREE.BufferGeometry();
|
||||||
var positions = new Float32Array(PARTICLE_COUNT * 3);
|
var positions = new Float32Array(PARTICLE_COUNT * 3);
|
||||||
var startPositions = new Float32Array(PARTICLE_COUNT * 3);
|
var startPositions = new Float32Array(PARTICLE_COUNT * 3);
|
||||||
var targetPositions = new Float32Array(PARTICLE_COUNT * 3);
|
var targetPositions = new Float32Array(PARTICLE_COUNT * 3);
|
||||||
|
var sizes = new Float32Array(PARTICLE_COUNT);
|
||||||
|
|
||||||
// 随机在球壳表面生成点(均匀分布),作为目标位置
|
// 随机在球壳表面生成点(均匀分布),作为目标位置
|
||||||
function randomPointOnSphere(radius) {
|
function randomPointOnSphere(radius) {
|
||||||
@@ -108,19 +109,56 @@
|
|||||||
positions[i3] = start.x;
|
positions[i3] = start.x;
|
||||||
positions[i3 + 1] = start.y;
|
positions[i3 + 1] = start.y;
|
||||||
positions[i3 + 2] = start.z;
|
positions[i3 + 2] = start.z;
|
||||||
|
|
||||||
|
// 粒子尺寸:每个粒子随机一个基础大小,后续在顶点着色器中再做距离衰减
|
||||||
|
// 你可以调节下方这两个数,控制整体粒子大小的分布范围
|
||||||
|
sizes[i] = 0.8 + Math.random() * 2.2; // 0.8 ~ 3.0 之间
|
||||||
}
|
}
|
||||||
|
|
||||||
geometry.setAttribute(
|
geometry.setAttribute(
|
||||||
"position",
|
"position",
|
||||||
new THREE.BufferAttribute(positions, 3)
|
new THREE.BufferAttribute(positions, 3)
|
||||||
);
|
);
|
||||||
|
geometry.setAttribute(
|
||||||
|
"size",
|
||||||
|
new THREE.BufferAttribute(sizes, 1)
|
||||||
|
);
|
||||||
|
|
||||||
var material = new THREE.PointsMaterial({
|
// 使用自定义着色器,让粒子可以拥有不同大小
|
||||||
color: 0x38bdf8, // 粒子主色(可自行调整)
|
var material = new THREE.ShaderMaterial({
|
||||||
size: 0.08, // 每个粒子在世界中的尺寸
|
uniforms: {
|
||||||
sizeAttenuation: true,
|
uColor: { value: new THREE.Color(0x38bdf8) }, // 粒子主色
|
||||||
|
uOpacity: { value: 0.95 },
|
||||||
|
uSize: { value: 18.0 }, // 全局尺寸基准,越大粒子越大
|
||||||
|
uPixelRatio: { value: Math.min(window.devicePixelRatio || 1, 2) },
|
||||||
|
},
|
||||||
|
vertexShader: `
|
||||||
|
attribute float size;
|
||||||
|
uniform float uSize;
|
||||||
|
uniform float uPixelRatio;
|
||||||
|
void main() {
|
||||||
|
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
|
||||||
|
gl_Position = projectionMatrix * mvPosition;
|
||||||
|
// 简单的距离衰减,让远处粒子稍微小一些
|
||||||
|
float dist = length(mvPosition.xyz);
|
||||||
|
float att = 1.0 / (0.1 + dist * 0.35);
|
||||||
|
gl_PointSize = size * uSize * uPixelRatio * att;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
fragmentShader: `
|
||||||
|
uniform vec3 uColor;
|
||||||
|
uniform float uOpacity;
|
||||||
|
void main() {
|
||||||
|
// 将点渲染成柔和的圆形(不使用默认的方形 point sprite)
|
||||||
|
vec2 c = gl_PointCoord - vec2(0.5);
|
||||||
|
float d = length(c);
|
||||||
|
if (d > 0.5) discard;
|
||||||
|
float alpha = (1.0 - d * 2.0) * uOpacity;
|
||||||
|
if (alpha <= 0.0) discard;
|
||||||
|
gl_FragColor = vec4(uColor, alpha);
|
||||||
|
}
|
||||||
|
`,
|
||||||
transparent: true,
|
transparent: true,
|
||||||
opacity: 0.95,
|
|
||||||
depthWrite: false,
|
depthWrite: false,
|
||||||
blending: THREE.AdditiveBlending,
|
blending: THREE.AdditiveBlending,
|
||||||
});
|
});
|
||||||
@@ -133,7 +171,7 @@
|
|||||||
var innerSphereMat = new THREE.MeshBasicMaterial({
|
var innerSphereMat = new THREE.MeshBasicMaterial({
|
||||||
color: 0x0f172a,
|
color: 0x0f172a,
|
||||||
transparent: true,
|
transparent: true,
|
||||||
opacity: 0.25,
|
opacity: 0.0, // 表面颜色完全透明,只保留粒子视觉
|
||||||
side: THREE.BackSide,
|
side: THREE.BackSide,
|
||||||
});
|
});
|
||||||
var innerSphereMesh = new THREE.Mesh(innerSphereGeom, innerSphereMat);
|
var innerSphereMesh = new THREE.Mesh(innerSphereGeom, innerSphereMat);
|
||||||
@@ -161,6 +199,10 @@
|
|||||||
camera.aspect = w / h;
|
camera.aspect = w / h;
|
||||||
camera.updateProjectionMatrix();
|
camera.updateProjectionMatrix();
|
||||||
renderer.setSize(w, h);
|
renderer.setSize(w, h);
|
||||||
|
// 同步像素比,避免在缩放/视网膜屏下粒子尺寸异常
|
||||||
|
if (material && material.uniforms && material.uniforms.uPixelRatio) {
|
||||||
|
material.uniforms.uPixelRatio.value = Math.min(window.devicePixelRatio || 1, 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
window.addEventListener("resize", onResize);
|
window.addEventListener("resize", onResize);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user