从零开始搭建开源智慧城市项目(四)扩散扫光和颜色渐变

2,087 阅读1分钟

前言

上一节实现了上升线效果,这一节继续修改上一节中的shader,添加颜色渐变效果和扩散扫光效果。

思路

颜色渐变:让扩散扫光的效果中间亮,两边暗,来模拟光的效果,可通过sin函数模拟效果,把扫光半径计算到0-PI之间。他们的值变化如下图,0PI最暗,PI/2最亮。

image.png

扩散扫光:这个思路也比较简单,设置一个原点,然后第一帧模型距离这个原点0-10单位长度的所有的点进行发光,第二帧距离10-20单位长度的点进行发光,以此类推。

代码讲解

   fragmentShader: `
   //求距离的公式,平方和开根号
float distanceTo(vec2 src,vec2 dst)
{
    float dx=src.x-dst.x;
    float dy=src.y-dst.y;
    float dv=dx*dx+dy*dy;
    return sqrt(dv);
}
varying vec3 vPosition;
uniform float height;
uniform vec3 uFlowColor;
uniform vec3 uCityColor;
void main()
{
    //模型的基础颜色
    vec3 distColor=uCityColor;
    //定位当前点位位置
    vec2 position2D=vec2(vPosition.x,vPosition.y);
    //求点到原点的距离
    float Len=distanceTo(position2D,vec2(0,0));
      if(Len>height*30.0&&Len<(height*30.0+130.0)){
        // 颜色渐变
        float dIndex = sin((Len - height*30.0) / 130.0 * 3.14);
        //通过上面的渐变值进行颜色混合
        distColor= mix(uFlowColor, distColor, 1.0-dIndex);
    }
    //最终颜色
    gl_FragColor=vec4(distColor,1.0);
}`,

传入的值和上一节相比没有变化,主函数部分关于上升线效果的也不进行介绍了,想要了解可以看上一篇文章(juejin.cn/post/704371…) 下面说一下添加的部分。

  • 函数新添加了一个计算两点(平面点)距离的函数distanceTo,通过勾股定理计算两个点的距离。
  • vec2 position2D=vec2(vPosition.x,vPosition.y);是把从顶点着色器中的点的x,y坐标进行组合,重新生成了一个平面坐标。
  • float Len=distanceTo(position2D,vec2(0,0))是计算模型点平面坐标到原点的距离,然后把距离在height*30.0height*30.0+130.0之间的点进行混色。其中height*30是原点距发光环内半径的距离,height*30+130是原点距发光环外半径的距离,130.0是发光环的内径。
  • float dIndex = sin((Len - height*30.0) / 130.0 * 3.14)是通过sin函数把距离在height*30.0height*30.0+130.0之间的值进行计算,值从height*30.0height*30.0+65.0height*30.0+130.0分别是0.0——1.0——0.0,实现两边值小中间值大的效果。
  • distColor= mix(uFlowColor, distColor, 1.0-dIndex)是通过mix函数进行颜色混色,把uFlowColordistColor两个颜色通过1.0: 1.0-dIndex进行混色.实现最终效果。

完整代码

 setCityMaterial(object) {
      const shader = new THREE.ShaderMaterial({
        uniforms: {
          height: this.height,
          uFlowColor: {
            value: new THREE.Color("#5588aa"),
          },
          uCityColor: {
            value: new THREE.Color("#1B3045"),
          },
        },
        vertexShader: `
                varying vec3 vPosition;
                void main()
                {
                  vPosition = position;
                  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
                }`,
        fragmentShader: `
float distanceTo(vec2 src,vec2 dst)
{
    float dx=src.x-dst.x;
    float dy=src.y-dst.y;
    float dv=dx*dx+dy*dy;
    return sqrt(dv);
}
varying vec3 vPosition;
uniform float height;
uniform float uStartTime;
uniform vec3 uSize;
uniform vec3 uFlowColor;
uniform vec3 uCityColor;
void main()
{
    //模型的基础颜色
    vec3 distColor=uCityColor;
    // 流动范围当前点z的高度加上流动线的高度
    float topY=vPosition.z+10.;
    if(height>vPosition.z&&height<topY){
        // 颜色渐变
            float dIndex = sin((height - vPosition.z) / 10.0 * 3.14);
            distColor = mix(uFlowColor, distColor, 1.0-dIndex);

    }
    //定位当前点位位置
    vec2 position2D=vec2(vPosition.x,vPosition.y);
    //求点到原点的距离
    float Len=distanceTo(position2D,vec2(0,0));
      if(Len>height*30.0&&Len<(height*30.0+130.0)){
        // 颜色渐变
        float dIndex = sin((Len - height*30.0) / 130.0 * 3.14);
        distColor= mix(uFlowColor, distColor, 1.0-dIndex);
    }
    gl_FragColor=vec4(distColor,1.0);
}`,
                    transparent: true,
      });

      const city = new THREE.Mesh(object.geometry, shader);
      city.position.set(
        object.position.x,
        object.position.y,
        object.position.z
      );
      scene.add(city);
      city.rotateX(-Math.PI / 2);
    },

效果图

SDGIF_Rusult_1.gif 项目地址: github.com/lixiaochjaj…