事件

基于物体的识别事件:

V4.X以后的升级,已经修复了之前的bug,并且和primitive统一起来了

<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import { OrbitControls } from '@tresjs/cientos'
function onClick(ev) {
	if (ev) {
		ev.object.material.color.set('#008080')
	}
}
function onPointerEnter(ev) {
	if (ev) {
		ev.object.material.color.set('#CCFF03')
	}
}
function onPointerLeave(ev) {
	if (ev) {
		ev.eventObject.material.color.set('#efefef')
	}
}
function onPointerMove(ev) {
	if (ev) {
		console.log(ev)
	}
}
</script>
<template>
	<TresCanvas clearColor="#202020">
		<TresPerspectiveCamera :position="[11, 11, 11]" :look-at="[0, 0, 0]" />
		<OrbitControls />
		<template v-for=" x in [-2.5, 0, 2.5] ">
			<template v-for=" y in [-2.5, 0, 2.5] ">
				<TresMesh v-for=" z in [-2.5, 0, 2.5] " :key="`${[x, y, z]}`" :position="[x, y, z]" @click="onClick"
					@pointer-enter="onPointerEnter" @pointer-leave="onPointerLeave" @pointer-move="onPointerMove">
					<TresBoxGeometry :args="[1, 1, 1]" />
					<TresMeshToonMaterial color="#efefef" />
				</TresMesh>
			</template>
		</template>
		<TresDirectionalLight :intensity="1" />
		<TresAmbientLight :intensity="1" />
	</TresCanvas>
</template>
  • Intersectionopen in new window : 返回基于ThreeJS的光线投射Raycaster的 Intersection 类,具体参数详见链接。您可以通过 intersection.object 访问触发事件的 Object3D
  • PointerEventopen in new window :返回 web 通用PointerEvent类,包含鼠标的坐标等,体参数详见链接

直接上代码:

<TresMesh
  @click="(event) => console.log('click')"
  @context-menu="(event) => console.log('context-menu (right click)')"
  @double-click="(event) => console.log('double-click')"
  @pointer-move="(event) => console.log('pointer-move')"
  @pointer-enter="(event) => console.log('pointer-enter')"
  @pointer-leave="(event) => console.log('pointer-leave')"
  @pointer-down="(event) => console.log('pointer-down')"
  @pointer-up="(event) => console.log('pointer-up')"
  @wheel="(event) => console.log('wheel')"
  @pointer-missed="(event) => console.log('pointer-missed')"
/>
事件描述返回参数说明
click基于同一物体的点击Intersectionopen in new window, PointerEventopen in new window
pointer-move鼠标在物体上移动Intersectionopen in new window, PointerEventopen in new window
pointer-enter鼠标划入物体Intersectionopen in new window, PointerEventopen in new window
pointer-leave鼠标划出物体Intersectionopen in new window,PointerEventopen in new window

TIP

  • 通常在几个物体互相遮挡时,可以通过使用 EventPropagation 来控制冒泡事件。 具体例子详见链接:穿透事件open in new window
<TresMesh
  @pointer-down="(event) => {
    console.log('pointer-down')
    event.stopPropagation() //结束冒泡
  }"
/>
  • 因为TresJS封装的事件方法使用的是ThreeJS光线投射(raycaster),所以在物体mesh顶点相对多的时候,会出现卡顿的现象。需要通过开启three-mesh-bvh的方法,增加效率。开启方法详情请见:three-mesh-bvhopen in new window 代码应用详见 TvT.js 开源例子:heatmap2open in new window

  • 加载模型后,使用primitive挂载后,模型绑定事件同TresMesh, 这里不再赘述。

针对整体循环刷新的 Loop 函数

我们在写 three.js 的时候,经常会写如下函数:

// 整体场景刷新
window.requestAnimationFrame(() => {
  render.render(scene, camera)
})

// 或者每个基于Object3D的render循环函数
const cube = new THREE.Mesh(geometry, material)
cube.onBeforeRender = function (
  renderer,
  scene,
  camera,
  geometry,
  material,
  group
) {
  // 在渲染之前执行的自定义操作
  this.rotation.x += 0.01
}

我们现在有 useRenderLoopopen in new window 的全替代解决方案:

// 此函数 可在任意vue文件下 调用
const { onLoop, resume } = useRenderLoop()

onLoop(({ delta, elapsed, clock }) => {
  // I will run at every frame ~60FPS (depending of your monitor)
})

回调onLoop根据时钟接收具有以下属性的对象:

  • delta:当前帧与上一帧之间的时间差。这是自上一帧以来的时间(以秒为单位)。
  • elapsed:自渲染循环开始以来经过的时间。

当然,还包括渲染前onBeforeLoop,渲染后onAfterLoop

// 同样 可在任意vue文件下 调用
const { onBeforeLoop, onAfterLoop } = useRenderLoop()

onBeforeLoop(({ delta, elapsed }) => {
  // I will run before the renderer updates the scene
  fps.begin()
})

onAfterLoop(({ delta, elapsed }) => {
  // I will run after the renderer updates the scene
  fps.end()
})
const { onLoop } = useRenderLoop()
onLoop(({ elapsed }) => {
  if (!sphereRef.value) return
  sphereRef.value.position.y += Math.sin(elapsed) * 0.01
  sphereRef2.value.position.y += Math.sin(elapsed) * 0.01
})

对应gitee源码文件open in new window

事件绑定的bug

注意 Tres.js3.9 以及之前的版本,存在TresGroup以及primitive中有 group 的情况下,事件绑定后,不响应的问题。

新版本已解决方案: