1

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>

友人A
81 声望11 粉丝