从零开始搭建开源智慧城市项目(五)背景天空盒、扩散墙、扩散圆

·  阅读 4004

前言

上一节实现了颜色渐变效果和扩散扫光效果,这一节来添加背景天空盒、扩散墙、扩散圆。

添加天空盒思路

three添加天空盒有两种格式,一种是需要上下左右前后六张图来组成天空盒,一种是创建一个足够大的球,把这个球表面贴上一张图 场景在球里面组成天空球。

  1. 六张图:这种方式是通关threeTHREE.CubeTextureLoader().load方法,吧六张图地址数据添加到该对象里面去然后把场景的背景设置为这个对象。原理图如下所示image.pngimage.png
  2. 一张图:因为three没有加载hdr天空盒的方式,可以模仿加载六张图的方式,因为加载六张图相当于创建了一个正方体,每个面贴了一张图片材质,相机在正方体内形成天空盒。那么hdr单张图就可以通过创建一个球体,球体表面贴图,相机在球体里面来实现(这种方式是我同事提出来的脑洞😂)。 这里推荐一个网址可以下载HDR材质(这个材质既可以当天空盒来用,也可以当环境贴图来用)polyhaven.com/hdris

image.png

天空盒实现

我这里天空盒实现选的是第一种方式(因为数据是六张图的),代码如下

   const textureCube = new THREE.CubeTextureLoader().load(['1.jpg', '2.jpg', '3.jpg', '4.jpg', '5.jpg', '6.jpg'],);
   scene.background = textureCube; // 作为背景贴图
复制代码

数据如下

image.png

效果

SDGIF_Rusult_1.gif

扩散圆实现思路

通过THREE.RingGeometry创建一个圆,然后给这个圆添加想要实现效果的贴图,然后再render循环里面每一帧都改变这个圆的大小。

扩散圆实现

通过创建THREE.TextureLoader()来进行读取图片纹理数据其中this.img为图片地址,创建THREE.RingGeometry模型,把读出来的纹理赋给THREE.MeshBasicMaterial材质,然后再render循环里面改变这个模型的缩放比例来进行扩散效果模拟。 代码如下

/* eslint-disable */
import * as THREE from 'three';
/**
 * 波纹散射图层
 * @param  options.img 照片地址
 * @param  options.speed 流动速度
 * @param  options.scene three场景
 * @param  options.radius 圆的半径
 * @param  options.thing 圆的位置
 * @param  options.meshrings 存储圆形数据
 * @example
 */

class RunRing {
  constructor(option) {
    this.img = option.img || '';
    this.speed = option.speed / 100 || 0.01;
    this.scene = option.scene;
    this.radius = option.radius || 100;
    this.position = option.position || [0, 0, 0];
    this.meshrings = [];
    this.CreatRing();
  }
  CreatRing() {
    //创建对象读取照片纹理
    const textureLoader = new THREE.TextureLoader();
    textureLoader.load(this.img, (texture) => {
      //创建圆圈结构
      const geometry = new THREE.RingGeometry(0, this.radius, 500);
      //创建材质 把读取到的图片赋给材质
      const material2 = new THREE.MeshBasicMaterial({
        color: 0xffffff,
        side: THREE.DoubleSide,
        depthTest: true,
        blending: THREE.AdditiveBlending,
        map: texture,
      });
      //传入的多点的话生成多个模型
      for (let i = 0; i < this.position.length; i += 1) {
        //组合生成模型
        this.meshring = new THREE.Mesh(geometry, material2);
        //设置模型的X轴偏移量,让模型平铺再X面上
        this.meshring.rotateX(Math.PI / 2);
        //设置初始状态模型缩放比例
        this.meshring.scale.set(0.1, 0.1, 0.1);
        //设置模型位置
        this.meshring.position.set(this.position[i][0], this.position[i][1], this.position[i][2]);
        //储存模型对象,用于render改变属性和销毁对象
        this.meshrings.push(this.meshring)
        //添加到场景里面
        this.scene.add(this.meshrings[i]);

      }


    });
    //创建render,每一帧进行模型改变
    this.thing = setInterval(() => {
      //循环所有创建的模型,进行改变
      for (let i = 0; i < this.position.length; i += 1) {
        //如果模型已经创建
        if (this.meshrings[i]) {
          //当模型缩放比例小于1的时候,模型进行放大
          if (this.meshrings[i].scale.x < 1) {
            this.meshrings[i].scale.set(
              this.meshrings[i].scale.x + 0.01,
              this.meshrings[i].scale.x + 0.01,
              this.meshrings[i].scale.x + 0.01,
            );
          } else {
            //当模型比例大于1的时候,模型重置
            this.meshrings[i].scale.set(0.1, 0.1, 0.1);
          }
        }
      }

    }, 50);

  }
  delete() {
    //删除scene中对应的模型
    for (let i = 0; i < this.position.length; i += 1) {
      if (this.meshrings[i]) {
        this.scene.remove(this.meshrings[i]);
      }
    }
    if (this.thing) {
      //清除render事件
      clearInterval(this.thing);
    }
  }
}
export default RunRing;
复制代码

数据格式

 {
        img: "clice.png",
        scene: scene,
        speed: 1,
        radius: 400,
        position: [
          [400, 30, 400],
          [100, 30, 1200],
        ],
      }
复制代码

image.png 效果图

SDGIF_Rusult_1.gif

扩散墙实现思路

扩散墙和上一节一样 是通过ShaderMaterial来实现的,要实现的效果是墙面随着高度增加透明度也增加,所以模型点位的透明度和高度呈反比。模型的扩散效果是把模型点位的位置通过mod函数来进行取余运算(%),把计算结果限制再0-1之间。

扩散墙实现

/* eslint-disable */
import * as THREE from "three";
/**
 * 波动墙
 * @param  options.scene three场景
 * @param  options.radius 中心
 * @param  options.height 墙高度
 * @param  options.opacity 墙透明度
 * @param  options.color 墙颜色
 * @example
 */

class Wall {
  constructor(option) {
    this.scene = option.scene;
    this.radius = option.radius || 420;
    this.height = option.height || 120;
    this.opacity = option.opacity || 0.5;
    this.color = option.color || "#efad35";
    this.speed = option.speed || 0.5;
    this.mesh = ""; //生成的模型数据
    this.CreatRing();
  }
  CreatRing() {
    const vertexShader = `
uniform vec3 u_color;

uniform float time;
uniform float u_height;
 
varying float v_opacity;

void main() {
//模型点位置乘以一个0.0-1.0的系数,来模拟扩散效果。
    vec3 vPosition = position * mod(time/20.0, 1.0);
//模型的透明度和模型的高度呈反比
    v_opacity =1.0- position.y / u_height;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(vPosition, 1.0);
}
`;
    const fragmentShader = ` 
uniform vec3 u_color;
uniform float u_opacity;
 
varying float v_opacity;

void main() { 
    //u_color是颜色 v_opacity * u_opacity是高度所产生的透明效果和模型传入的透明度的乘积。
    gl_FragColor = vec4(u_color, v_opacity * u_opacity);
}
`;
//获取参数
    const { radius, height, opacity, color, speed, renderOrder } = this;
//生成模型结构
    const geometry = new THREE.CylinderGeometry(
      radius,
      radius,
      height,
      32,
      1,
      true
    );
    //模型位置设置
    geometry.translate(0, height / 2, 0);
    //自定义模型材质
    const material = new THREE.ShaderMaterial({
      uniforms: {
        u_height: {
          value: height,
        },
        u_opacity: {
          value: opacity,
        },
        u_color: {
          value: new THREE.Color(color),
        },
        time: {
          value: 0,
        },
      },
      transparent: true,
      depthWrite: false,
      depthTest: false,
      side: THREE.DoubleSide,
      vertexShader: vertexShader,
      fragmentShader: fragmentShader,
    });
    //组合材质和结构生成对象
    const mesh = new THREE.Mesh(geometry, material);
    //设置模型遮挡,把这个模型放到最前面防止遮挡
    mesh.renderOrder = renderOrder || 1;
    this.mesh = mesh;
  }
}

export default Wall;

复制代码

效果图

SDGIF_Rusult_1.gif

项目地址: github.com/lixiaochjaj…

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改