可视化效果之半环、白模、辉光

523 阅读3分钟

这篇博客,博主展示一下常见效果半环、白模、辉光。

半环是常用的可视化手段,可以用在缓冲区、警戒区设定上,这种动效要比静态的圆显得更直观,更具感染力。

白模,是对建筑群的直观展示,能有效的降低建模的成本,只需要建筑多边形坐标和建筑高度即可在程序中生成白膜,这里,博主使用geojson生成白模。

辉光,光,在场景中是必不可少的重要一环,加入辉光后处理,能是场景更具科技感,这里博主使用threejs中提供的辉光解决方案,讨论一下使用时需要注意的点。

半环实现方式:

半环效果看起来比较唬人,实际上半环本质上可以看作是一个没有上下底面的圆柱体,给圆柱体配上由渐变贴图做成的材质,渲染时,控制圆柱按计算好的距离缩放即可。

  const texture = new THREE.TextureLoader().load(colorPng);
  texture.wrapS = THREE.RepeatWrapping;
  texture.wrapT = THREE.RepeatWrapping;
  texture.repeat.set(1, 1);
  const geometry = new THREE.CylinderBufferGeometry(radius, radius, 1, 64);
  const materials = [
    new THREE.MeshBasicMaterial({
      map: texture,
      side: THREE.DoubleSide,
      transparent: true,
    }),
    new THREE.MeshBasicMaterial({
      transparent: true,
      opacity: 0,
      side: THREE.DoubleSide,
    }),
    new THREE.MeshBasicMaterial({
      transparent: true,
      opacity: 0,
      side: THREE.DoubleSide,
    }),
  ];

  cylinderMesh = new THREE.Mesh(geometry, materials);
  cylinderMesh.position.set(position.x, position.y, position.z);

效果:

banhuan.jpg

白模实现方式:

白模源数据依然是geojson,可以在数据处理阶段将geojson数据转成obj数据,最好转成gltf,因为白模数据可能是比较细碎的,数量非常多,前端直接读json生成可能会造成比较大的损失。博主搭建的个人项目区域不大,因此采用前端生成白模的方式。

生成方法:

读取并解析geojson,按照之前介绍过的方法,进行坐标转换。

将转换过的坐标使用threejs中的shape,将底面画出来。

 

使用绘制好的shape生成ExtrudeGeometry,让二维的shape挤成三维的体。

生成材质,ExtrudeGeometry可以使用一个材质数组,第一个材质可以用在他的表面,第二个材质用在他挤出来的面。这是非常舒服的,这使得展示效果可操作性变得更高,这里我传入两个材质,使ExtrudeGeometry顶部底部都是透明的,侧面使用canvas绘制一张渐变图,作为材质贴图。

使用ExtrudeGeometry和材质数组生成Mesh。

效果:

baimo.jpg

辉光:

辉光效果,threejs官方文档中已经有了详细介绍,这里不再赘述。在这里,讲一讲我采用的辉光分层的方法。

官方文档中的分层方法,是写两个过滤函数,在渲染时一直过滤object,不需要辉光的object设置一个预先生成的暗材质,这样实现了辉光分层,但是感觉好像不辉光的object看起来有些模糊?应该是暗材质的问题吧。而且需要一直手动过滤,性能不知道会不会有影响,毕竟官网给出的demo是单页面。

Threejs中有layers的概念,可以为Object3D分配32个图层,图层可以控制对象的显示,默认所有Object3D都存储在第0层中。

图层控制对象显隐,对象要与camera共享图层。Camera渲染时,camera共享的图层也会渲染,这样,辉光分层完全可以转换为layers分层,渲染时根据camera的图层,分别渲染。

if (composer) {
    renderer.autoClear = false;
    renderer.clear();
    camera.layers.set(bloomLayerNum);
    composer?.render();
  }
  renderer.clearDepth();
  camera.layers.set(0);
  renderer.render(scene, camera);

bloomLayerNum表示辉光图层。实际上官网demo也做了这样的分层,但是还是做了过滤函数。

具体代码可以查看我之前分享的github仓库。