这个是突发奇想的一个成品,目的是保持自己对threejs的熟练程度,现在公司不使用threejs进行开发了。

上述效果总共分为3大块,分别是 地球
,飞线
,目标点
创建地球
首先我们在创建地球时准备好地球的贴图

然后我们创建一个几何球体

ts
const geometry = new THREE.SphereGeometry(6, 100, 100);
const material = new THREE.MeshBasicMaterial({color:"#ffffff"})
const mesh = new THREE.Mesh(geometry, material);
如何将球体和贴图绑定在一起呢?
我们使用的是SphereGeometry
着色器纹理将图像与几何体进行渲染
我们首先确定着色器需要的变量
我们这里只需要传入贴图即可,代码如下
ts
const material = new THREE.ShaderMaterial({
uniforms: {
u_texture: {
value: new THREE.TextureLoader().load(
"/img/8k_earth_daymap.jpg" // 图片路径
),
},
},
fragmentShader: fs,
vertexShader: vs,
});
片元着色器
首选我们通过sampler2D获取到传入的贴图,然后获取贴图的颜色,并进行归一化获取RGB颜色的点积。并对x进行判断,不同的区间使用不同的色值。
c
// 纹理
uniform sampler2D u_texture;
varying vec2 v_uv;
float snoise(vec3 v);
void main() {
vec3 color = texture2D(u_texture,v_uv).xyz;
color = normalize(color);
if(color.x<=0.5) {
color = vec3(0.6f, 0.22f, 0.71f);
} else {
color = vec3(0.93f, 0.72f, 0.98f);
};
gl_FragColor = vec4(color, 1.0);
}
顶点着色器
顶点着色器获取每个色值的rgb,并将将其叠加在当前坐标的法向*0.2倍率,实现凹凸效果
c
uniform sampler2D u_texture;
varying vec3 v_position;
varying vec3 v_normal;
varying vec2 v_uv;
void main() {
v_position = position;
v_normal = normal;
v_uv = uv;
vec3 color = texture2D(u_texture, uv).xyz;
vec3 new_position = position + (normal * color) * 0.2;
vec4 modelViewPosition = modelViewMatrix * vec4(new_position, 1.0);
vec4 projectPosition = projectionMatrix * modelViewPosition;
gl_Position = projectPosition;
}

到此地球就创建完毕了
创建飞线
在threejs中线条是无法实现分段效果的,也许是我还没接触到可以分段的方法,我们这里使用管道几何体TubeGeometry
,并将几何体分为20段,并利用向量实现飞线抬升的效果,利用样条曲线实现弧度,来实现飞线效果。
c
getCurve(p1: THREE.Vector3, p2: THREE.Vector3) {
const v1 = new THREE.Vector3(p1.x, p1.y, p1.z);
const v2 = new THREE.Vector3(p2.x, p2.y, p2.z);
const points: THREE.Vector3[] = [];
Array.from({length: 20}).forEach((_,i)=>{
const p = new THREE.Vector3().lerpVectors(v1, v2, i / 20);
p.multiplyScalar(1 + Math.abs(0.3 * Math.sin((Math.PI * i) / 20)));
points.push(p);
})
const path = new THREE.CatmullRomCurve3(points);
const geometry = new THREE.TubeGeometry(path, 20, 0.02, 50, false);
const material = new THREE.ShaderMaterial({
uniforms: {
u_time: {
value: 0,
},
},
fragmentShader: pfs,
vertexShader: pvs,
side: THREE.DoubleSide,
});
return new THREE.Mesh(geometry, material);
}
片元着色器
利用sin函数和当前顶点的坐标+u_time实现飞线流动效果
c
uniform float u_time;
varying vec3 v_normal;
varying vec2 v_uv;
void main() {
float dash = sin((v_uv.x + u_time) * 50.);
if(dash < 0.3)
discard;
gl_FragColor = vec4(vec3(1.0, 1.0, 1.0), 1.0);
}

到此,地球和飞线都已经创建完毕了,并实现了飞线流动效果。