700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Three.js - 鼠标拾取(射线追踪法)(十九)

Three.js - 鼠标拾取(射线追踪法)(十九)

时间:2022-06-11 04:05:40

相关推荐

Three.js - 鼠标拾取(射线追踪法)(十九)

射线追踪法

射线追踪法是最常见的方法,因为three.js提供了Raycaster对象来实现它。原理:从鼠标处发射一条射线,穿透场景的视椎体,通过计算,找出与射线相交的对象。

Raycaster

属性:origin光线投射的原点。direction射线的方向。near投射近点,不能大于far,不能为负值,其默认值为0。far投射远点,不能小于near,其默认值为无穷大。 常用方法:.setFromCamera(coords,camera)更新原点坐标和相机视椎。coords原点坐标,camera相机。.intersectObject(scenes,recursive,optionalTarget)检查射线与场景对象和其子集是否有交集。scenes要检查的场景对象数组格式recursivetrue检查所有后代。optionalTarget返回交集结果,可选。

使用

基础场景,绘制两个立方体。

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><title>学习</title></head><body><canvas id="c2d" class="c2d" width="1000" height="500"></canvas><script type="module">import * as THREE from './file/three.js-dev/build/three.module.js'import {OrbitControls } from './file/three.js-dev/examples/jsm/controls/OrbitControls.js'const canvas = document.querySelector('#c2d')// 渲染器const renderer = new THREE.WebGLRenderer({canvas })const fov = 40 // 视野范围const aspect = 2 // 相机默认值 画布的宽高比const near = 0.1 // 近平面const far = 10000 // 远平面// 透视投影相机const camera = new THREE.PerspectiveCamera(fov, aspect, near, far)camera.position.set(0, 6, 5)camera.lookAt(0, 0, 0)// 控制相机const controls = new OrbitControls(camera, canvas)controls.update()// 场景const scene = new THREE.Scene(){// 灯光const color = 0xffffffconst intensity = 1const light = new THREE.DirectionalLight(color, intensity)light.position.set(-1, 10, 4)scene.add(light)}{// 立方体const boxWidth = 1const boxHeight = 1const boxDepth = 1const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth)const material = new THREE.MeshPhongMaterial({color: 0x6688aa})const cube = new THREE.Mesh(geometry, material)cube.position.x = -1scene.add(cube)const material2 = new THREE.MeshPhongMaterial({color: 0x6688aa})const cube2 = new THREE.Mesh(geometry, material2)cube2.position.x = 1scene.add(cube2)}// 渲染function render() {renderer.render(scene, camera)requestAnimationFrame(render)}requestAnimationFrame(render)</script></body></html>

使用.Raycaster()

第一步获取鼠标的屏幕坐标,将鼠标坐标转化成设备坐标(归一化),后续的操作都交由.Raycaster()完成。这里非全屏使用画布,鼠标坐标以画布开始计算。

// 计算 以画布 开始为(0,0)点 的鼠标坐标function getCanvasRelativePosition(event) {const rect = canvas.getBoundingClientRect()return {x: ((event.clientX - rect.left) * canvas.width) / rect.width,y: ((event.clientY - rect.top) * canvas.height) / rect.height}}

归一化鼠标坐标。

/*** 获取鼠标在three.js 中归一化坐标* */function setPickPosition(event) {let pickPosition = {x: 0, y: 0 }// 计算后 以画布 开始为 (0,0)点const pos = getCanvasRelativePosition(event)// 数据归一化pickPosition.x = (pos.x / canvas.width) * 2 - 1pickPosition.y = (pos.y / canvas.height) * -2 + 1return pickPosition}

监听鼠标事件,获取归一化坐标。使用.intersectObjects()发出射线计算相交对象。需要一个全局对象,用于鼠标离开后恢复对象的原样。

// 监听鼠标window.addEventListener('mousemove', onRay)// 全局对象let lastPick = nullfunction onRay(event) {let pickPosition = setPickPosition(event)const raycaster = new THREE.Raycaster()raycaster.setFromCamera(pickPosition, camera)// 计算物体和射线的交点const intersects = raycaster.intersectObjects(scene.children, true)// 数组大于0 表示有相交对象if (intersects.length > 0) {if (lastPick) {lastPick.object.material.color.set('yellow')}lastPick = intersects[0]} else {if (lastPick) {// 复原lastPick.object.material.color.set(0x6688aa)lastPick = null}}}

就这样一个简单鼠标拾取就完成了。除了射线追踪法还可以使用GPU拾取,它是利用颜色的6位16进制表示,以颜色作为ID,在后台渲染出纹理后。然后,检查鼠标位置关联的像素的颜色,通过颜色来确认相交的对象是哪个。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。