three.js 点击交互事件 含解决点击的物体与看到的不一致问题(非全屏/多边形偏移)

这篇具有很好参考价值的文章主要介绍了three.js 点击交互事件 含解决点击的物体与看到的不一致问题(非全屏/多边形偏移)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在 three.js 中,可以通过添加事件监听器来实现点击交互事件。具体步骤如下:文章来源地址https://www.toymoban.com/news/detail-735312.html

1. 获取场景中的所有物体,并为每个物体添加一个点击事件监听器。

javascript 
scene.traverse(function(object) { 
  if (object instanceof THREE.Mesh) { 
    object.addEventListener('click', function() { 
      // 处理点击事件 
    }); 
  } 
}); 

2. 在点击事件处理函数中,可以获取到被点击的物体对象,并进行相应的操作。


function handleClick(event) { 
  var mouse = new THREE.Vector2(); 
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1; 
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; 
 
  var raycaster = new THREE.Raycaster(); 
  raycaster.setFromCamera(mouse, camera); 
 
  var intersects = raycaster.intersectObjects(scene.children, true); 
 
  if (intersects.length > 0) { 
    var clickedObject = intersects[0].object; 
    // 处理被点击的物体对象 
  } 
}

需要注意的是,有时候点击的物体与看到的物体不一致,这可能是由于非全屏或多边形偏移等问题导致的。解决方法如下:

1. 非全屏问题:在创建渲染器时,将 canvas 的宽高设置为窗口的宽高。

var renderer = new THREE.WebGLRenderer({ canvas: canvas }); 
renderer.setSize(window.innerWidth, window.innerHeight); 

2. 多边形偏移问题:在创建材质时,设置 polygonOffset 属性。

var material = new THREE.MeshBasicMaterial({ 
  color: 0xffffff, 
  polygonOffset: true, 
  polygonOffsetFactor: 1, 
  polygonOffsetUnits: 1 
}); 

通过以上方法,可以实现 three.js 中的点击交互事件,并解决点击的物体与看到的不一致问题。

示例

<template>
  <div class="hello">
    <div class="tip">
      <canvas id="three"></canvas>
    </div>
    
    <Mabtn @cocorbtn="cocorbtn" @caizhibtn="caizhibtn" @btnopen="btnopen"/>
  </div>
</template>

<script>
import Mabtn from "../components/mabtn.vue";
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
// 添加轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer"
import {RenderPass} from "three/examples/jsm/postprocessing/RenderPass"
import {OutlinePass} from "three/examples/jsm/postprocessing/OutlinePass"
import {ShaderPass} from "three/examples/jsm/postprocessing/ShaderPass"
import {FXAAShader} from "three/examples/jsm/shaders/FXAAShader"

import {setcolor} from '../../public/setColor'
var OBJ = ''
export default {
  name: 'HelloWorld',
  components:{
    Mabtn
  },
  data(){
    return{

      renderer:null,
      nameNode:null,
      composer:null,
      outlinePass:null,
      renderPass:null,
      scene:null,
      camera:null,
      gltfscene:null,
      bujian:'',
      faguang:false,
    }
  },
  mounted() {
    this.initThree()
    // this.render()
  },
  
  methods: {
    btnopen(){
      // document.querySelector('#three').style.height='100%'
      
    },
    cocorbtn(b){
      console.log(b);
      console.log(this.faguang);
      if (!this.faguang) {
        if (this.nameNode.children.length>0) { //点击颜色
          let img =  setcolor(b)
           // 更换纹理贴图
          var texture = new THREE.TextureLoader().load(img + '.png');
          OBJ.material.map = texture
          for (let i = 0; i < this.nameNode.children.length; i++) {
            this.nameNode.children[i].material.color.set(b)
          } 
        }else{
          this.nameNode.material.color.set(b)
        }
      }
     
    },
    caizhibtn(a){//点击部件
      console.log(a);
      this.bujian=a
      this.nameNode=this.gltfscene.getObjectByName(a)
      if (this.nameNode.children.length>0) { //点击颜色
        this.outlineObj([this.nameNode.children[0]])
        OBJ = this.nameNode.children[0]
        console.log(this.nameNode.children[0]);
      }else{
        this.outlineObj([this.nameNode])
        OBJ = this.nameNode
      }
      this.faguang=!this.faguang
    },
    
    initThree() {
      let that = this
      this.scene = new THREE.Scene() // 创建一个scene 
      this.scene.background = new THREE.Color('#eee') // 背景颜色

      const canvas = document.querySelector('#three')
      // 渲染器锯齿属性.antialias
      that.renderer = new THREE.WebGLRenderer({ canvas, antialias: true }) // 创建一个WebGLRenderer,将canvas和配置参数传入
   
      // 引入3D模型 gltf放置public目录 
      const gltfLoader = new GLTFLoader()
      gltfLoader.load('/ShoeOne/ShoeOne.gltf', (gltf) => {
        let model = gltf.scene
        // 递归遍历所有模型节点批量修改材质
        gltf.scene.traverse(function(obj) {
            if (obj.isMesh) {//判断是否是网格模型
                // console.log('模型节点',obj);
                // console.log('模型节点名字',obj.name);
                // console.log('gltf默认材质',obj.material); 
            }
        });
        console.log(gltf.scene)
        this.gltfscene = gltf.scene
        // 设置模型离中心点的位置
        // gltf.scene.scale.set(40,40,40)
        // gltf.scene.position.x = 0
        // gltf.scene.position.y = -80
        // gltf.scene.position.z = 0
        //  console.log(nameNode);
        //  for (let i = 0; i < nameNode.children.length; i++) {
        //   nameNode.children[i].material.color.set(0xff0000)
        //   nameNode.children[i].position.x = 0
        //   nameNode.children[i].position.y = -10
        //   nameNode.children[i].position.z = 0
        //  } 
        // const nameNode = gltf.scene.getObjectByName("内里");
        // nameNode.material.color.set(0xff0000);//改变Mesh材质颜色
       
        this.scene.add(model)
      })
      that.renderer.domElement.addEventListener('click', that.modelMouseClick, false) //设置点击方法
      that.renderer.setSize(window.innerWidth, window.innerHeight)

      const hemLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 1)
      hemLight.position.set(0, 48, 0)
      this.scene.add(hemLight)

      //平行光 (这里可以用点光源PointLight和环境光AmbientLight没有特定方向,整体改变场景的光照明暗)
      const dirLight = new THREE.DirectionalLight(0xffffff, 1)
      //光源等位置
      dirLight.position.set(-10, 8, -5)
  
      //使用PerspectiveCamera(透视摄像机):透视相机用来模拟人眼所看到的景象,物体的大小会受远近距离的影响,它是3D场景的渲染中使用得最普遍的投影模式。
      this.camera = new THREE.PerspectiveCamera(
        50,
        window.innerWidth / window.innerHeight,
        1,
        1000
      )
      // camera.position.z = 10 // 正方位
      this.camera.position.set(3, 4, 3);

      const controls = new OrbitControls(this.camera, that.renderer.domElement)
      // 阻尼感
      controls.enableDamping = true
        // 动画循环函数
      function animate() {
        controls.update()
        that.renderer.render(that.scene, that.camera)
        requestAnimationFrame(animate)

        if (resizeRendererToDisplaySize(that.renderer)) {
          const canvas = that.renderer.domElement
          that.camera.aspect = canvas.clientWidth / canvas.clientHeight
          that.camera.updateProjectionMatrix()
        }
        if (that.composer) {
          that.composer.render()
        }
      }
      animate()
      // 物理像素分辨率与CSS像素分辨率
      function resizeRendererToDisplaySize(renderer) {
        const canvas = renderer.domElement
        var width = window.innerWidth
        var height = window.innerHeight
        var canvasPixelWidth = canvas.width / window.devicePixelRatio
        var canvasPixelHeight = canvas.height / window.devicePixelRatio

        const needResize =
          canvasPixelWidth !== width || canvasPixelHeight !== height
        if (needResize) {
          renderer.setSize(width, height, false)
          
        }
        return needResize
      }
    },
        // 窗口监听函数
    onWindowResize() {
      this.camera.aspect = window.innerWidth / window.innerHeight;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(window.innerWidth, window.innerHeight);
    },
 
    
    // 模型的点击事件
    modelMouseClick( event ) {
      let raycaster = new THREE.Raycaster();
      let mouse = new THREE.Vector2();
      // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
      mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
      mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 0.8;


      raycaster.setFromCamera(mouse, this.camera);

      const intersects = raycaster.intersectObjects(this.scene.children);

      // if (intersects[0].object) {
        if (this.nameNode==intersects[0].object) {
          console.log('jin1');
          this.faguang=!this.faguang
        }else{
          console.log('jin2');
          this.faguang=false
        }
      // }
     
      console.log(this.faguang,'001');
      this.nameNode= intersects[0].object
      // 根据它来判断点击的什么,length为0即没有点击到模型
      console.log(intersects.length ? intersects[0].object.name : intersects, 'intersects----->>>')
       // 获取选中最近的 Mesh 对象

       if (intersects.length != 0 && intersects[0].object instanceof THREE.Mesh) {
        this.outlineObj([intersects[0].object] )
      }
      // if(intersects.length){

      // }
    },
    //高亮显示模型(呼吸灯)
    outlineObj (selectedObjects) {
      console.log(selectedObjects);
      // let that = this
       // 创建一个EffectComposer(效果组合器)对象,然后在该对象上添加后期处理通道。
       this.composer = new EffectComposer(this.renderer)
      // 新建一个场景通道  为了覆盖到原理来的场景上
      this.renderPass = new RenderPass(this.scene, this.camera)
      this.composer.addPass(this.renderPass);
      // 物体边缘发光通道
      this.outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), this.scene, this.camera, selectedObjects)
      console.log(this.faguang,'002');
      if (!this.faguang) {
        this.outlinePass.selectedObjects = selectedObjects
      }else{
        this.outlinePass.selectedObjects =[]
      }
      console.log('显示',this.faguang);
      this.outlinePass.edgeStrength = 15.0 // 边框的亮度
      this.outlinePass.edgeGlow = 2// 光晕[0,1]
      this.outlinePass.usePatternTexture = false // 是否使用父级的材质
      this.outlinePass.edgeThickness = 1.0 // 边框宽度
      this.outlinePass.downSampleRatio = 1 // 边框弯曲度
      this.outlinePass.pulsePeriod = 0 // 呼吸闪烁的速度
      this.outlinePass.visibleEdgeColor.set(parseInt(0x0000FF)) // 呼吸显示的颜色
      this.outlinePass.hiddenEdgeColor = new THREE.Color(0x0000FF) // 呼吸消失的颜色
      this.outlinePass.clear = true
      this.composer.addPass(this.outlinePass)
      // 自定义的着色器通道 作为参数
      let effectFXAA = new ShaderPass(FXAAShader)
      effectFXAA.uniforms.resolution.value.set(1 / window.innerWidth, 1 / window.innerHeight)
      effectFXAA.renderToScreen = true
      this.composer.addPass(effectFXAA)
      
    },

 
  }
}
</script>

<style scoped>
.tip{
  width: 100%;
  height: 80%;
  position: fixed;
  top: 0;
  left: 0;
}
#three {
  width: 100% !important;
  height: 100% !important;

}
</style>

到了这里,关于three.js 点击交互事件 含解决点击的物体与看到的不一致问题(非全屏/多边形偏移)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • THREE.JS使用详细(three.js创建3d物体,three.js的使用方式)

    简述:three.js封装了WebGL的底层细节,是一款运行在浏览器中的 3D 引擎,可以用它创建各种三维场景,包括了摄影机、光影、材质等各种对象,目前在Git上已经拥有90k+的star,今天用three.js来构建一个三维模型; 1、首先,在项目中需要下载threejs的相关依赖; 2、在js页面引入使

    2024年01月23日
    浏览(76)
  • unity点击场景内物体进行交互

    提示:本文展示点击事件,另有其他自行研究 前言 一、原理 二、使用步骤 1.使用前提 2.使用脚本 总结 很多情况下我们需要对场景内的物体进行交互,今天我们采用射线检测的方法进行点击。 例如:点击场景内的Cube 进行开始旋转 提示:以下是本篇文章正文内容,下面案例

    2024年02月11日
    浏览(63)
  • three.js中物体的灯光与阴影设置

    要让球体的阴影照射到平面上,需要使用阴影映射技术。具体步骤如下: 在渲染器中启用阴影: 创建一个平面和一个球体: 创建一个聚光灯: 设置球体和聚光灯的关系: 现在打开浏览器预览,就可以看到球体的阴影照射到了平面上。如果想让阴影更加自然,可以调整阴影

    2024年02月11日
    浏览(46)
  • Three 之 three.js (webgl)鼠标/手指通过射线移动物体的简单整理封装

    目录 Three 之 three.js (webgl)鼠标/手指通过射线移动物体的简单整理封装 一、简单介绍 二、实现原理 三、注意事项 四、效果预览 五、案例实现步骤 六、关键代码 Three js 开发的一些知识整理,方便后期遇到类似的问题,能够及时查阅使用。 本节介绍, three.js (webgl) 中,

    2024年02月16日
    浏览(56)
  • Unity功能测试3D物体和UI的点击事件

    我们在功能开发中 当UI和3D物体在一起的时候点击事件通常会有这么几种情况 1、UI和3D物体同时响应事件 这种情况很常见,如果是故意有次功能需求那将不需要改动.实现代码 3D物体上挂载 UI上挂载 这里面ExecuteAll这个方法也可以处理同理响应事件的问题(已注释) 2、UI和3D物体

    2024年02月05日
    浏览(62)
  • Three.js--》理解光源对物体产生影响的重要性

    上篇文章 前端开发者掌握3d技术不再是梦,初识threejs 作为three.js入门篇讲解了许多内容但是没有深入了解其原理以及实现方法,仅仅只是展示了实现的内容及代码,本篇文章将深入讲解实现效果其背后用到的知识与原理。 目录 使用相机控件轨道控制器 理解光源影响 环境光

    2024年02月03日
    浏览(90)
  • Unity3D-场景中3D物体添加点击事件

    Unity3D - 场景中3D物体添加鼠标点击事件 鼠标点击3D物体触发,Unity从本质上来说有两种:一种是通过事件(event)触发,一种是通过射线(ray)判断穿过的物体触发。这两种触发的原理是不同的,不论哪种触发都必须满足触发的要求才可以,既然原理不同,触发的要求也不一样

    2024年02月08日
    浏览(74)
  • Three.js点击地图动态标注

    首先来看看效果  效果目前就是这样。实现这种效果也借用了很多别人的代码,这里我就只说动态添加怎么来的。 首先肯定是创建射线,获得你点击的那个区域,同时在生成地图本身的时候就给mesh对象添加上相应的mesh和center,这里我用的都是各个行政区划的省会。 然后就是

    2024年02月15日
    浏览(42)
  • 【虚幻引擎】UE4/UE5鼠标点击事件实现物体移动

     在UE4/UE5中,引擎有它自己的一套框架体系,虚幻就是基于这一个框架体系来实现的。其中就有PlayerController(玩家控制器),玩家控制器中就有对鼠标的一系列设置,包括显示鼠标,允许点击事件等。  1.创建PlayerController,命名为MyPlayerController 2.打开MyPlayerController,勾选参数

    2024年02月10日
    浏览(103)
  • threejs点击获取三维坐标(Three.js获取鼠标点击的三维坐标)

    绑定点击事件,通过 THREE.Raycaster 光线投射,用于确定鼠标点击位置上有哪些物体, raycaster.intersectObjects(scene.children) 返回点击位置上所有的物体的数组;我们用 var selected = intersects[0] 取第一个,也就是最前面的那个物体;在通过 selected.point 取点坐标

    2024年02月11日
    浏览(118)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包