龙空技术网

用Three.js搞个泛光轮廓和渐变围栏

王哥爱编程 54

前言:

现在你们对“我的世界js怎么做地图”大致比较珍视,朋友们都需要剖析一些“我的世界js怎么做地图”的相关知识。那么小编也在网摘上收集了一些有关“我的世界js怎么做地图””的相关知识,希望我们能喜欢,同学们快快来学习一下吧!

1.3D区块泛光轮廓

网上好多是LineMaterial画的轮廓,通过attributes的color来配置高亮部分颜色,我这里用的是TubeGeometry,就想有点线宽的样子。

1.画个3D区块

js复制代码createRegion(points) {          const extrudeSettings = {            depth: 0.2,            bevelEnabled: false          };          const shape = new THREE.Shape();          shape.moveTo(points[0].x, points[0].z);          for (let i = 1; i < points.length; i = i + 2) {            shape.lineTo(points[i].x, points[i].z);          }          shape.lineTo(points[0].x, points[0].z);          //添加区块形状          const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);          //卫星贴图          const tex = new THREE.TextureLoader().load('./assets/tex.png');          tex.wrapS = THREE.RepeatWrapping;          tex.wrapT = THREE.RepeatWrapping;          const material = new THREE.MeshBasicMaterial({            map: tex,            color: new THREE.Color('#00FFFF')          });          const mesh = new THREE.Mesh(geometry, material);          //将竖着的形状转个90度          mesh.rotateX(Math.PI * 0.5);          return mesh        }

注意:

points是区块外边界,这里用的是广州的。卫星贴图是随便截图的正方形图片,不是真实的,只是为了好看。经纬度坐标记得用d3-geo转换成px

js复制代码import d3geo from './d3-geo.min.js';let geoFun;export function initGeoFun(size) {//放大倍数  geoFun = d3geo.geoMercator().scale(size); }export const latlng2px = (pos) => {  if (pos[0] >= -180 && pos[0] <= 180 && pos[1] >= -90 && pos[1] <= 90) {    return geoFun(pos);  }  return pos;};initGeoFun(180);          let points = await this.getData();          //转换经纬度          points = points.map((item) => {            const p = latlng2px(item);            return new THREE.Vector3(p[0], 0, p[1]);          });

详细3D区块地图实现请参考:用Three.js搞个炫酷的3D区块地图

2.区块轮廓

js复制代码createLine(points) {          const curve = new THREE.CatmullRomCurve3(points, true, 'catmullrom', 0);          const geometry = new THREE.TubeGeometry(            curve,            Math.round(points.length * 0.5),            0.01,            8,            true          );                   const material = new THREE.MeshBasicMaterial({ color: 'white' });          const mesh = new THREE.Mesh(geometry, material);          return mesh;        }        

注意:

CatmullRomCurve3传入的点经纬度是x位经度,z为纬度。因为是基于CatmullRomCurve3计算的,可能轮廓有一小部分不重合,但是别纠结,看上去没问题就行。3.让轮廓动起来

顶点着色器

c++复制代码uniform float time;uniform float size;uniform float len;uniform vec3 color1;uniform vec3 color2;varying vec3 vColor;void main() {    vColor =color1;    vec3 newPosition = position;    float d = uv.x - time;//当前运动点的距离       if(abs(d) < len) {//如果在范围内,则管道宽度变大,颜色变成color2        newPosition = newPosition + normal * size;        vColor = color2;    }    gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);}

片元着色器

c++复制代码varying vec3 vColor; void main() {  gl_FragColor =vec4(vColor, 1.0);}

将材质换成ShaderMaterial

js复制代码 const material = new THREE.ShaderMaterial({            uniforms: {              time: { value: 0.0 },//运动时间              len: { value: 0.05 },//运动点距离范围              size: { value: 0.02 },//管道增加宽度              color1: { value: new THREE.Color('#FFFFFF') },              color2: { value: new THREE.Color('yellow') }            },            vertexShader: ``,            fragmentShader: ``          });          this.material = material;

动画修改time,让轮廓随着时间动起来

js复制代码   animateAction() {          if (this.material) {            if (this.time >= 1.0) {              this.time = 0.0;            }            this.time = this.time + 0.005;            this.material.uniforms.time.value = this.time;          }        }
4.添加后期泛光效果

只有轮廓需要泛光,这里用了visible显隐来控制部分泛光

js复制代码 initBloom(params) {          const renderScene = new RenderPass(this.scene, this.camera);          const bloomPass = new UnrealBloomPass(            new THREE.Vector2(this.container.offsetWidth, this.container.offsetHeight),            1.5,            0.4,            0.85          );          bloomPass.threshold = params.threshold;          bloomPass.strength = params.strength;          bloomPass.radius = params.radius;          const composer = new EffectComposer(this.renderer);          composer.addPass(renderScene);          composer.addPass(bloomPass);          const outputPass = new OutputPass();          composer.addPass(outputPass);          this.composer = composer;        }animate(){ this.renderer.setViewport(              0,              0,              this.container.offsetWidth,              this.container.offsetHeight            );            //必须关闭autoClear,避免渲染效果被清除            this.renderer.autoClear = false;            this.renderer.clear();            //不需要发光的物体在bloom后期前隐藏            this.normalObj.visible = false;            this.composer.render();            this.renderer.clearDepth();            //不需要发光的物体在bloom后期后显示            this.normalObj.visible = true;            this.renderer.render(this.scene, this.camera);
2.3D区块渐变围栏先将区块形状画出来
js复制代码  createShape(points) {          const shape = new THREE.Shape();          shape.moveTo(points[0].x, points[0].z);          for (let i = 1; i < points.length; i = i + 2) {            shape.lineTo(points[i].x, points[i].z);          }          shape.lineTo(points[0].x, points[0].z);          return shape;        }
围栏和区块都共用这个形状,分别创建两个ExtrudeGeometry,区块的厚度小点,围栏的厚度大点。要实现渐变围栏则需要使用ShaderMaterial 顶点着色器
c++复制代码varying vec2 vUv;varying vec3 vNormal;void main() {    vUv = uv;    vNormal = normal;    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}

片元着色器

c++复制代码uniform vec3 color1;varying vec2 vUv;varying vec3 vNormal;void main() {//顶面和底面都为透明    if(vNormal.z == 1.0 || vNormal.z == -1.0 || vUv.y == 0.0) {        discard;    } else {        gl_FragColor = vec4(color1, mix(1.0, 0.0, vUv.y));//透明度根据竖直方向渐变    }}js复制代码const material = new THREE.ShaderMaterial({            side: THREE.DoubleSide,//双面可见            transparent: true,//开启透明度            depthTest: false,//关闭深度测试            uniforms: {              color1: { value: new THREE.Color('#00FFFF') }//围栏颜色            },            vertexShader: ``,            fragmentShader: ``          });

注意:

围栏记得开启透明度,否则没有渐变效果。另外因为有透明的问题,会出现深度冲突,轮廓重叠的地方有点奇怪的黑边,所以关闭深度测试来纠正。围栏和区块还要根据厚度调整一下位置才能呈现合适的效果。3.3D区块多重渐变围栏根据上面的围栏只需要稍微修改一下片元着色器

c++复制代码uniform vec3 color1;uniform float time;uniform float num;varying vec2 vUv;varying vec3 vNormal;void main() {    if(vNormal.z == 1.0 || vNormal.z == -1.0 || vUv.y == 0.0) {        discard;    } else {    //随着时间移动的多重渐变        gl_FragColor = vec4(color1, 1.0 - fract((vUv.y - time) * num));    }}
对应的ShaderMaterial也要添加参数
js复制代码const material = new THREE.ShaderMaterial({            side: THREE.DoubleSide,            transparent: true,            depthTest: false,            uniforms: {              time: { value: 0.0 },//时间变化              num: { value: 5.0 },//几重渐变              color1: { value: new THREE.Color('#00FFFF') }            },            vertexShader: ``,            fragmentShader: ``          });                                animateAction() {//改变时间动起来          if (this.material) {            if (this.time >= 1.0) {              this.time = 0.0;            }            this.time = this.time + 0.005;            this.material.uniforms.time.value = this.time;          }        }
Github地址

github.com/xiaolidan00…

作者:敲敲敲敲暴你脑袋 链接:

标签: #我的世界js怎么做地图