likes
comments
collection
share

用Three.js搞个炫酷雷达扩散和扫描特效雷达扩散和雷达扫描是3D建筑群常用特效,点进来就跟我学怎么用Three.js

作者站长头像
站长
· 阅读数 112

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);

用Three.js搞个炫酷雷达扩散和扫描特效雷达扩散和雷达扫描是3D建筑群常用特效,点进来就跟我学怎么用Three.js

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

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);`
            );
          };

用Three.js搞个炫酷雷达扩散和扫描特效雷达扩散和雷达扫描是3D建筑群常用特效,点进来就跟我学怎么用Three.js

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

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

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

用Three.js搞个炫酷雷达扩散和扫描特效雷达扩散和雷达扫描是3D建筑群常用特效,点进来就跟我学怎么用Three.js

至此,建筑和平面的俯视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;
              }
            });
          }
        }

用Three.js搞个炫酷雷达扩散和扫描特效雷达扩散和雷达扫描是3D建筑群常用特效,点进来就跟我学怎么用Three.js

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

雷达扫描特效

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

  • 雷达扫描是通过扇形渐变形成的,还要随着时间旋转角度
  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)); `;

用Three.js搞个炫酷雷达扩散和扫描特效雷达扩散和雷达扫描是3D建筑群常用特效,点进来就跟我学怎么用Three.js

GitHub地址

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

转载自:https://juejin.cn/post/7349837128508964873
评论
请登录