注册
web

用Three.js搞个炫酷雷达扩散和扫描特效

1.画点建筑模型


添加光照,开启阴影


//开启renderer阴影
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;

//设置环境光
const light = new THREE.AmbientLight(0xffffff, 0.6); // soft white light
this.scene.add(light);

//夜晚天空蓝色,假设成蓝色的平行光
const dirLight = new THREE.DirectionalLight(0x0000ff, 3);
dirLight.position.set(50, 50, 50);
this.scene.add(dirLight);

平行光设置阴影


//开启阴影
dirLight.castShadow = true;
//阴影相机范围
dirLight.shadow.camera.top = 100;
dirLight.shadow.camera.bottom = -100;
dirLight.shadow.camera.left = -100;
dirLight.shadow.camera.right = 100;
//阴影影相机远近
dirLight.shadow.camera.near = 1;
dirLight.shadow.camera.far = 200;
//阴影贴图大小
dirLight.shadow.mapSize.set(1024, 1024);


  • 平行光的阴影相机跟正交相机一样,因为平行光的光线是平行的,就跟视线是平行一样,切割出合适的阴影视角范围,用于计算阴影。
  • shadow.mapSize设置阴影贴图的宽度和高度,值越高,阴影的质量越好,但要花费计算时间更多。

增加建筑


//添加一个平面
const pg = new THREE.PlaneGeometry(100, 100);
//一定要用受光材质才有阴影效果
const pm = new THREE.MeshStandardMaterial({
color: new THREE.Color('gray'),
transparent: true,//开启透明
side: THREE.FrontSide//只有渲染前面
});
const plane = new THREE.Mesh(pg, pm);
plane.rotateX(-Math.PI * 0.5);
plane.receiveShadow = true;//平面接收阴影
this.scene.add(plane);

//随机生成建筑
this.geometries = [];
const helper = new THREE.Object3D();
for (let i = 0; i < 100; i++) {
const h = Math.round(Math.random() * 15) + 5;
const x = Math.round(Math.random() * 50);
const y = Math.round(Math.random() * 50);
helper.position.set((x % 2 ? -1 : 1) * x, h * 0.5, (y % 2 ? -1 : 1) * y);
const geometry = new THREE.BoxGeometry(5, h, 5);
helper.updateWorldMatrix(true, false);
geometry.applyMatrix4(helper.matrixWorld);
this.geometries.push(geometry);
}
//长方体合成一个形状
const mergedGeometry = BufferGeometryUtils.mergeGeometries(this.geometries, false);
//建筑贴图
const texture = new THREE.TextureLoader().load('assets/image.jpg');
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
const material = new THREE.MeshStandardMaterial({ map: texture,transparent: true });
const cube = new THREE.Mesh(mergedGeometry, material);
//形状产生阴影
cube.castShadow = true;
//形状接收阴影
cube.receiveShadow = true;
this.scene.add(cube);

image.png


效果就是很多高楼大厦的样子,为什么楼顶有窗?别在意这些细节,有的人就喜欢开天窗呢~


2.搞个雷达扩散和扫描特效


改变建筑材质shader,计算建筑的俯视uv


material.onBeforeCompile = (shader, render) => {
this.shaders.push(shader);
//范围大小
shader.uniforms.uSize = { value: 50 };
shader.uniforms.uTime = { value: 0 };
//修改顶点着色器
shader.vertexShader = shader.vertexShader.replace(
'void main() {',
` uniform float uSize;
varying vec2 vUv;
void main() {`

);
shader.vertexShader = shader.vertexShader.replace(
'#include <fog_vertex>',
`#include <fog_vertex>
//计算相对于原点的俯视uv
vUv=position.xz/uSize;`

);
//修改片元着色器
shader.fragmentShader = shader.fragmentShader.replace(
'void main() {',
`varying vec2 vUv;
uniform float uTime;
void main() {`

);
shader.fragmentShader = shader.fragmentShader.replace(
'#include <dithering_fragment>',
`#include <dithering_fragment>
//渐变颜色叠加
gl_FragColor.rgb=gl_FragColor.rgb+mix(vec3(0,0.5,0.5),vec3(1,1,0),vUv.y);`

);
};

image.png


然后你将同样的onBeforeCompile函数赋值给平面的时候,没有对应的效果。


因为平面没有z,只有xy,而且经过了-90度旋转后,坐标位置也要对应反转,由此可以得出平面的uv计算公式


vUv=vec2(position.x,-position.y)/uSize;

image.png


至此,建筑和平面的俯视uv一致了。


雷达扩散特效



  • 雷达扩散就是一段渐变的环,随着时间扩大。
  • 顶点着色器不变,改一下片元着色器,增加扩散环颜色uColor,对应shader.uniforms也要添加

shader.uniforms.uColor = { value: new THREE.Color('#00FFFF') };

const fragmentShader1 = `varying vec2 vUv;
uniform float uTime;
uniform vec3 uColor;
uniform float uSize;
void main() {`
;
const fragmentShader2 = `#include <dithering_fragment>
//计算与中心的距离
float d=length(vUv);
if(d >= uTime&&d<=uTime+ 0.1) {
//扩散圈
gl_FragColor.rgb = gl_FragColor.rgb+mix(uColor,gl_FragColor.rgb,1.0-(d-uTime)*10.0 )*0.5 ;
}`
;

shader.fragmentShader = shader.fragmentShader.replace('void main() {', fragmentShader1);
shader.fragmentShader = shader.fragmentShader.replace(
'#include <dithering_fragment>',
fragmentShader2);

//改变shader的时间变量,动起来
animateAction() {
if (this.shaders?.length) {
this.shaders.forEach((shader) => {
shader.uniforms.uTime.value += 0.005;
if (shader.uniforms.uTime.value >= 1) {
shader.uniforms.uTime.value = 0;
}
});
}
}

20240322_224153.gif


噔噔噔噔,完成啦!是立体化的雷达扩散,看起来很酷的样子。


雷达扫描特效


跟上面雷达扩散差不多,只要修改一下片元着色器



  • 雷达扫描是通过扇形渐变形成的,还要随着时间旋转角度

  const fragmentShader1 = `varying vec2 vUv;
uniform float uTime;
uniform vec3 uColor;
uniform float uSize;
//旋转角度矩阵
mat2 rotate2d(float angle)
{
return mat2(cos(angle), - sin(angle),
sin(angle), cos(angle));
}
//雷达扫描渐变扇形
float vertical_line(in vec2 uv)
{
if (uv.y > 0.0 && length(uv) < 1.2)
{
float theta = mod(180.0 * atan(uv.y, uv.x)/3.14, 360.0);
float gradient = clamp(1.0-theta/90.0,0.0,1.0);
return 0.5 * gradient;
}
return 0.0;
}
void main() {`
;


const fragmentShader2 = `#include <dithering_fragment>
mat2 rotation_matrix = rotate2d(- uTime*PI*2.0);
//将雷达扫描扇形渐变混合到颜色中
gl_FragColor.rgb= mix( gl_FragColor.rgb, uColor, vertical_line(rotation_matrix * vUv)); `
;

20240322_232006.gif


GitHub地址


https://github.com/xiaolidan00/my-earth


作者:敲敲敲敲暴你脑袋
来源:juejin.cn/post/7349837128508964873

0 个评论

要回复文章请先登录注册