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

ThreeJs功能演示——几何体操作导入导出

1、内部创建几何体导出编辑能力

1)支持内部创建的面、正方体、球体

内部创建物体时,如果是三维物体,要创建集合形状geometry,和对应的材质material。再一起创建一个三维物体。

	// 存储创建的几何体列表
	const geometries = [];
	createPlane()
	createCube()
	createSphere()
	addGUIForGeometry(geometries)
	// 几何体创建函数
	function createPlane() {
		const geometry = new THREE.PlaneGeometry(1,1);
		const material = new THREE.MeshBasicMaterial({color:0xffff00, side:THREE.DoubleSide})
		const plane = new THREE.Mesh(geometry, material)
		plane.name = "Plane";
		plane.position.set(-1, -1, -1)
		scene.add(plane)
		geometries.push(plane)
		return plane;
	}
	// 创建正方体
	function createCube() {
		const geometry = new THREE.BoxGeometry(1, 1, 1 );
		const material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
		const cube = new THREE.Mesh( geometry, material );
		cube.name = 'Cube';
		scene.add( cube );
		geometries.push(cube);
		return cube;
	}
	// 创建球体
	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(2,2,2)
		scene.add( sphere );
		geometries.push(sphere);
		return sphere;
	}

2)支持几何体的位置、角度、比例调整

通过GUI控制器调整创建物体的位置、角度、放大比例信息。

	// GUI控制器
	function addGUIForGeometry(geometryArr) {
		const gui = new GUI();
		gui.add({x:0}, 'x', -10, 10).name('Position X').onChange((value)=>{
			for (let element of geometryArr) {
				console.log(element.position)
				element.position.set(value, element.position.y, element.position.z)
			}
			animate()
		});
		gui.add({scale:1}, 'scale', 0.1, 10).name('Scale').onChange((value)=>{
			for (let element of geometryArr) {
				element.scale.set(value, value, value)
			}
			animate()
		});
		gui.add({rotateX:0}, "rotateX",  -Math.PI, Math.PI).name("Rotate X").onChange((value)=>{
			for (let element of geometryArr) {
				element.rotation.set(value, element.rotation.y, element.rotation.z)
			}
			animate()
		})
		gui.open();
	}

3)支持几何体批量导出、重新导入

将3D物体的位置、形状、角度、放大序列化到json文件,支持导出。

导入时,根据物体的类型分别创建3D模型

	// 导入几何体
	function importGeometries() {
		const input = document.createElement('input');
		input.type = 'file';
		input.accept = '.json';
		input.addEventListener('change', (event) => {
			const file = event.target.files[0];
			if (file) {
				const reader = new FileReader();
				reader.onload = (e) => {
					const geometriesData = JSON.parse(e.target.result);
					geometriesData.forEach(data => {
						let geometry;
						let material;
						switch (data.type) {
							case 'Mesh':
								switch (data.name) {
									case 'Plane':
										geometry = new THREE.PlaneGeometry(data.geometryData.vertices, data.geometryData.indices);
										material = new THREE.MeshBasicMaterial({ color: 0xffff00, side: THREE.DoubleSide });
										break;
									case 'Cube':
										geometry = new THREE.BoxGeometry(data.geometryData.vertices, data.geometryData.indices);
										material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
										break;
									case 'Sphere':
										geometry = new THREE.SphereGeometry(data.geometryData.vertices, data.geometryData.indices);
										material = new THREE.MeshBasicMaterial({ color: 0x0000ff });
										break;
								}
								const mesh = new THREE.Mesh(geometry, material);
								mesh.name = data.name;
								mesh.position.fromArray(data.position);
								mesh.rotation.fromArray(data.rotation);
								mesh.scale.fromArray(data.scale);
								scene.add(mesh);
								geometries.push(mesh);
								break;
						}
					});
				};
				reader.readAsText(file);
			}
		});
		input.click();
	}

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>
<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';
	// 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);
	}
	animate();
	// 存储创建的几何体列表
	const geometries = [];
	createPlane()
	createCube()
	createSphere()
	addGUIForGeometry(geometries)
	// 几何体创建函数
	function createPlane() {
		const geometry = new THREE.PlaneGeometry(1,1);
		const material = new THREE.MeshBasicMaterial({color:0xffff00, side:THREE.DoubleSide})
		const plane = new THREE.Mesh(geometry, material)
		plane.name = "Plane";
		plane.position.set(-1, -1, -1)
		scene.add(plane)
		geometries.push(plane)
		return plane;
	}
	// 创建正方体
	function createCube() {
		const geometry = new THREE.BoxGeometry(1, 1, 1 );
		const material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
		const cube = new THREE.Mesh( geometry, material );
		cube.name = 'Cube';
		scene.add( cube );
		geometries.push(cube);
		return cube;
	}
	// 创建球体
	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(2,2,2)
		scene.add( sphere );
		geometries.push(sphere);
		return sphere;
	}

	// GUI控制器
	function addGUIForGeometry(geometryArr) {
		const gui = new GUI();
		gui.add({x:0}, 'x', -10, 10).name('Position X').onChange((value)=>{
			for (let element of geometryArr) {
				console.log(element.position)
				element.position.set(value, element.position.y, element.position.z)
			}
			animate()
		});
		gui.add({scale:1}, 'scale', 0.1, 10).name('Scale').onChange((value)=>{
			for (let element of geometryArr) {
				element.scale.set(value, value, value)
			}
			animate()
		});
		gui.add({rotateX:0}, "rotateX",  -Math.PI, Math.PI).name("Rotate X").onChange((value)=>{
			for (let element of geometryArr) {
				element.rotation.set(value, element.rotation.y, element.rotation.z)
			}
			animate()
		})
		gui.open();
	}
	function handleKeyDown(event) {
		switch (event.key) {
			case 'e':
				exportToJSON(geometries)
				break;
			case 'r':
				clearGeometries(geometries)
				break;
			case 'i':
				importGeometries(geometries)
				break;
		}
	}
	document.addEventListener('keydown', handleKeyDown);

	function exportToJSON(geometryList) {
		const geometriesData = geometryList.map(geometry => {
			return {
				name: geometry.name,
				position: geometry.position.toArray(),
				rotation: geometry.rotation.toArray(),
				scale: geometry.scale.toArray(),
				// 根据几何体类型添加更多特定信息
				type: geometry.type,
				geometryData: geometry.geometry.toJSON()
			};
		});
		const blob = new Blob([JSON.stringify(geometriesData)], { type: 'application/json' });
		const url = URL.createObjectURL(blob);
		const a = document.createElement('a');
		a.href = url;
		a.download = 'geometries.json';
		document.body.appendChild(a);
		a.click();
		document.body.removeChild(a);
		URL.revokeObjectURL(url);
	}
	// 清除几何体
	function clearGeometries(geoArr) {
		geometries.forEach(geometry => scene.remove(geometry));
		geometries.length = 0;
	}
	// 导入几何体
	function importGeometries() {
		const input = document.createElement('input');
		input.type = 'file';
		input.accept = '.json';
		input.addEventListener('change', (event) => {
			const file = event.target.files[0];
			if (file) {
				const reader = new FileReader();
				reader.onload = (e) => {
					const geometriesData = JSON.parse(e.target.result);
					geometriesData.forEach(data => {
						let geometry;
						let material;
						switch (data.type) {
							case 'Mesh':
								switch (data.name) {
									case 'Plane':
										geometry = new THREE.PlaneGeometry(data.geometryData.vertices, data.geometryData.indices);
										material = new THREE.MeshBasicMaterial({ color: 0xffff00, side: THREE.DoubleSide });
										break;
									case 'Cube':
										geometry = new THREE.BoxGeometry(data.geometryData.vertices, data.geometryData.indices);
										material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
										break;
									case 'Sphere':
										geometry = new THREE.SphereGeometry(data.geometryData.vertices, data.geometryData.indices);
										material = new THREE.MeshBasicMaterial({ color: 0x0000ff });
										break;
								}
								const mesh = new THREE.Mesh(geometry, material);
								mesh.name = data.name;
								mesh.position.fromArray(data.position);
								mesh.rotation.fromArray(data.rotation);
								mesh.scale.fromArray(data.scale);
								scene.add(mesh);
								geometries.push(mesh);
								break;
						}
					});
				};
				reader.readAsText(file);
			}
		});
		input.click();
	}
</script>
</body>
</html>


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

相关文章:

  • 「刘一哥GIS」系列专栏《GRASS GIS零基础入门实验教程(配套案例数据)》专栏上线了
  • hadoop3.3和hive4.0安装——单节点
  • 11-天猫订单数据分析
  • idea 自动导包,并且禁止自动导 *(java.io.*)
  • Java 面试题 - ArrayList 和 LinkedList 的区别,哪个集合是线程安全的?
  • replaceState和vue的router.replace删除query参数的区别
  • YOLOv8改进,YOLOv8检测头融合RFAConv卷积,并添加小目标检测层(四头检测),适合目标检测、分割等
  • Meta Quest 4:未来的虚拟现实体验
  • 数据区的内存空间
  • 海豚调度DolphinScheduler-3.1.9配置windows本地开发环境
  • “飞的”点外卖,科技新潮流来袭
  • WordPress Squirrly SEO插件存在身份认证SQL注入漏洞(CVE-2025-22783)
  • 基于SynxFlow库实现GPU加速的雨洪仿真(Python)
  • Linux 常用文件查看命令
  • android adb 无线连接 (wifi)
  • CPU负载与CPU使用率之区别
  • 网络科技有限公司网络设计
  • 数据结构漫游记:动态带头双向循环链表
  • 深度学习与浮点数精度问题探究
  • 【Unity-Game4Automation PRO 插件】
  • HCIP笔记1--IP路由基础回顾、BFD单臂回声、OSPF基础
  • wproxy客户端安装,代理返回JSON
  • 将图像输入批次扁平化为CNN
  • 掌握Golang strings包:高效字符串处理指南
  • Leetcode:3095
  • 中间件 MetaQ