之前写了个3D地球,添加大量柱体和性能优化,这次给3D地球实现更加炫酷的特效。
1.搞个地球
{
const geometry = new THREE.SphereGeometry(16, 32, 32);
const texture = new THREE.TextureLoader().load('assets/world.jpg');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
const texture1 = new THREE.TextureLoader().load('assets/earth.jpg');
texture1.wrapS = THREE.RepeatWrapping;
texture1.wrapT = THREE.RepeatWrapping;
const material = new THREE.MeshStandardMaterial({
map: texture,
bumpMap: texture,
bumpScale: 1
});
const sphere = new THREE.Mesh(geometry, material);
this.scene.add(sphere);
}
添加bumpMap
黑白凹凸贴图,让地球表面多点真实感。
bumpMap
:用于创建凹凸贴图的纹理。黑色和白色值映射到相对于灯光的感知深度。凹凸实际上不会影响对象的几何体,只会影响照明。如果定义了法线贴图,则会忽略此项。
2.渐变地球扫光
给地球添加一个透明外壳,半径比地球大一点。
const geometry = new THREE.SphereGeometry(18, 32, 16);
const material = new THREE.MeshBasicMaterial({
color: 0xffffff,
transparent: true,
opacity: 0.2
});
const sphere = new THREE.Mesh(geometry, material);
this.scene.add(sphere);
扫光特效
顶点着色器,要将顶点着色器里面的uv传递给片元着色器
varying vec2 vUv;
void main(){
vUv=uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
片元着色器
float PI = acos(-1.0);
uniform float iTime;
uniform vec3 uColor;
varying vec2 vUv;
void main(){
vec2 uv = vUv+ vec2(0.0, iTime);//扫光向下移动
float current = abs(sin(uv.y * PI));//透明度中间往两边减少
gl_FragColor.rgb=uColor;//扫光颜色
gl_FragColor.a = mix(1.0, 0.0, current);//透明度渐变
}
扫光材质
const material = new THREE.ShaderMaterial({
uniforms: {
iTime: { value: 0.0 },//随时间变化
uColor: { value: new THREE.Color('#FFFFFF') }//扫光颜色
},
transparent: true,//开启透明
vertexShader: ``,
fragmentShader: ``
});
扫光动起来
animateAction() {
if (this.material) {
if (this.material.uniforms.iTime.value > 1) this.material.uniforms.iTime.value = 0;
else this.material.uniforms.iTime.value += 0.005;//扫光速度
}
}
噔噔噔!渐变扫光效果完成。可通过uColor
配置扫光的颜色
3.地球斑点扫光
与上面的渐变扫光相似,只是片元着色器有些不同。
对于画圆点可以参考我之前的文章用three.js搞3个炫酷粒子出场
float PI = acos(-1.0);
uniform vec3 uColor;//点的颜色
uniform vec2 pointNum;//点的数量
uniform float iTime;//随时间变化
varying vec2 vUv;//从顶点着色器传过来的uv
void main() {
vec2 uv = vUv + vec2(0.0, iTime);//随着时间向下移动
float current = abs(sin(uv.y * PI));//中间往两边减少
//中间的那行点强调,其他点大小的逐渐变小
if(current < 0.996) {
current = current * 0.5;
}
//画多个圆点
float d = distance(fract(uv * pointNum * 2.0), vec2(0.5, 0.5));
if(d > current * 0.2) {//与中心点距离外的无颜色
discard;
} else {
gl_FragColor = vec4(uColor, current);
}
distance(point1,point2)
计算两个点的距离,当point2为vec2(0.5, 0.5)
时即计算点到中心的距离,可以通过距离半径if(d > radius)discard;
来排除外面的圆点外面的颜色,然后就画出圆了。uv
的x和y范围是都是[0,1]
,通过将其乘以数量,然后fract
规整取,fract(uv * pointNum)
可以让横向和纵向的数量翻倍。
注意:
pointNum
赋值最好是2:1的比例相对应,球体的贴图展开成矩形刚好是360:180=》2:1
,这样才能保持画出的点是圆形的,否则有可能出现椭圆形。
uniforms: {
pointNum: { value: new THREE.Vector2(32, 16) },
}
- 另外,点的数量足够多才可以做到包围球体并扫描,所以我
fract(uv * pointNum * 2.0)
这里特意将数量乘以两倍。
GitHub地址
https://github.com/xiaolidan00/my-earth