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