学习threejs,使用JSON格式保存和加载模型
👨⚕️ 主页: gis分享者
👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
👨⚕️ 收录于专栏:threejs gis工程师
文章目录
- 一、🍀前言
- 1.1 ☘️THREE toJSON()方法
- 二、🍀使用JSON格式保存和加载模型
- 1. ☘️实现思路
- 2. ☘️代码样例
一、🍀前言
本文详细介绍如何基于threejs在三维场景中使用JSON格式保存和加载模型,亲测可用。希望能帮助到您。一起学习,加油!加油!
1.1 ☘️THREE toJSON()方法
通过调用Three.js各个对象的.toJSON()方法可以保存这些对象为json格式,比如你通过Threejs开发一个三维模型编辑系统,想保存Threejs中创建的立方体、球体、obj、glb等三维模型的顶点、材质等数据,就可以通过.toJSON()方法实现。
二、🍀使用JSON格式保存和加载模型
1. ☘️实现思路
- 1、初始化renderer渲染器
- 2、初始化Scene三维场景
- 3、初始化camera相机,定义相机位置 camera.position.set,定义相机方向lookAt。
- 4、初始化THREE.AmbientLight环境光源,scene场景加入环境光源,初始化THREE.DirectionalLight平行光源,设置平行光源位置,设置平行光源投影,scene添加平行光源。
- 5、加载几何模型:创建THREE.AxesHelper坐标辅助工具,scene场景加入THREE.AxesHelper坐标辅助工具。
- 6、加入gui控制,定义重绘方法redraw、模型保存方法save、模型加载方法load,实现细节具体看代码样例。加入controls,加入stats监控器,监控帧数信息。
2. ☘️代码样例
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>learn40(使用JSON格式保存和加载模型)</title><script src="lib/threejs/127/three.js-master/build/three.js"></script><script src="lib/threejs/127/three.js-master/examples/js/utils/SceneUtils.js"></script><script src="lib/threejs/127/three.js-master/examples/js/controls/OrbitControls.js"></script><script src="lib/threejs/127/three.js-master/examples/js/libs/stats.min.js"></script><script src="lib/threejs/127/three.js-master/examples/js/libs/dat.gui.min.js"></script>
</head>
<style>html, body {margin: 0;height: 100%;}canvas {display: block;}
</style>
<body onload="draw()">
</body>
<script>var renderervar initRender = () => {renderer = new THREE.WebGLRenderer({antialias: true})renderer.setClearColor(new THREE.Color(0x000000))renderer.setSize(window.innerWidth, window.innerHeight)document.body.appendChild(renderer.domElement)}var scenevar initScene = () => {scene = new THREE.Scene()}var cameravar initCamera = () => {camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 200)camera.position.set(-25, 40, 50)camera.lookAt(new THREE.Vector3(-25, 0, 0))}var lightvar initLight = () => {scene.add(new THREE.AmbientLight(0x404040))light = new THREE.DirectionalLight(0xffffff)light.position.set(1, 1, 1)scene.add(light)}var initModel = () => {var helper = new THREE.AxesHelper(50)scene.add(helper)}var statsvar initStats = () => {stats = new Stats()document.body.appendChild(stats.dom)}var controls, knot, loadedMeshvar initGui = () => {//声明一个保存需求修改的相关数据的对象controls = {"radius": 13,"tube": 1.7,"radialSegments": 156,"tubularSegments": 12,"p": 3,"q": 4,"heightScale": 3.5,"rotate": false,redraw: function () {// 删除掉原有的模型if (knot) scene.remove(knot)// 创建一个环形结构///<param name ="radius" type="float">环形结半径</param>///<param name ="tube" type="float">环形结弯管半径</param>///<param name ="radialSegments" type="int">环形结圆周上细分线段数</param>///<param name ="tubularSegments" type="int">环形结弯管圆周上的细分线段数</param>///<param name ="p" type="float">p\Q:对knot(节)状方式有效,控制曲线路径缠绕的圈数,P决定垂直方向的参数.</param>///<param name ="q" type="float">p\Q:对knot(节)状方式有效,控制曲线路径缠绕的圈数,Q决定水平方向的参数.</param>///<param name ="heightScale" type="float">环形结高方向上的缩放.默认值是1</param>var geom = new THREE.TorusKnotGeometry(controls.radius, controls.tube, Math.round(controls.radialSegments), Math.round(controls.tubularSegments), Math.round(controls.p), Math.round(controls.q), controls.heightScale)//判断绘制的模型knot = createMesh(geom)// 将新创建的模型添加进去scene.add(knot)},save: function () {console.log(knot)var result = knot.toJSON()localStorage.setItem("json", JSON.stringify(result))},load: function () {scene.remove(loadedMesh)var json = localStorage.getItem("json")if (json) {var loadedGeometry = JSON.parse(json)var loader = new THREE.ObjectLoader()loadedMesh = loader.parse(loadedGeometry)loadedMesh.position.x -= 50scene.add(loadedMesh)console.log(loadedMesh)}}};var gui = new dat.GUI()//将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值)gui.add(controls, 'size', 0, 10).onChange(controls.redraw);var loadFolder = gui.addFolder("保存/加载")loadFolder.add(controls, "save")loadFolder.add(controls, "load")var meshFolder = gui.addFolder("模型相关");meshFolder.add(controls, 'radius', 0, 40).onChange(controls.redraw)meshFolder.add(controls, 'tube', 0, 40).onChange(controls.redraw)meshFolder.add(controls, 'radialSegments', 0, 400).step(1).onChange(controls.redraw)meshFolder.add(controls, 'tubularSegments', 1, 20).step(1).onChange(controls.redraw)meshFolder.add(controls, 'p', 1, 10).step(1).onChange(controls.redraw)meshFolder.add(controls, 'q', 1, 15).step(1).onChange(controls.redraw)meshFolder.add(controls, 'heightScale', 0, 5).onChange(controls.redraw)meshFolder.add(controls, 'rotate')controls.redraw()}var step = 0var render = () => {if (controls.rotate) {knot.rotation.y = step += 0.01}renderer.render(scene, camera)}var generateSprite = () => {var canvas = document.createElement('canvas')canvas.width = 16canvas.height = 16var context = canvas.getContext('2d')var gradient = context.createRadialGradient(canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2)gradient.addColorStop(0, 'rgba(255,255,255,1)')gradient.addColorStop(0.2, 'rgba(0,255,255,1)')gradient.addColorStop(0.4, 'rgba(0,0,64,1)')gradient.addColorStop(1, 'rgba(0,0,0,1)')context.fillStyle = gradientcontext.fillRect(0, 0, canvas.width, canvas.height)var texture = new THREE.Texture(canvas)texture.needsUpdate = truereturn texture}var createPointCloud = () => {var material = new THREE.PointCloudMaterial({color: 0xffffff,size: 3,transparent: true,blending: THREE.AdditiveBlending,map: generateSprite(),depthTest: false})var cloud = new THREE.Points(geom, material)cloud.sortParticles = truereturn cloud}var createMesh = (geom) => {// 创建两面都显示的纹理var meshMaterial = new THREE.MeshNormalMaterial({wireframe: true})meshMaterial.side = THREE.DoubleSide// 生成模型var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial])return mesh}var onWindowResize = () => {camera.aspect = window.innerWidth / window.innerHeightcamera.updateProjectionMatrix()render()renderer.setSize(window.innerWidth, window.innerHeight)}var animate = () => {render()stats.update()requestAnimationFrame(animate)}var draw = () => {initRender()initScene()initCamera()initLight()initModel()initGui()initStats()animate()window.onresize = onWindowResize}
</script>
</html>
效果如下:
相关文章:

学习threejs,使用JSON格式保存和加载模型
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE toJSON()方法 二、&a…...
中国首部《能源法》正式问世,它的亮点有哪些呢?
2024年11月8日,《中华人民共和国能源法》经十四届全国人大常委会第十二次会议审议通过,正式出台,将于明年1月1日起施行。 中国首部《能源法》正式问世,它的亮点有哪些呢? 一、填补立法空白,完善能源法律体…...

【外包】软件行业的原始形态,项目外包与独立开发者
【外包】互联网软件行业的原始形态,项目外包与独立开发者 本科期间写的一些东西,最近整理东西看到了,大致整理一下放出来,部分内容来自其他文章,均已引用。 文章目录 1、互联网软件行业的原始形态2、项目订单ÿ…...

工程数学线性代数(同济第七版)附册课后习题答案PDF
《线性代数附册 学习辅导与习题全解》是与同济大学数学科学学院编《工程数学 线性代数》第七版教材配套的教学辅导书,由同济大学作者团队根据教材内容和要求编写而成。本书在《工程数学 线性代数》第六版附册(即辅导书)的基础上修改而成。全书…...

【Ubuntu24.04】部署服务(基础)
目录 0 背景1 设置静态IP2 连接服务器3 部署服务3.1 安装JDK3.2 下载并安装MySQL8.43.2.1 从官网下载 APT Repository 配置文件3.2.2 安装 MySQL8.43.2.3 配置远程连接 3.3 下载并配置Redis3.4 上传jar包并部署应用3.5 开放端口 4 总结 0 背景 在成功安装了Ubuntu24.04操作系统…...
Linux符号使用记录
~ 账户 home 目录,如果是 root 账户就是 /root . 当前目录 .. 上层目录 | 管道符 & 后台工作,放在完整指令列的最后端,表示将该指令列放入后台中工作。 > 输出重定向,重新…...

初阶C++之C++入门基础
大家好!欢迎来到C篇学习,这篇文章的内容不会很难,为c的引入,c的重点内容将在第二篇的文章中讲解,届时难度会陡然上升,请做好准备! 我们先看网络上的一个梗:21天内⾃学精通C 好了&am…...

ODOO学习笔记(7):模块化架构(按需安装)
一、Odoo模块化架构概述 Odoo是一个功能强大的企业资源规划(ERP)系统,其模块化架构是它的核心优势之一。这种架构允许系统通过添加、移除或修改不同的模块来灵活地适应企业的各种业务需求。 核心模块与自定义模块: Odoo本身带有一…...

Java的dto,和多表的调用
1理论 需求是新增菜品eg:菜名:豆腐脑;口味:甜口,咸口, 菜单表:dish;口味表dish_flavor; 1dto:数据传输对象 新建一个dishDto对象有两个表里的属性 2用到两个表,dish,d…...

时序数据库TimescaleDB安装部署以及常见使用
文章目录 一、时序数据库二、TimescaleDB部署1、repository yum仓库配置2、yum在线安装3、插件配置4、TimescaleDB使用登录pg创建插件使用超表 一、时序数据库 什么是时序数据库?顾名思义,用于处理按照时间变化顺序的数据的数据库即为时序数据库&#x…...

MG算法(英文版)题解
翻译: 考虑一个加法流,其中一个特定项目出现 n^(1/2) 次,并且有 n - n^(1/2) - 1 个其他不同的项目,每个项目出现一次。在应用 Misra-Gries(MG)算法时,应该选择哪个 ε(epsilon&…...
2-UML概念模型测试
1. (单选题, 1.0 分) UML中的关系不包括()。 A. 抽象B. 实现C. 依赖D. 关联 我的答案:A正确答案: A 知识点: UML的构成 1.0分 2. (单选题, 1.0 分) 下列事物不属于UML结构事物的是()。 A. 组件B. 类C. 节点D. 状…...

人工智能(AI)对于电商行业的变革和意义
 参考, x.content content --EXTRACTVALUE(x.Content, //zlxml//document//subdoc[antetypeid"3C38A8DAB01C473A9074A8EDD0B8553"]//utext) 主治医师, --EXTRACTVALUE(x.…...

RK3568平台开发系列讲解(GPIO篇)GPIO的sysfs调试手段
🚀返回专栏总目录 文章目录 一、内核配置二、GPIO sysfs节点介绍三、命令行控制GPIO3.1、sd导出GPIO3.2、设置GPIO方向3.3、GPIO输入电平读取3.4、GPIO输出电平设置四、Linux 应用控制GPIO4.1、控制输出4.2、输入检测4.3、使用 GPIO 中断沉淀、分享、成长,让自己和他人都能有…...

使用 Web Search 插件扩展 GitHub Copilot 问答
GitHub Copilot 是一个由 GitHub 和 OpenAI 合作开发的人工智能代码提示工具。它可以根据上下文提示代码,还可以回答各种技术相关的问题。但是 Copilot 本身不能回答非技术类型的问题。为了扩展 Copilot 的功能,微软发布了一个名为 Web Search 的插件&am…...

workerman的安装与使用
webman是一款基于workerman开发的高性能HTTP服务框架。webman用于替代传统的php-fpm架构,提供超高性能可扩展的HTTP服务。你可以用webman开发网站,也可以开发HTTP接口或者微服务。 除此之外,webman还支持自定义进程,可以做worker…...

QtQuick.Controls 控件介绍(都有哪些type)
这里写目录标题 主要控件 官方示例1. quickcontrols示例示例1 控制controlsSliders滑块bottom与tab 示例2 系统对话框 systemdialogs示例3 仪表盘示例4 uiforms 表格-客户通讯录 2. quickcontrols2示例1 gallery 展示2 flat Style 扁平化 帮助文档 主要控件 Button:…...
Unity导出APK加速与导出失败总结(不定时更新)
APK导出加速 1、修改配置文件: 需要修改的文件位置:编辑器安装路径/Editor/Data/PlaybackEngines/AndroidPlayer/Tools/GradleTemplates 1.1 settingsTemplate.gradle文件修改 直接附上最终效果: pluginManagement {repositories {**ART…...
域名绑定服务器小白教程
域名绑定与 Docker 容器部署指南 1. 获取云服务器公网 IP 登录云服务提供商控制台记录服务器公网 IP(例:123.456.78.90) 2. 配置域名 DNS 解析 登录域名注册商控制台添加 A 记录: 主机记录:类型:A值&am…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

VisualXML全新升级 | 新增数据库编辑功能
VisualXML是一个功能强大的网络总线设计工具,专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑(如DBC、LDF、ARXML、HEX等),并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...

对象回调初步研究
_OBJECT_TYPE结构分析 在介绍什么是对象回调前,首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例,用_OBJECT_TYPE这个结构来解析它,0x80处就是今天要介绍的回调链表,但是先不着急,先把目光…...
webpack面试题
面试题:webpack介绍和简单使用 一、webpack(模块化打包工具)1. webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖文件,使用loaders来处理它们&#x…...

网页端 js 读取发票里的二维码信息(图片和PDF格式)
起因 为了实现在报销流程中,发票不能重用的限制,发票上传后,希望能读出发票号,并记录发票号已用,下次不再可用于报销。 基于上面的需求,研究了OCR 的方式和读PDF的方式,实际是可行的ÿ…...