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

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>

相关文章:

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

1、内部创建几何体导出编辑能力 1&#xff09;支持内部创建的面、正方体、球体 内部创建物体时&#xff0c;如果是三维物体&#xff0c;要创建集合形状geometry&#xff0c;和对应的材质material。再一起创建一个三维物体。 // 存储创建的几何体列表const geometries [];cre…...

LeetCode::2270. 分割数组的方案数

2270. 分割数组的方案数 思路 前缀和 提示 给你一个下标从 0 开始长度为 n 的整数数组 nums 。 如果以下描述为真&#xff0c;那么 nums 在下标 i 处有一个 合法的分割 &#xff1a; 前 i 1 个元素的和 大于等于 剩下的 n - i - 1 个元素的和。下标 i 的右边 至少有一个 元…...

elementui表单验证,数据层级过深验证失效

先看示例代码&#xff0c;代码为模拟动态获取表单数据&#xff0c;然后动态添加rules验证规则&#xff0c;示例表单内输入框绑定form内第四层&#xff1a; <template><el-form :model"form" :rules"rules" ref"ruleForm" label-width&…...

【Java】LinkedHashMap (LRU)淘汰缓存的使用

文章目录 **1. initialCapacity&#xff08;初始容量&#xff09;****2. loadFactor&#xff08;加载因子&#xff09;****3. accessOrder&#xff08;访问顺序&#xff09;****完整参数解释示例****示例验证** LinkedHashMap 在 Java 中可维护元素插入或访问顺序&#xff0c;并…...

CancerGPT :基于大语言模型的罕见癌症药物对协同作用少样本预测研究

今天我们一起来剖析一篇发表于《npj Digital Medicine》的论文——《CancerGPT for few shot drug pair synergy prediction using large pretrained language models》。该研究聚焦于一个极具挑战性的前沿领域&#xff1a;如何利用大语言模型&#xff08;LLMs&#xff09;在数…...

《汽车维护与修理》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答&#xff1a; 问&#xff1a;《汽车维护与修理》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的正规学术期刊。 问&#xff1a;《汽车维护与修理》级别&#xff1f; 答&#xff1a;国家级。主管单位&#xff1a;中国汽车维修行业协会 …...

tomcat状态一直是Exited (1)

docker run -di -p 80:8080 --nametomcat001 你的仓库地址/tomcat:9执行此命令后tomcat一直是Exited(1)状态 解决办法&#xff1a; 用以下命令创建运行 docker run -it --name tomcat001 -p 80:8080 -d 你的仓库地址/tomcat:9 /bin/bash最终结果 tomcat成功启动...

消息中间件的基础概念入门

目录 一、什么是消息中间件 1.1、简介 1.2、消息中间件的主要作用 解耦合 异步通信 负载均衡 可靠性与持久性 消息路由与调度 削峰 事务支持 监控与审计 跨平台和跨语言支持 二、常用消息中间件对比 2.1、 RabbitMQ 2.1.1、特点 2.1.2、适用场景 2.2、Apache K…...

基于Web的宠物医院看诊系统设计与实现(源码+定制+开发)在线预约平台、宠物病历管理、医生诊疗记录、宠物健康数据分析 宠物就诊预约、病历管理与健康分析

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…...

Excel数据叠加生成新DataFrame:操作指南与案例

目录 一、准备工作 二、读取Excel文件 三、数据叠加 四、处理重复数据(可选) 五、保存新DataFrame到Excel文件 六、案例演示 七、注意事项 八、总结 在日常数据处理工作中,我们经常需要将不同Excel文档中的数据整合到一个新的DataFrame中,以便进行进一步的分析和处…...

Web 开发入门之旅:从静态页面到全栈应用的第一步

Web 开发入门之旅&#xff1a;从静态页面到全栈应用的第一步 在当今互联网飞速发展的时代&#xff0c;掌握 Web 开发技能已成为众多技术爱好者和职场人士的必修课。然而&#xff0c;对于初学者而言&#xff0c;面对繁杂的技术栈和庞大的学习资源&#xff0c;往往感到无从下手。…...

WebSocket实现分布式的不同方案对比

引言 随着实时通信需求的日益增长&#xff0c;WebSocket作为一种基于TCP的全双工通信协议&#xff0c;在实时聊天、在线游戏、数据推送等场景中得到了广泛应用。然而&#xff0c;在分布式环境下&#xff0c;如何实现WebSocket的连接管理和消息推送成为了一个挑战。本文将对比几…...

基于注意力机制的端到端合成语音检测

End-to-end Synthetic Speech Detection Based on Attention Mechanism 摘要&#xff1a; 五种轻量级注意力模块改为适用于语音序列的 通道注意力机制和 一维空间注意力机制 ASVspoof2019测试集的 等错误率和 最小串联检测代价函数都有所降低 池化层之前嵌入CBAM、ECA的模型测试…...

MySQL NaviCat 安装及配置教程(Windows)【安装】

文章目录 一、 MySQL 下载 1. 官网下载2. 其它渠道 二、 MySQL 安装三、 MySQL 验证及配置四、 NaviCat 下载 1. 官网下载2. 其它渠道 五、 NaviCat 安装六、 NaviCat 逆向工程 软件 / 环境安装及配置目录 一、 MySQL 下载 1. 官网下载 安装地址&#xff1a;https://www.m…...

微信小程序:播放音频

在小程序开发中&#xff0c;音频播放是一个重要的功能。本文将详细介绍小程序音频播放的相关知识点&#xff0c;帮助开发者更好地掌握小程序音频播放的实现方法。 一、小程序音频播放的基本流程 在小程序中&#xff0c;音频播放的基本流程如下&#xff1a; 获取音频数据&#…...

Ubuntu安装K8S

第一步&#xff1a; 安装docker Install Docker #注意docker是早期的名称已经过时了&#xff0c;因此请使用如下命令&#xff0c;一步到位安装docker-ce。 第二步&#xff1a;设置K8S源&#xff1a; &#xff08;大陆使用aliyun源&#xff0c;大陆外使用google源&#xff09;…...

独立同分布时,联合概率密度函数等于边缘概率密度函数乘积

在概率论中&#xff0c;独立同分布&#xff08;i.i.d.&#xff09;指的是多个随机变量既独立又服从相同的概率分布。对于一组随机变量 (X_1, X_2, \dots, X_n)&#xff0c;若它们是独立同分布的&#xff0c;那么它们的联合概率密度函数 (p(x_1, x_2, \dots, x_n)) 就可以表示为…...

半导体数据分析: 玩转WM-811K Wafermap 数据集(三) AI 机器学习

前面我们已经通过两篇文章&#xff0c;一起熟悉了WM-811K Wafermap 数据集&#xff0c;并对其中的一些数据进行了调用&#xff0c;生成了一些统计信息和图片。今天我们接着继续往前走。 半导体数据分析&#xff1a; 玩转WM-811K Wafermap 数据集&#xff08;二&#xff09; AI…...

【.net core】【sqlsugar】时间查询示例

1、时间包含查询示例 //model.TimeInterval为时间区间参数&#xff0c;参数格式为2024-01-01~2025-01-01 //query为当前查询的语句内容 //为当前查询语句增加创建时间模糊搜索查询条件 query query.Where(a > ((DateTime)a.F_CreatorTime).ToString("yyyy-MM-dd HH:m…...

Kotlin 协程基础十 —— 协作、互斥锁与共享变量

Kotlin 协程基础系列&#xff1a; Kotlin 协程基础一 —— 总体知识概述 Kotlin 协程基础二 —— 结构化并发&#xff08;一&#xff09; Kotlin 协程基础三 —— 结构化并发&#xff08;二&#xff09; Kotlin 协程基础四 —— CoroutineScope 与 CoroutineContext Kotlin 协程…...

Kerberos身份认证原理与企业级排错实战指南

1. 这不是“另一个登录框”&#xff0c;而是一套精密运转的身份验证齿轮系统很多人第一次听说 Kerberos&#xff0c;是在公司内网登录邮箱或访问内部系统时&#xff0c;看到那个带小盾牌图标的弹窗——“正在使用 Kerberos 协议进行身份验证”。于是下意识觉得&#xff1a;“哦…...

别再乱用npm install了!手把手教你用npx only-allow为项目指定包管理器(支持pnpm/yarn/npm)

用only-allow统一团队包管理器&#xff1a;从配置到CI的全流程指南 你是否曾经在拉取一个新项目后&#xff0c;面对npm install、yarn还是pnpm i的抉择感到困惑&#xff1f;或者更糟的是&#xff0c;团队成员混用不同包管理器导致node_modules结构不一致&#xff0c;引发各种诡…...

Mysql:事务管理(中)

在前面的章节中&#xff0c;我们提到了 MVCC&#xff08;多版本并发控制&#xff09;&#xff0c;它巧妙地通过“版本快照”解决了“读-写”冲突&#xff0c;实现了非阻塞读。但如果两个事务同时执行 UPDATE 操作修改同一行数据&#xff0c;即 写-写&#xff08;Write-Write&am…...

Unity渲染排序三要素:SortingLayer、Order in Layer与RenderQueue协同原理

1. 为什么刚进Unity的美术和程序总在“图层遮挡”上反复拉扯&#xff1f;“这个UI怎么被背景挡住了&#xff1f;”“粒子特效一开就穿模&#xff0c;明明Z轴没问题&#xff01;”“我调了Order in Layer到999&#xff0c;还是被另一个Sprite挡住——它连Sorting Layer都没改过&…...

如何用Python脚本榨干百度网盘带宽:pan-baidu-download终极指南

如何用Python脚本榨干百度网盘带宽&#xff1a;pan-baidu-download终极指南 【免费下载链接】pan-baidu-download 百度网盘下载脚本 项目地址: https://gitcode.com/gh_mirrors/pa/pan-baidu-download 在数字时代&#xff0c;百度网盘已成为我们存储和分享大型文件的默认…...

Claude端到端测试设计终极清单:覆盖17类非功能需求(含延迟敏感度分级、幻觉熔断阈值、多轮对话状态持久化验证)

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;Claude端到端测试设计的演进逻辑与核心范式 Claude端到端测试并非静态产物&#xff0c;而是随模型能力边界拓展、交互场景复杂化及可靠性要求升级而持续演化的工程实践。其演进逻辑根植于三个关键张力&#xf…...

猫抓浏览器扩展终极指南:5分钟掌握全网视频资源下载技巧

猫抓浏览器扩展终极指南&#xff1a;5分钟掌握全网视频资源下载技巧 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 你是否经常遇到心仪的视频无法…...

UE5 Cesium项目里,如何把默认的飞行Pawn换成建筑漫游Pawn?保姆级迁移教程

UE5 Cesium项目建筑漫游Pawn迁移实战&#xff1a;从飞行模式到精细化浏览的完整指南当你在UE5中结合Cesium插件构建数字孪生场景时&#xff0c;DynamicPawn提供的全球飞行体验令人印象深刻。但当视角聚焦到单体建筑或室内空间时&#xff0c;那种仿佛操控无人机般的操作方式就显…...

红外信号逆向工程:破解电磁炉协议实现抽油烟机智能联动

1. 项目概述&#xff1a;当电磁炉与抽油烟机“对话”厨房里的自动化&#xff0c;听起来像是未来智能家居的专属&#xff0c;但其实很多乐趣和便利就藏在身边已有的设备里。我最近给家里的厨房换上了一台新的电磁炉&#xff0c;在翻阅说明书时&#xff0c;偶然发现了一个名为“h…...

炉石传说脚本:智能游戏自动化助手的完整使用指南

炉石传说脚本&#xff1a;智能游戏自动化助手的完整使用指南 【免费下载链接】Hearthstone-Script Hearthstone script&#xff08;炉石传说脚本&#xff09; 项目地址: https://gitcode.com/gh_mirrors/he/Hearthstone-Script 还在为炉石传说重复性的日常任务感到疲惫吗…...