事件

基于物体的识别事件:

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

<!--
 * @Description: 
 * @Version: 1.668
 * @Autor: 地虎降天龙
 * @Date: 2023-12-15 09:28:45
 * @LastEditors: 地虎降天龙
 * @LastEditTime: 2025-10-16 08:22:05
-->
<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"
					@pointerenter="onPointerEnter" @pointerleave="onPointerLeave" @pointermove="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')"
  @contextmenu="(event) => console.log('context-menu (right click)')"
  @doubleclick="(event) => console.log('double-click')"
  @pointermove="(event) => console.log('pointer-move')"
  @pointerenter="(event) => console.log('pointer-enter')"
  @pointerleave="(event) => console.log('pointer-leave')"
  @pointerdown="(event) => console.log('pointer-down')"
  @pointerup="(event) => console.log('pointer-up')"
  @pointercancel="(event) => console.log('Fired when pointer interaction is cancelled')"
/>
事件描述返回参数说明
click基于同一物体的点击Intersectionopen in new window, PointerEventopen in new window
pointermove鼠标在物体上移动Intersectionopen in new window, PointerEventopen in new window
pointerenter鼠标划入物体Intersectionopen in new window, PointerEventopen in new window
pointerleave鼠标划出物体Intersectionopen in new window,PointerEventopen in new window

TIP

<script setup lang="ts">
function onChildClick(event) {
  event.stopPropagation() // Prevents parent from receiving the event
  console.log('Child clicked!')
}

function onParentClick() {
  console.log('Parent clicked!') // Won't fire if child stops propagation
}
</script>

<template>
  <TresGroup @click="onParentClick">
    <TresMesh @click="onChildClick">
      <TresBoxGeometry />
      <TresMeshNormalMaterial />
    </TresMesh>
  </TresGroup>
</template>
  • 因为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
}

tres有 useLoopopen in new window 的全替代解决方案:

// 此函数 可在任意vue文件下 调用
import { useLoop } from '@tresjs/core'
const { onBeforeRender, onRender } = useLoop()

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

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

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

当然,还包括渲染前onBeforeLoop

// 同样 可在任意vue文件下 调用
import { useLoop } from '@tresjs/core'

const { onBeforeRender, onRender } = useLoop()

onBeforeRender(() => {
  console.log('earlier before render')
}, -10)

onBeforeRender(() => {
  console.log('just before render')
})

onBeforeRender(() => {
  console.log('even closer before render')
}, 10)
const { onBeforeRender } = useLoop()
onBeforeRender(({ 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

所有回调都会接收具有以下属性的对象:

  • delta:当前帧与上一帧之间的时间差。这是自上一帧以来的秒数。
  • elapsed:自渲染循环开始以来经过的时间。
  • renderer:您的场景的WebGLRenderer 。
  • scene:你的场景的场景。
  • camera:当前活动的相机。
  • controls:场景的控制。
  • invalidate:使渲染循环无效的方法。仅当您将render-modeprop 设置为 时才需要该方法on-demand。
  • advance:一种推进渲染循环的方法。仅当您将render-modeprop 设置为 时才需要该方法manual。
  • 等等 跳转tres.js章节open in new window