赞
踩
1.3D地图的第三步,增加描边的线条和辉光
1.还记得当初我们引入的map.json文件去生成的地图吗?如果忘了,可以去复习第二章,现在我们要做的是创建一个arr,把map.json的数据以省份的格式放进来,如果直接使用地图的数据,线条的起始点和另一个起始点会交叉在一起,非常混乱
//在 generateGeometry方法下新建 linArr数组
let linArr=[]
2.每次循环清零linArr,并push进当前省份的数据,把当前linArr的省份数据 发给getLin(),去创建线条,
要调整成一下z轴的高度,是地图z轴高度的下面一点点
linArr.push(5.7)
注意代码里我关于linArr数组的操作
multiPolygon.forEach((polygon) => { // linArr.length=0 //构建几何图形 //清零 linArr.length=0 const shape = new THREE.Shape() for (let i = 0; i < polygon.length; i++) { const [x, y] = projection(polygon[i]) //如果有NvN的数据就让他跳过,要不然three.js会报错 if(!x){ continue; } //指定我们的起点 if (i === 0) { shape.moveTo(x, -y) } // this. pointArr.push(x) // this. pointArr.push(-y) // this. pointArr.push(2) linArr.push(x) linArr.push(-y) linArr.push(5.7) //后续就开始从起点画线 //如果你使用过canvans画线,那你肯定秒懂,他们是一个道理 shape.lineTo(x, -y) // lineGeometry.vertices.push(new THREE.Vector3(x, -y, 4)) } //注意这里 this.getLin(linArr) //构建地图的 正面贴图 ,这里使用基础材质,关于材质,大家可以去详细看看api material = new THREE.MeshBasicMaterial ({ // color:'#144685', transparent: true, opacity:1, map:texture, }) //构建地图的 侧面贴图 ,这里使用基础材质 const material_1 = new THREE.MeshBasicMaterial ({ color: '#558BAB', transparent: true, opacity: 0.45, }) const extrudeSettings = { depth: 2, bevelEnabled: false, } //这里我们把先前构造的几何图形 通过ExtrudeGeometry 拉伸成几何体 const geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings ) const extrudeSettings_2={ depth: 1, bevelEnabled: false, } const geometry_2 = new THREE.ExtrudeGeometry( shape, extrudeSettings_2 ) const material_2 = new THREE.MeshBasicMaterial ({ color: '#ffffff', transparent: true, opacity: 0, }) //把几何体和 我们两个贴图 合成一个 网格对象 mesh const mesh = new THREE.Mesh(geometry, [material, material_1]) const mesh_2 = new THREE.Mesh(geometry_2, [material_1,material_2]) const mesh_3= mesh_2.clone() mesh.castShadow=true //把网格对象加入省份的3d对象 mesh.position.z=4 mesh_2.position.z=1 mesh_3.position.z=-2 province.add(mesh) province.add(mesh_2) province.add(mesh_3) })
3.在生成线条之前,我们需要引入three.meshline来控制线条的宽度
npm i three.meshline
//引入
import { MeshLine, MeshLineMaterial, MeshLineRaycast } from 'three.meshline';
webgl不支持线条的线条的宽度属性,用这个就可以很好实现,还不受版本的限制。 接下来我们看看如何生成线条,我会用大量注释帮助你理解。
getLin(arr){ //Group对象,你可以把他看做一个数组,用这个主要是为了更方便的去控制每一个省份的线条 let groups=new THREE.Group() if(arr.length!=0){ // 初始化MeshLine const line = new MeshLine() // 传入顶点坐标数据 line.setPoints(arr) // 生成线材质 let material = new MeshLineMaterial({ useMap: 0, color: '#0fb9ee', opacity: 1, resolution: new THREE.Vector2(window.innerWidth, window.innerHeight), sizeAttenuation: 2, lineWidth: 0.6, transparent: true, wireframe: false, }) //构建线条的网格对象 const mesh = new THREE.Mesh(line.geometry,material) //把他放进去分层1 类似于z-index,方便后面实现辉光 mesh.layers.enable(1) //加入数组 groups.add(mesh) //把group加入地图对象 map.add(groups) } },
效果展示:
1.对于新手来讲,接下来的内容会比较晦涩难懂,我建议你可以结合起来看看three.js的官网案例代码去帮助你理解
three.js案例
2.准备工作,引入包,并开启双层渲染
这些包都是three.js自带的,不要额外引入,去包里找就好了。
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass';
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass';
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass';
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer';
import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader';
//混合器 let composer const ENTIRE_SCENE = 0,// 全部的,整个的场景 BLOOM_SCENE = 1; // 光晕场景 const bloomLayer = new THREE.Layers();// 光晕层次-创建一个图层对象 bloomLayer.set(BLOOM_SCENE);// 先把光晕层次设置光晕场景的层次1 const darkMaterial = new THREE.MeshBasicMaterial({ color: "black" });// 跟辉光光晕有关的变量 const materials = {};// 跟辉光光晕有关的变量 const params = { exposure: 0,// 暴露 bloomStrength: 0.78,// 光晕强度 bloomThreshold: 0,// 光晕阈值 bloomRadius: 0.1,// 光晕半径 }; let bloomPass let finalComposer let bloomComposer
主要思路: 请一定要先想明白这里,再继续下去,辉光渲染的主要思路在于 分层渲染,其中的分层 它相当于重新创建了一个渲染的通道,你也可以简单的理解为z-index分层,他们不在一个层次,我们渲染先渲染需要发光的部分 也就是 layers.enable(1)的部分,在渲染另一个 layers.enable(0)的部分,最后再让他们合并。
3.开始构建
顶点和片段着色器
需要用GLSL语言来编写,目前我还不会,这是从官网demo找的代码片段,主要作用就是用于制造光晕
//顶点着色器 <script type="x-shader/x-vertex" id="vertexshader"> varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); } </script> //片段着色器 <script type="x-shader/x-fragment" id="fragmentshader"> uniform sampler2D baseTexture; uniform sampler2D bloomTexture; varying vec2 vUv; void main() { gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) ); } </script>
feng(){ // 通过ShaderPass构造函数把FXAAShader着色器和uniforms构成的对象作为参数,创建一个锯齿通道FXAAShaderPass,然后把锯齿通道插入到composer中。 const effectFXAA = new ShaderPass(FXAAShader); effectFXAA.uniforms["resolution"].value.set( 0.6 / window.innerWidth, 0.6 / window.innerHeight ); // 渲染区域Canvas画布宽高度 effectFXAA.renderToScreen = true; // 去掉锯齿---1 const renderScene = new RenderPass(scene, camera);// RenderPass这个通道会在当前场景(scene)和摄像机(camera)的基础上渲染出一个新场景,新建: // 添加光晕效果---2 bloomPass = new UnrealBloomPass( // UnrealBloomPass通道可实现一个泛光效果。 new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85 ); bloomPass.threshold = params.bloomThreshold; bloomPass.strength = params.bloomStrength; bloomPass.radius = params.bloomRadius; // 添加光晕效果---2 // 着色器通道容器--放进容器里 bloomComposer = new EffectComposer(renderer); // EffectComposer可以理解为着色器通道容器,着色器通道按照先后顺序添加进来并执行 bloomComposer.renderToScreen = false; bloomComposer.addPass(renderScene); bloomComposer.addPass(bloomPass); // 添加光晕效果 bloomComposer.addPass(effectFXAA);// 去掉锯齿 // 着色器通道容器--放进容器里 const finalPass = new ShaderPass( new THREE.ShaderMaterial({ uniforms: { baseTexture: { value: null }, bloomTexture: { value: bloomComposer.renderTarget2.texture }, }, vertexShader: document.getElementById("vertexshader").textContent, fragmentShader: document.getElementById("fragmentshader") .textContent, defines: {}, }), "baseTexture" ); finalPass.needsSwap = true; finalComposer = new EffectComposer(renderer); finalComposer.addPass(renderScene); finalComposer.addPass(finalPass); finalComposer.addPass(effectFXAA); },
关键的四个类
ShaderPass:用于添加自定义的GLSL着色器(FXAAShader主要用于制造模糊效果 )
RenderPass:一个新的通道,他会渲染出一个新的场景
UnrealBloomPass:后期处理通道,用于模拟真实世界中的光晕效果,即模拟光线在明亮区域产生的模糊和光晕效果,他有四个参数,主要用来调节光晕
radius:表示光晕散发的半径。
strength:表示光晕的强度,值越大,光晕效果越明显。
threshold:表示产生光晕的光照强度阈值,只有光照强度大于该值的部分才会产生光晕效果。
blurKernel:表示用于模糊的卷积核,可以根据需要自定义。
EffectComposer:用于实现后期处理效果的一个对象,他可以把先前生成的渲染通道合并起来渲染,每个通道都是一种后期处理的效果,包括颗粒 模糊等
然后去吧 渲染器的 alpha打开,渲染器输出的图像将具有透明度,黑色将完全透明。
renderer = new THREE.WebGLRenderer({
alpha: true,
})
重写 render方法,渲染手法重点来了
render() { scene.traverse((obj) => { if (bloomLayer.test(obj.layers) === false) { materials[obj.uuid] = obj.material; obj.material = darkMaterial; } }); bloomComposer.render(); scene.traverse((obj) => { if (materials[obj.uuid]) { obj.material = materials[obj.uuid]; delete materials[obj.uuid]; } }); finalComposer.render(); }
现在已经完工了 你想把哪个几何体设置为辉光效果,就加上 layers.enable(1),让他进入另一个通道渲染
我们回到 getlin创建线条的方法
const mesh = new THREE.Mesh(line.geometry,material)
mesh.layers.enable(1)
效果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。