threejs物体扫描

threejs物体扫描


前言

在 vue2 中实现 threejs单物体扫描


一、地形

地形是基于 ImprovedNoise 创建,可以创建具有一定规律的随机点,用来模拟地形效果很好。

//引入
import{ ImprovedNoise } from'three/examples/jsm/math/ImprovedNoise'//柏林噪声

funZ(width, height) {
      let size = width * height;
      let data = new Uint8Array(size);
      let perlin = new ImprovedNoise();
      // 控制地面显示效果  可以尝试0.01  0.1  1等不值
      // 0.1凹凸不平的地面效果  1山脉地形效果
      let quality = 1.2;
      // z值不同每次执行随机出来的地形效果不同
      let z = Math.random() * 100;
      for (let j = 0; j < 4; j++) {
        for (let i = 0; i < size; i++) {
          // x的值0 1 2 3 4 5 6...
          let x = i % width;
          // ~表示按位取反 两个~就是按位取反后再取反
          // ~~相当于Math.floor(),效率高一点
          // y重复若干个值
          let y = ~~(i / width);
          // 通过噪声生成数据
          data[i] += Math.abs(perlin.noise(x / quality, y / quality, z) * quality * 1.75);
          // console.log(y);
        }
        // 循环执行的时候,quality累乘  乘的系数是1  显示效果平面
        quality *= 5;
      }

      return data;
    }

// width,height两个变量用控制平面几何体顶点数量
      // 行列两个方向顶点数量不同  显示效果不同   分别为100和250显示不同的效果
      let width = 250, height = 250;
      // 生成地形顶点高度数据
      let data = this.funZ(width, height);
      //创建一个平面地形,行列两个方向顶点数据分别为width,height
      let geometry = new THREE.PlaneBufferGeometry(400, 400, width - 1, height - 1);
      geometry.rotateX(-Math.PI / 2);
      // 访问几何体的顶点位置坐标数据
      let vertices = geometry.attributes.position.array;
      // 改变顶点高度值
      for (let i = 0, j = 0, l = vertices.length; i < l; i++, j += 3) {
        vertices[j + 1] = data[i] * 0.8;
      }
      // 不执行computeVertexNormals,没有顶点法向量数据
      geometry.computeVertexNormals();

      let mymaterial = this.initShader(light)
      this.planeMaterial = mymaterial
      let mesh = new THREE.Mesh(geometry, mymaterial);
      mesh.position.set(200,200,0)
      scene.add(mesh);

二、材质

1.shader

代码如下(示例):

initShader(light){
      let vertexShader = `
      varying vec3 vNormal;
      varying vec2 vUv;
      uniform vec3 myLight;
      varying vec3 lightToPos;
      varying vec3 myPosition;
      ${THREE.ShaderChunk[ "common" ]}
      ${THREE.ShaderChunk[ "bsdfs" ]}
      ${THREE.ShaderChunk[ "shadowmap_pars_vertex" ]}
      void main()
      {
          ${THREE.ShaderChunk['beginnormal_vertex']}
          ${THREE.ShaderChunk['defaultnormal_vertex']}
          ${THREE.ShaderChunk[ "begin_vertex" ]}
          ${THREE.ShaderChunk[ "project_vertex" ]}
          ${THREE.ShaderChunk[ "worldpos_vertex" ]}
          ${THREE.ShaderChunk[ "shadowmap_vertex" ]}
          vec3 mvposition = vec3((modelViewMatrix * vec4( position, 1.0 )).xyz);
          lightToPos = myLight - mvposition;
          vNormal = normalize(normalMatrix * normal);
          vUv = uv;
          myPosition = vec3((modelMatrix * vec4( position, 1.0 )).xyz);
          gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
      }`
      //float dir = length(vNormal * vec3(0.0, 0.0, 1.0));
      let fragmentShader = `
      uniform vec3 myLight;
      uniform float myTime;
      varying vec3 lightToPos;
      varying vec3 vNormal;
      varying vec3 myPosition;
      varying vec2 vUv;
      ${THREE.ShaderChunk[ "common" ]}
      ${THREE.ShaderChunk[ "packing" ]}
      ${THREE.ShaderChunk[ "bsdfs" ]}
      ${THREE.ShaderChunk[ "lights_pars_begin" ]}
      ${THREE.ShaderChunk[ "shadowmap_pars_fragment" ]}
      ${THREE.ShaderChunk[ "shadowmask_pars_fragment" ]}
      void main(){
        float diff = max( dot( vNormal , normalize(lightToPos) ) , 0.0 );
        vec3 diffuse = diff * vec3(0.9,0.5,0.1);//diff * lightColor

        float lighty = abs(myTime - myPosition.x);
        if(lighty<10.0 && myTime>0.0){
          float lighty_Rev = 1.0 - lighty/10.0;
          diffuse = mix(diffuse , vec3(1,1,1) , lighty_Rev);
        }
        gl_FragColor = vec4( diffuse, 1.0);
      }`
      //着色器材质
      let sm = new THREE.ShaderMaterial({
          uniforms: THREE.UniformsUtils.merge( [
            THREE.UniformsLib[ "lights" ],
            {
                myLight: {type: 'v3', value: light.position},
                myTime: {value:0.0}
            },
          ]),
          vertexShader: vertexShader,
          fragmentShader: fragmentShader,
          // side:THREE.DoubleSide,//双面渲染
          side: THREE.FrontSide,
      });
      return sm
    },

2.使用

代码如下(示例):

    /* 扫描 */
    saomiao(isClick){
      if(isClick && this.state=='stop'){this.state = 'moving'}
      if(this.state=='stop'){return}
      this.myTime += 1.8
      if(this.myTime >400){
        this.myTime = 0
        this.state = 'stop'
      }
      this.updateMaterial()
    },
    /* 材质变化参数 */
    updateMaterial(){
      this.planeMaterial.uniforms.myTime.value = this.myTime
    }




    animation(){
      this.saomiao(false);//扫描
      this.controls.update();//更新控制器插件
      this.stats.update();//更新刷新率插件
      this.draw();//渲染
      window.requestAnimationFrame(this.animation);
    },



    <button @click="saomiao(true)">扫描</button>

总结

这种方式实现扫描效果需要对时间与距离进行计算,不知道有没有大神优化。下一篇写一个后期处理的扫描。

                                                             

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值