乐趣区

关于three.js:threejs射线拾取模型点击事件以及控制模型隐藏

onMouseClick()办法实现射线拾取
创立模型的时候能够将 mesh 的 group 特地提出来

gltf.scene.traverse((child) => {if (child.isGroup) {
      child.name = 'dikuai'
      this.groups.push(child);
    }
  });

上面是残缺代码👇👇

<template>
  <div class="main-3d">
    <div id="scene-container" ref="sceneContainer"></div>
    <div class="tool-box">
      <div class="tool-site flexC" @click="show"> 隐身 </div>
      <div class="tool-site flexC" @click="isRotate=!isRotate"> 旋转 </div>
    </div>
  </div>
</template>

<script>
import * as THREE from 'three'
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls'
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader'
export default {
  name: 'HelloWorld',
  data () {
    return {
      container: null,
      scene: null,
      camera: null,
      controls: null,
      renderer: null,
      stats: null,
      models:null,
      isRotate:false,
      groups:[]}
  },
  methods: {onMouseClick() {
      let that = this;
      debugger
      function onMouseClick(event) {let a = document.getElementsByTagName("canvas")
        var canvas
        for(let i of a){if(i.parentElement&&i.parentElement.id&&i.parentElement.id =="scene-container"){canvas = i}
        }
        let x =
          ((event.clientX - canvas.getBoundingClientRect().left) /
            canvas.offsetWidth) *
            2 -
          1; // 规范设施横坐标

        // 这里的 mainCanvas 是个 dom 元素,getBoundingClientRectangle 会返回以后元素的视口大小.

        let y =
          -((event.clientY - canvas.getBoundingClientRect().top) /
            canvas.offsetHeight
          ) *
            2 +
          1; // 规范设施纵坐标

        let standardVector = new THREE.Vector3(x, y, 1); // 规范设施坐标

        // 规范设施坐标转世界坐标

        let worldVector = standardVector.unproject(that.camera);

        // 射线投射方向单位向量(worldVector 坐标减相机地位坐标)

        let ray = worldVector.sub(that.camera.position).normalize();

        // 创立射线投射器对象

        let raycaster = new THREE.Raycaster(that.camera.position, ray);

        // 获取 raycaster 直线和所有模型相交的数组汇合
        var intersects = raycaster.intersectObjects(that.scene.children, true);
        if (intersects.length > 0) {console.log(1);
        }
      }
      // 这个中央肯定用 renderer.domElement 千万别用 window!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!坑
      that.renderer.domElement.addEventListener("click", onMouseClick, false);
    },
    show(){},
    hide(){let a = this.groups.find( item => item.name=='dikuai')
      a.children.forEach(element => {
        element.material.transparent = true
        element.material.opacity = 0
      });
    },
    init () {
      // set container
      this.container = this.$refs.sceneContainer

      // add stats

      // add camera
      const fov = 60 // Field of view
      const aspect = this.container.clientWidth / this.container.clientHeight
      const near = 20 // the near clipping plane
      const far = 300 // the far clipping plane
      const camera = new THREE.PerspectiveCamera(fov, aspect, near, far)
      camera.position.set(0, 50, 100)
      this.camera = camera

      // create scene
      this.scene = new THREE.Scene()
      this.scene.background = new THREE.Color('skyblue')


      var hemiLight = new THREE.HemisphereLight(0xffff55, 0x00ffff, 0.6);
      hemiLight.position.set(0,-100,0)

        var helper = new THREE.HemisphereLightHelper(hemiLight, 5);
        this.scene.add(helper);



      const mainLight = new THREE.DirectionalLight(0xffffff, 4.0)
      mainLight.position.set(10, 50, 10)
      this.scene.add(mainLight,hemiLight)

      const mainLight2 = new THREE.DirectionalLight(0xffffff, 4.0)
      mainLight2.position.set(-10, -50, -10)
      this.scene.add(mainLight2,hemiLight)

      
      

      // add controls
      this.controls = new OrbitControls(this.camera, this.container)

      // create renderer
      this.renderer = new THREE.WebGLRenderer({antialias: true})
      this.renderer.setSize(this.container.clientWidth, this.container.clientHeight)
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.gammaFactor = 2.2
      this.renderer.outputEncoding = THREE.sRGBEncoding
      this.renderer.physicallyCorrectLights = true
      this.container.appendChild(this.renderer.domElement)

      // set aspect ratio to match the new browser window aspect ratio
      this.camera.aspect = this.container.clientWidth / this.container.clientHeight
      this.camera.updateProjectionMatrix()
      this.renderer.setSize(this.container.clientWidth, this.container.clientHeight)

      const loader = new GLTFLoader()

      loader.load(
        '/glb/aaa.glb',
        gltf => {
          debugger
          this.models = gltf.scene
          this.scene.add(this.models)
          gltf.scene.traverse((child) => {if (child.isGroup) {
              child.name = 'dikuai'
              this.groups.push(child);
            }
          });
          console.log(this.groups);
        },
        undefined,
        undefined
      )

      this.renderer.setAnimationLoop(() => {this.rotate()
        this.render()})
    },
    render () {this.renderer.render(this.scene, this.camera)
    },
    rotate() {if(!this.isRotate){return false}
      // this.models.rotation.z += 0.01;
      // this.models.rotation.x += 0.01;
      // this.models.rotation.y += 0.01;
      this.models.rotateY(0.01);
    }
  },
  mounted () {this.init()
    this.onMouseClick()}
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.main-3d{
  width: 100%;
  height: 100%;
  .tool-box{
    position: fixed;
    bottom: 10px;
    right: 10px;
    .tool-site{
      width: 48px;
      height: 36px;
      background: red;
      cursor: pointer;
    }
  }
}
h3 {margin: 40px 0 0;}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {color: #42b983;}
#scene-container {height: 100%;}
</style>
退出移动版