当前位置: 首页 > article >正文

ThreeJS能力演示——界面点选交互能力

1、支持界面点选

点选模型整体思路是:根据camera位置作为起始点,叠加鼠标相对位置作为偏置,摄像头方向作为射线方向。

根据射线方向中的遇到的3D物体列表,第一个遇到的物体作为被点选的物体。

	// 鼠标事件处理
	let selectedObject = null;
	const raycaster = new THREE.Raycaster();
	const mouse = new THREE.Vector2();
	const rayHelper = new THREE.Line(new THREE.BufferGeometry(), new THREE.LineDashedMaterial({ color: 0xff0000, dashSize: 1, gapSize: 1 }));
	scene.add(rayHelper);

	function onMouseClick(event) {
		event.preventDefault();
		mouse.x = ((event.clientX / renderer.domElement.clientWidth) * 2) - 1;
		mouse.y = -((event.clientY / renderer.domElement.clientHeight) * 2) + 1;
		raycaster.setFromCamera(mouse, camera);
		const intersects = raycaster.intersectObjects(scene.children);
		if (intersects.length > 0) {
			selectedObject = intersects[0].object;
			const selectionInfo = document.getElementById('selection-info');
			selectionInfo.innerHTML = `选中对象: ${selectedObject.name}`;
			const origin = new THREE.Vector3();
			origin.copy(camera.position);
			const direction = new THREE.Vector3();
			direction.copy(raycaster.ray.direction).multiplyScalar(100);
			rayHelper.geometry.setFromPoints([origin, origin.clone().add(direction)]);
		} else {
			selectedObject = null;
			const selectionInfo = document.getElementById('selection-info');
			selectionInfo.innerHTML = '未选中任何对象';
			rayHelper.geometry.dispose();
			rayHelper.geometry = new THREE.BufferGeometry();
		}
	}

	window.addEventListener('click', onMouseClick);

2、整体代码

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Three.js 几何体操作示例</title>
	<style>
		body { margin: 0; overflow: hidden; }
		#camera-info {
			position: absolute;
			top: 10px;
			left: 10px;
			background-color: rgba(0, 0, 0, 0.5);
			color: white;
			padding: 10px;
			font-family: Arial, sans-serif;
		}
	</style>
</head>
<body>
<div id="camera-info"></div>
<div id="selection-info"></div>
<script type="importmap">
	{
		"imports": {
			"three": "./three.js-master/build/three.module.js",
			"three/addons/": "./three.js-master/examples/jsm/"
		}
	}
</script>
<script type="module">
	import * as THREE from "three"
	import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
	import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
	import { PCDLoader } from "three/addons/loaders/PCDLoader.js"
	import { GLTFLoader } from "three/addons/loaders/GLTFloader.js"
	// 1) 创建画布
	const scene = new THREE.Scene();
	scene.background = new THREE.Color( 0xa0a0a0 );
	const renderer = new THREE.WebGLRenderer();
	renderer.setSize(window.innerWidth, window.innerHeight);
	document.body.appendChild(renderer.domElement);

	// 2) 设置 camera 位置,朝向角度
	const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
	camera.position.set(0, 0, 20); // 设置相机位置
	camera.lookAt(scene.position); // 让相机朝向场景中心

	// 设置控制轨道
	const controls = new OrbitControls( camera, renderer.domElement );
	controls.target.set( 0, 0.1, 0 );
	controls.update();
	controls.minDistance = 0.5;
	controls.maxDistance = 1000;
	controls.maxPolarAngle = 0.5 * Math.PI;

	// 5) 支持动态显示摄像头位置、角度、缩放信息
	const cameraInfo = document.getElementById('camera-info');
	function updateCameraInfo() {
		cameraInfo.innerHTML = `
                摄像头信息:<br>
                位置: (${camera.position.x.toFixed(2)}, ${camera.position.y.toFixed(2)}, ${camera.position.z.toFixed(2)})<br>
                角度: (${camera.rotation.x.toFixed(2)}, ${camera.rotation.y.toFixed(2)}, ${camera.rotation.z.toFixed(2)})<br>
                缩放: ${camera.zoom.toFixed(2)}
            `;
	}
	updateCameraInfo();
	// 渲染循环
	function animate() {
		requestAnimationFrame(animate);
		updateCameraInfo();
		renderer.render(scene, camera);
	}

	// 存储创建的几何体列表
	createSphere()
	// 几何体创建函数
	// 创建球体
	function createSphere() {
		const geometry = new THREE.SphereGeometry( 1, 32, 32 );
		const material = new THREE.MeshBasicMaterial( {color: 0x0000ff} );
		const sphere = new THREE.Mesh( geometry, material );
		sphere.name = 'Sphere';
		sphere.position.set(0,0,0)
		scene.add( sphere );
		return sphere;
	}
	// 1) 导入点云
	const loader = new PCDLoader();
	loader.load( './exported_point_cloud.pcd', function ( points ) {
		// loader.load( './three.js-master/examples/models/pcd/binary/Zaghetto.pcd', function ( points ) {
		points.geometry.center();
		points.geometry.rotateX( Math.PI );
		points.name = 'Zaghetto.pcd';
		points.position.set(2,0,0)
		scene.add( points );
	} );
	// 1) 导入glb模型
	const glb_loader = new GLTFLoader();
	glb_loader.load('./three.js-master/examples/models/gltf/Horse.glb', (gltf) => {
		// loader.load('./exported_model.gltf', (gltf) => {
		const model = gltf.scene;
		model.name = "Horse.glb"
		scene.add(model);
		// 2) 支持缩放模型比例
		model.scale.set(1, 1, 1);
		// 3) 支持调整模型放置位置,角度姿态
		model.position.set(0, 0, 0);
		model.rotation.set(0, 0, 0);
	}, undefined, (error) => {
		console.error('模型加载失败: ', error);
	});
	animate();

	// 鼠标事件处理
	let selectedObject = null;
	const raycaster = new THREE.Raycaster();
	const mouse = new THREE.Vector2();
	const rayHelper = new THREE.Line(new THREE.BufferGeometry(), new THREE.LineDashedMaterial({ color: 0xff0000, dashSize: 1, gapSize: 1 }));
	scene.add(rayHelper);

	function onMouseClick(event) {
		event.preventDefault();
		mouse.x = ((event.clientX / renderer.domElement.clientWidth) * 2) - 1;
		mouse.y = -((event.clientY / renderer.domElement.clientHeight) * 2) + 1;
		raycaster.setFromCamera(mouse, camera);
		const intersects = raycaster.intersectObjects(scene.children);
		if (intersects.length > 0) {
			selectedObject = intersects[0].object;
			const selectionInfo = document.getElementById('selection-info');
			selectionInfo.innerHTML = `选中对象: ${selectedObject.name}`;
			const origin = new THREE.Vector3();
			origin.copy(camera.position);
			const direction = new THREE.Vector3();
			direction.copy(raycaster.ray.direction).multiplyScalar(100);
			rayHelper.geometry.setFromPoints([origin, origin.clone().add(direction)]);
		} else {
			selectedObject = null;
			const selectionInfo = document.getElementById('selection-info');
			selectionInfo.innerHTML = '未选中任何对象';
			rayHelper.geometry.dispose();
			rayHelper.geometry = new THREE.BufferGeometry();
		}
	}

	window.addEventListener('click', onMouseClick);
	animate();
</script>
</body>
</html>

代码中为了方面确定鼠标射线,在点选后,我这边通过rayHelper显示点选射线方向。实际应用时可以删除。


http://www.kler.cn/a/508847.html

相关文章:

  • MATLAB基础应用精讲-【优化算法】阿基米德优化算法(附MATLAB代码实现)
  • 深度学习 Pytorch 张量(Tensor)的创建和常用方法
  • 【ArcGIS微课1000例】0140:总览(鹰眼)、放大镜、查看器的用法
  • NodeJS | 搭建本地/公网服务器 live-server 的使用与安装
  • 动态主机配置协议 (DHCPv4)介绍,详细DHCP协议学习笔记
  • 深入了解卷积神经网络(CNN):图像处理与深度学习的革命性技术
  • 探索基于机器学习的信用评分:从数据到洞察
  • Android BottomNavigationView不加icon使text垂直居中,完美解决。
  • PyTorch使用教程(4)-torch.nn
  • PCL 计算多边形的面积【2025最新版】
  • Redisson分布式锁的原理和实践?
  • 0基础跟德姆(dom)一起学AI 自然语言处理16-输入部分实现
  • Kotlin Bytedeco OpenCV 图像图像55 图像透视变换
  • macOS docker hub / docker desktop替代方案
  • 逻辑结构与存储结构
  • visionpro数据-输入-输出
  • 【深度学习】Pytorch:自实现残差网络
  • pyspark连接clickhouse数据库的方式(其它数据库同样适用)
  • Jenkins质量门禁设计方案的深入探讨
  • SQL Server 2022中文软件下载安装过程
  • 中间件以及主流中间件产品:IBM MQSeries和BEA Tuxedo介绍
  • 爬虫请求失败时如何处理?
  • AWS设计和实现低空管理系统
  • Visual Studio2019调试DLL
  • 如何构建优质的prompt
  • 3d系统误差分析