从零开始搭建开源智慧城市项目(三)上升线效果

2,951 阅读3分钟

前言

上一节实现了添加建筑物线框,模型外墙和道路地面材质添加。这一节准备通过简单的shader实现上升线效果。

思路

简单的说一下思路,通过获取模型顶点坐标所在的高度Z来进行筛选,高度再某一区间内设置成上升线的颜色,其余高度颜色正常,把高度不断上升来让这根上升线不断上升,到一定高度后重置。

ShaderMaterial的组成

实现主要通关Three内自定义材质(ShaderMaterial)来实现,首先来实现一个最简单的ShaderMaterial来看一下这个材质的组成。

  const shader = new THREE.ShaderMaterial({
      //从程序穿到着色器里面的值,这里先不传值
        uniforms: {
        },
        //顶点着色器
         vertexShader: `
                void main()
                {
                  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
                }`,
         //片段着色器
         fragmentShader: `
                  void main()
                  {
                    gl_FragColor = vec4(1.0);
                  }`,
      });
  1. 顶点着色器(vertexShader ):首先来介绍一下顶点着色器,顶点着色器是用来处理顶点数据的,本例子中的顶点着色器主要代码就一句:
 gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

先来说一下每个变量的意思

  • position:模型点位数据。

  • modelViewMatrix:视图矩阵,等于camera.matrixWorldInverse * object.matrixWorld,就是模型矩阵和相机矩阵(视图矩阵)的乘积。

  • projectionMatrix:投影矩阵,等于camera.projectionMatrix。

  • gl_Position:矩阵变换后模型点位投影到屏幕上的位置,该值与position的关系如下图。 image.png

经过上述的矩阵变化,模型就会投影到裁剪坐标系然后经过一系列计算,显示到屏幕上。

  1. 片段着色器 (fragmentShader ):片段着色器是片元的颜色,本例子中的顶点着色器如下:
 gl_FragColor = vec4(1.01.01.01.0);

gl_FragColor是每个片段的颜色,这里统一设置成白色 vec4(1.0,1.0,1.0,1.0)。 然后把这个材质赋给模型

//object.geometry是模型的geometry属性,shader是上面定义的材质
  const city = new THREE.Mesh(object.geometry, shader);
//把重新生成的模型对象添加到场景里面
  scene.add(city);

这里的显示效果:

image.png

所有的建筑模型显示白色。

上升线效果实现

  1. 这个效果的实现需要四个值:线上升到的高度height、上升线的颜色uFlowColor、建筑模型的颜色uCityColor、模型点位的高度值z(这个顶点着色器里面有,需要从顶点着色器传到片段着色器中),然后把这些值通过uniforms传入到着色器里面去。着色器代码如下:
   const shader = new THREE.ShaderMaterial({
        uniforms: {
          height: this.height,
         uFlowColor: {
            value: new THREE.Color("#5588aa"),
          },
          uCityColor: {
            value: new THREE.Color("#FFFFDC"),
          },
        },
        vertexShader: `
                varying vec3 vPosition;
                void main()
                {
                  vPosition = position;
                  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
                }`,
        fragmentShader: `
                  varying vec3 vPosition;
                    uniform float height;
                     uniform float uStartTime; 
                    uniform vec3 uSize;
                    uniform vec3 uFlow;
                    uniform vec3 uFlowColor;
                    uniform vec3 uCityColor;
                  void main()
                  {
                    //模型的基础颜色
                   vec3 distColor=uCityColor;
                 // 流动范围当前点z的高度加上流动线的高度
                   float topY = vPosition.z +5.0;
                if (height > vPosition.z && height < topY) {
                   // 颜色渐变 
                    distColor = uFlowColor; 
                  }
                   gl_FragColor = vec4(distColor, 0.6);
                  }`,
                    transparent: true,
      });

render添加如下代码

      this.height.value += 0.03;
      if(this.height.value>100)
      {
        this.height.value=0.0
      }

首先说一下render中的代码,render是在每一次渲染中都会执行,在每一帧渲染时把height值逐渐增加,当height大于100的时候重置。

接下来是shader材质的定义,这里我们在uniforms中把需要的上升线的高度height,上升线的颜色uFlowColor,建筑模型的颜色uCityColor进行了传入,然后在vertexShader中把fragmentShader需要的点位属vPosition性通过varying变量实现了两个着色器直接的共用,这样上升效果需要的变量就都齐全了。

在片段着色器中首先定义模型的基本颜色distColor,然后定义流动颜色的位置float topY = vPosition.z +5.0;vPosition.z 是当前点位的z值加上一个宽度就是模型需要着色的部位。下一步进行筛选,筛选点位高度在 vPosition.z-height vPosition.z+0.5-height之间的值进行着色。把这一块的颜色设置成上升片段的颜色(uFlowColor).显示效果如下图:

SDGIF_Rusult_1.gif

项目地址: github.com/lixiaochjaj…