<template>
  <div style="width: 100%; height: calc(100vh - 200px); display: flex; justify-content: center; align-items: center">
    <a-spin :spinning="loading" />
    <div id="damper3D" v-show="!loading"> </div>
  </div>
</template>

<script setup lang="ts">
  import { ref, onMounted, onUnmounted } from 'vue';
  import UseThree from '/@/hooks/core/useThree';
  import * as THREE from 'three';
  import gsap from 'gsap';

  const loading = ref(false);
  let model;


  const setCustomMaterial = (group)=>{
    const cityMaterial = model.track(new THREE.MeshBasicMaterial({
      color: new THREE.Color(0x0c016f),
    }));
    group?.traverse((item: THREE.Mesh) => {
      if (item.type === 'Mesh') {
        item.material = cityMaterial;
        setMaterial(item);
      }
    });
  }

  /* 自定义材质 */
  const setMaterial = (obj) => {
    obj.geometry.computeBoundingBox();
    const { max, min } = obj.geometry.boundingBox;
    const distance = max.y - min.y + 2;

    obj.material.onBeforeCompile = (shader) => {
      shader.uniforms.uDistance = {
        value: distance,
      };
      shader.uniforms.uTopColor = {
        value: new THREE.Color(0xaaaeff),
      };
      addGrad(shader);
      addRadiusSpread(shader);
      addLineSpread(shader);
      addToSpread(shader);
    };
  }
  /* 自定义着色器 */
  const addGrad = (shader) => {
    shader.vertexShader = shader.vertexShader.replace(
      '#include <common>',
      `

      #include <common>
      varying vec3 vPosition;
    `
    );
    shader.vertexShader = shader.vertexShader.replace(
      '#include <fog_vertex>',
      `

      #include <fog_vertex>
      vPosition = position;
     `
    );
    shader.fragmentShader = shader.fragmentShader.replace(
      '#include <common>',
      `
      #include <common>
      uniform vec3 uTopColor;
      uniform float uDistance;
      varying vec3 vPosition;
  
      `
    );

    shader.fragmentShader = shader.fragmentShader.replace(
      '#include <dithering_fragment>',
      `
      #include <dithering_fragment>

      vec4 distGradColor = gl_FragColor;
      // 设置混合的百分比
      float gradMix = (vPosition.y + (uDistance / 2.0)) / uDistance / 5.0;
      // 设置混合颜色
      vec3 colorMix = mix(distGradColor.xyz, uTopColor, gradMix);
      gl_FragColor = vec4(colorMix, 1.0);
      //#end#
      `
    );
  }
  /* 自定义着色器 */
  const addRadiusSpread = (shader) => {
    // 设置扩散中心店
    shader.uniforms.uRadiusSpreadCenter = {
      value: new THREE.Vector2(0, 0),
    };
    // 扩散时间
    shader.uniforms.uRadiusSpreadTime = {
      value: 0,
    };

    shader.uniforms.uRadiusSpreadWidth = {
      value: 20,
    };
    shader.fragmentShader = shader.fragmentShader.replace(
      '#include <common>',
      `
      #include <common>
      uniform vec2 uRadiusSpreadCenter;
      uniform float uRadiusSpreadTime;
      uniform float uRadiusSpreadWidth;

      `
    );

    shader.fragmentShader = shader.fragmentShader.replace(
      '//#end#',
      `
      float spreadRadius = distance(vPosition.xz + vec2(-720, -550), uRadiusSpreadCenter);
      // 扩散范围
      float spreadIndex = -(spreadRadius - uRadiusSpreadTime) * (spreadRadius - uRadiusSpreadTime ) + uRadiusSpreadWidth;
      if(spreadIndex > 0.0){
        gl_FragColor = mix(gl_FragColor, vec4(1.0, 1.0, 1.0, 1.0), spreadIndex / uRadiusSpreadWidth );
      }
      //#end#
      `
    );
    gsap.to(shader.uniforms.uRadiusSpreadTime, {
      value: 250,
      duration: 1,
      ease: 'none',
      repeat: -1,
    });
  }
  /* 自定义着色器 */
  const addLineSpread = (shader)=>{
    // 设置扩散中心店
    shader.uniforms.uLineSpreadCenter = {
      value: new THREE.Vector2(0, 0),
    };
    // 扩散时间
    shader.uniforms.uLineSpreadTime = {
      value: 0,
    };

    shader.uniforms.uLineSpreadWidth = {
      value: 20,
    };
    shader.fragmentShader = shader.fragmentShader.replace(
      '#include <common>',
      `
      #include <common>
      uniform vec2 uLineSpreadCenter;
      uniform float uLineSpreadTime;
      uniform float uLineSpreadWidth;

      `
    );

    shader.fragmentShader = shader.fragmentShader.replace(
      '//#end#',
      `
      float spreadLine = vPosition.x - 400.0;
      // 扩散范围
      float spreadLineIndex = -(spreadLine - uLineSpreadTime * 5.0) * (spreadLine - uLineSpreadTime * 5.0) + uLineSpreadWidth;
      if(spreadLineIndex > 0.0){
        gl_FragColor = mix(gl_FragColor, vec4(1.0, 1.0, 1.0, 1.0), spreadLineIndex / uLineSpreadWidth );
      }
      //#end#
      `
    );
    gsap.to(shader.uniforms.uLineSpreadTime, {
      value: 150,
      duration: 2,
      ease: 'none',
      repeat: -1,
    });
  }
  /* 自定义着色器 */
  const addToSpread = (shader) => {
    // 设置扩散中心店
    shader.uniforms.uTopSpreadCenter = {
      value: new THREE.Vector2(0, 0),
    };
    // 扩散时间
    shader.uniforms.uTopSpreadTime = {
      value: 0,
    };

    shader.uniforms.uTopSpreadWidth = {
      value: 20,
    };
    shader.fragmentShader = shader.fragmentShader.replace(
      '#include <common>',
      `
      #include <common>
      uniform vec2 uTopSpreadCenter;
      uniform float uTopSpreadTime;
      uniform float uTopSpreadWidth;

      `
    );

    shader.fragmentShader = shader.fragmentShader.replace(
      '//#end#',
      `
      float spreadTopLine = vPosition.y * 2.0;
      // 扩散范围uTopSpreadWidth
      float spreadTopIndex = -(spreadTopLine - uTopSpreadTime) * (spreadTopLine - uTopSpreadTime) + uTopSpreadWidth;
      if(spreadTopIndex > 0.0){
        gl_FragColor = mix(gl_FragColor, vec4(0.0, 1.0, 1.0, 1.0), spreadTopIndex / uTopSpreadWidth / uTopSpreadTime * 2.0);
      }
      //#end#
      `
    );
    gsap.to(shader.uniforms.uTopSpreadTime, {
      value: 200,
      duration: 5,
      ease: 'none',
      repeat: -1,
    });
  }

  /* 模型线框 */
  const addLine = (geometry)=>{
    const edges = new THREE.EdgesGeometry(geometry);
    const line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ color: 0xff0000 }));
    (model.scene as THREE.Scene).add(line);
  }

  const addLight = (scene) => {

    const light = new THREE.PointLight( 0xffffff, 1, 1000 );
    light.position.set( 50, 10, 50 );
    // scene.add( light );

    const pointLight = new THREE.PointLight( 0xffffff, 1, 200 );
    pointLight.position.set(0, 0, 10)
    // scene.add( pointLight );
    
    const pointLight2 = new THREE.PointLight( 0xffffff, 1, 100 );
    pointLight2.position.set(0, 3, 10)
    // light2.castShadow = true
    pointLight2.shadow.bias = 0.05
    scene.add(pointLight2)
    // const pointLightHelper2 = new THREE.PointLightHelper( pointLight2, 1 );
    // scene.add( pointLightHelper2 );

    const pointLight3 = new THREE.PointLight( 0xffffff, 1, 100 );
    pointLight3.position.set(-80, 3, 10)
    // light2.castShadow = true
    pointLight3.shadow.bias = 0.05
    scene.add(pointLight3)
    // const pointLightHelper = new THREE.PointLightHelper( pointLight3, 1 );
    // scene.add( pointLightHelper );

    const pointLight4 = new THREE.PointLight( 0xffffff, 1, 100 );
    pointLight4.position.set(37, 3, 10)
    // light2.castShadow = true
    pointLight4.shadow.bias = 0.05
    scene.add(pointLight4)
    // const pointLightHelper4 = new THREE.PointLightHelper( pointLight4, 1 );
    // scene.add( pointLightHelper4 );

    const pointLight5 = new THREE.PointLight( 0xffffff, 1, 100 );
    pointLight5.position.set(100, 3, 10)
    // light2.castShadow = true
    pointLight5.shadow.bias = 0.05
    scene.add(pointLight5)
    // const pointLightHelper5 = new THREE.PointLightHelper( pointLight5, 1 );
    // scene.add( pointLightHelper5 );

 
    pointLight2.shadow.mapSize.width = 10; // default
    pointLight2.shadow.mapSize.height = 10; // default
    pointLight2.shadow.camera.near = -0.0000001; // default
    pointLight2.shadow.camera.far = 20; // default
  
    const spotLight = new THREE.SpotLight();
    spotLight.angle = Math.PI / 16;
    spotLight.penumbra = 0;
    spotLight.castShadow = true;
    spotLight.intensity = 2
    spotLight.position.set( -400, 400, 400 );
    scene.add( spotLight );

    spotLight.shadow.mapSize.width = 2000;  // default
    spotLight.shadow.mapSize.height = 1000; // default
    spotLight.shadow.camera.near = 0.5;    // default
    spotLight.shadow.camera.far = 800      // default
    spotLight.shadow.focus = 1; 
    spotLight.shadow.bias = -0.000001

  }
  const resetCamera = () => {
    model.camera.position.setZ(200)
    model.camera.position.setY(120)
    model.camera?.lookAt( -100, 0.1, 50 );
    model.camera.updateProjectionMatrix();
    model.orbitControls.update()
  }

  onMounted(() => {
    model = new UseThree('#damper3D');
    model.setEnvMap('test1');
    model.setCustomMaterial = setCustomMaterial
    loading.value = true;
    model.setModel('fm-n-processed').then(() => {
      addLight(model.scene)
      resetCamera()
      // 模型加载成功
      loading.value = false;
    });
  });

  onUnmounted(() => {
    if(model){
      model.deleteModal()
    }
  })

</script>
<style scoped lang="scss"></style>
