threejs记录选中变化纹理

2023-12-11 09:45:20 浏览数 (2)

代码语言:javascript复制
<template>
  <div class="wrap">
    <div ref="container" id="container"></div>
    <div id="panel" v-if="isShowPanel" :style ="{left:left 'px',top:top 'px'}">
      <div>名称:{{panel.name}}</div>
      <div>温度:{{panel.temp}}</div>
      <div>使用情况:{{panel.use}}</div>
    </div>
  </div>
</template>

<script>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import {CSS3DRenderer, CSS3DObject} from "three/examples/jsm/renderers/CSS3DRenderer.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"
import { MeshBasicMaterial, TextureLoader } from 'three';

export default {
  name: "ThreeTest",
  data() {
    return {
      left:0,
      top:0,
      panel:{
        name:"",
        temp:"",
        use:""
      },
      isShowPanel:false,
      //纹理集合
      maps:[],
      // 机柜集合
      cabinets:[],
      //划入的当前机柜
      curcabinet:null
    };
  },
  mounted() {
    // this.getData();
    this.timer = null;
    this.myReq = null;
    this.container;
    this.scene;
    this.camera;
    this.renderer;
    this.labelRenderer;
    this.controls;
    this.initScene();
    this.initCamera();
    this.initRender();
    this.initModel();
    this.initControls();
    this.initLight()
    this.animate();
    window.onresize = this.onWindowResize;
    this.crtTexture("Cube-hover.png")
    document.addEventListener('mousemove', this.onClick, false);
  },

  methods: {
    onClick(event){
      this.selectCabinet(event.clientX,event.clientY)
    },
    selectCabinet(x,y){
      
        var raycaster = new THREE.Raycaster();
        var pointer = new THREE.Vector2();
        const {width,height} = this.renderer.domElement
        console.log(width)
         console.log(height)
        // canvas 坐标转裁剪坐标
        pointer.set((x/width)*2-1,-(y/height)*2 1)
        raycaster.setFromCamera(pointer,this.camera)
                console.log(this.cabinets)
        // 选择机柜
        const intersect = raycaster.intersectObjects(this.cabinets)[0]
        let intersectObject = intersect?intersect.object:null
        console.log(this.curcabinet)

        console.log(intersectObject)
        // 若之前已有机柜被选择,且不等于当前所选择的机柜,取消之前选择的机柜的高亮
        if(this.curcabinet && this.curcabinet!=intersectObject){
          const material = this.curcabinet.material
          material.setValues({
            map:this.getMapByName("Cube.png")
          })
        }

        if(intersectObject){
          this.onMouseMoveCabinet(x,y)
          if(intersectObject != this.curcabinet){
            this.curcabinet = intersectObject
             const material = this.curcabinet.material
             material.setValues({
                map:this.getMapByName("Cube-hover.png")
             })
             this.onMouseOverCabinet(intersectObject)
          }
        }else if(this.curcabinet){
          this.curcabinet = null
          this.onMouseOutCabinet()
        }
    },
    // 鼠标划入机柜的事件,参数为机柜对象
    onMouseOverCabinet(){
      this.isShowPanel = true
    },
    //在机柜上移动的事件,参数为坐标
    onMouseMoveCabinet(x,y){
     this.left= x
     this.top= y
    },
    // 鼠标划出机柜的事件
    onMouseOutCabinet(){
      this.isShowPanel = false
    },
    pushMap(imageName,curTexture){
      this.maps.push({name:imageName,map:curTexture})
    },
    getMapByName(name){
      let rusult
      for(let i=0;i<this.maps.length;i  ){
        if(this.maps[i].name == name){
          rusult =  this.maps[i].map
          break
        }
      }
      return rusult
    },
    initScene() {
      this.scene = new THREE.Scene();
    },
    initCamera() {
      this.container = document.getElementById("container");
      this.camera = new THREE.PerspectiveCamera(
        70,
        this.container.clientWidth / this.container.clientHeight,
        1,
        1000
      );
      console.log(this.camera);
      this.camera.position.z = 20; //z设置小写会使图像变形小
      this.camera.position.y = 0
    },
    initRender: function () {
      this.renderer = new THREE.WebGLRenderer({ antialias: true });
      this.renderer.setSize(
        this.container.clientWidth,
        this.container.clientHeight
      );
      this.container.appendChild(this.renderer.domElement);
    },

    initLight() {
      this.scene.add(new THREE.AmbientLight(0xb9e1fb));
      this.light = new THREE.DirectionalLight(0xecfbb9,0.2);
      this.light.position.set(0, 0, 50);
      this.scene.add(this.light);
    },
    initModel() {
       let loader = new GLTFLoader()
       let gltScene
        loader.load("models/clickTest/threebox.gltf",(gltf)=>{
         for(let i=0;i<gltf.scene.children.length;i  ){
           console.log(gltf.scene.children[i])
           let mesh = gltf.scene.children[i]
           if(mesh.type == "Mesh"){
             console.log(mesh)
             const {map,color} = mesh.material
             this.changeMat(mesh,map,color)
             if(mesh.name.includes("Cube")){
               this.cabinets.push(mesh)
             }

            //  this.scene.add(mesh)   会有问题。Mesh减少
           }
         }

         this.scene.add(...gltf.scene.children)
       })
    },
    // 修改材质
    changeMat(mesh,map,color){
      let index = map.image.currentSrc.lastIndexOf("/")
      let imageName = map.image.currentSrc.substring(index 1)
      console.log(imageName)
      if(map){
        // this.maps.push({name:mesh.name,map:this.crtTexture(map.name)})
        // console.log(this.maps)
        mesh.material = new MeshBasicMaterial({
          map:this.crtTexture(imageName)
          // map:new THREE.TextureLoader().load("/models/clickTest/Cube.png")
        })
      }else{
        mesh.material = new MeshBasicMaterial({color})
      }
    },
    // 建立纹理对象
    crtTexture(imgName){
      let curTexture = this.getMapByName(imgName)
      if(!curTexture){
        curTexture = new THREE.TextureLoader().load(`/models/clickTest/${imgName}`)
        curTexture.flipY = false
        curTexture.wrapS = 1000
        curTexture.wrapT = 1000
        this.pushMap(imgName,curTexture)
      }
      return curTexture
    },
    initControls(){
       this.controls = new OrbitControls( this.camera, this.renderer.domElement );
    },

    render() {
      this.renderer.render(this.scene, this.camera);
      // this.labelRenderer.render(this.scene, this.camera);
    },
    onWindowResize() {
      this.camera.aspect = window.innerWidth / window.innerHeight;

      this.camera.updateProjectionMatrix();

      this.render();

      this.renderer.setSize(window.innerWidth, window.innerHeight);
      this.labelRenderer.setSize(window.innerWidth, window.innerHeight);
    },
    animate() {
      this.render();
      this.myReq = requestAnimationFrame(this.animate);
    },
  },
  beforeDestroy() {
    cancelAnimationFrame(this.myReq);
    clearInterval(this.timer);
    this.scene = null;
    // this.scene.dispose()
    this.camera = null;
    this.renderer = null;
    this.labelRenderer = null;
    this.controls = null;
  },
  watch: {},
  filters: {},
};
</script>

<style scope>
/deep/.label {
				color: #FFF;
				font-family: sans-serif;
				padding: 2px;
				background: rgba( 0, 0, 0, .6 );
			}
#panel{
  position:absolute;
  left:0;
  top:0;
  background: rgba( 0, 0, 0, .6 );
  padding:10px;
}

</style>

代码语言:javascript复制
threejs 中加载gltf模型 循环Mesh会减少,暂时使用整体加入this.scene.add(...gltf.scene.children)
curTexture = new THREE.TextureLoader().load("/models/clickTest/Cube-export.png")
curTexture.flipY = false
curTexture.wrapS = 1000
curTexture.wrapT = 1000
上面的3个参数不加贴图不准确,有偏移

blender导出是图片和gltf分别单独导出

材质通过setValues重新设置值
material.setValues({
     map:this.getMapByName("Cube-hover.png")
})

0 人点赞