学习threejs,将多个网格合并成一个网格

👨‍⚕️ 主页: gis分享者
👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
👨‍⚕️ 收录于专栏:threejs gis工程师


文章目录

  • 一、🍀前言
    • 1.1 ☘️THREE.Geometry 几何体
    • 1.2 为什么将多个网格合并成一个网格
  • 二、🍀将多个网格合并成一个网格
    • 1. ☘️实现思路
    • 2. ☘️代码样例


一、🍀前言

本文详细介绍如何基于threejs在三维场景中将多个网格合并成一个网格,亲测可用。希望能帮助到您。一起学习,加油!加油!

1.1 ☘️THREE.Geometry 几何体

THREE.Geometry对原生WebGL中的顶点位置position、顶点法向量normal、顶点颜色color、顶点纹理坐标uv、顶点索引index等顶点数据进行了封装。利用 Vector3 或 Color 存储了几何体的相关 attributes(如顶点位置,面信息,颜色等)比起 BufferGeometry 更容易读写,但是运行效率不如有类型的队列。
构造函数:
Geometry() 构造函数没有任何参数。
属性:
boundingBox:Geometry 的外边界矩形,可以通过 .computeBoundingBox() 进行计算,默认值是 null。
boundingSphere:Geometry 的外边界球形,可以通过 .computeBoundingSphere() 进行计算,默认值是 null。
colors:顶点 colors 队列,与顶点数量和顺序保持一致。该属性用于 Points 、 Line 或派生自 LineSegments 的类。 对于 Meshes,请使用 Face3.vertexColors 函数。如果要标记队列中的数据已经更新,Geometry.colorsNeedUpdate 值需要被设置为 true。
faces:faces 队列。描述每个顶点之间如何组成模型面的面队列。同时该队列保存面和顶点的法向量和颜色信息。如果要标记队列中的数据已经更新,Geometry.elementsNeedUpdate 值需要被设置为 true。
faceVertexUvs:面的 UV 层的队列,该队列用于将纹理和几何信息进行映射。每个 UV 层都是一个 UV 的队列,顺序和数量同面中的顶点相对用。如果要标记队列中的数据已经更新,Geometry.uvsNeedUpdate 值需要被设置为 true。
id:当前 geometry 实例的唯一标识符的数。
isGeometry:用于判断当前类或派生类属于 Geometries。默认值是 true。不应该改变该值,该值用于内部优化。
lineDistances:用于保存线型几何体中每个顶点间距离的。在正确渲染 LineDashedMaterial 时,需要用到该数据。
morphTargets:morph targets 的队列。
morphNormals:一个 morph 法向量的数组。
name:当前几何的可选别名。默认值是一个空字符串。
skinWeights:是一个数组,用于几何体蒙皮的。
skinIndices:是一个数组,用于几何体蒙皮的。
uuid:当前对象实例的 UUID。 该值会被自动分配,请不要修改它。
vertices:vertices 的队列。顶点的队列,保存了模型中每个顶点的位置信息。如果要标记队列中的数据已经更新,.verticesNeedUpdate 值需要被设置为 true。
verticesNeedUpdate:如果顶点队列中的数据被修改,该值需要被设置为 true。
elementsNeedUpdate:如果面队列中的数据被修改,该值需要被设置为 true。
uvsNeedUpdate:如果 UV 队列中的数据被修改,该值需要被设置为 true。
normalsNeedUpdate:如果法向量队列中的数据被修改,该值需要被设置为 true。
colorsNeedUpdate:如果颜色队列或 face3 的颜色数据被修改,该值需要被设置为 true。
groupsNeedUpdate:如果 face3 的 materialIndex 被修改,该值需要被设置为 true。
lineDistancesNeedUpdate:如果 linedistances 队列中的数据被修改,该值需要被设置为 true。

1.2 为什么将多个网格合并成一个网格

当对象的数量非常庞大时,性能就会成为一个瓶颈,因为在组里每个对象还是独立的,需要分别对它们进行渲染和处理,所以数量上来以后性能就会受到很大影响。通过THREE.Geometry的merge方法合并网格,可以极大提升渲染效率。

二、🍀将多个网格合并成一个网格

1. ☘️实现思路

  • 1、初始化renderer渲染器
  • 2、初始化Scene三维场景
  • 3、初始化camera相机,定义相机位置 camera.position.set,设置相机方向camera.lookAt。
  • 4、初始化THREE.AmbientLight环境光源,scene场景加入环境光源,初始化THREE.DirectionalLight平行光源,设置平行光源位置,设置平行光源投影,scene添加平行光源。
  • 5、加载几何模型:创建THREE.AxesHelper坐标辅助工具,scene场景加入THREE.AxesHelper坐标辅助工具。
  • 6、加入gui控制,定义重绘方法redraw,redraw方法通过THREE.Geometry对象的merge方法实现立方体合并。加入controls控制,加入stats监控器,监控帧数信息。

2. ☘️代码样例

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>learn39(将多个网格合并成一个网格)</title><script src="lib/threejs/91/three.js"></script><!--<script src="lib/threejs/127/three.js-master/build/three.js"></script>--><!--<script src="lib/threejs/127/three.js-master/examples/js/controls/OrbitControls.js"></script>--><script src="https://johnson2heng.github.io/three.js-demo/lib/js/controls/OrbitControls.js"></script><script src="lib/threejs/127/three.js-master/examples/js/libs/stats.min.js"></script><!--<script src="https://johnson2heng.github.io/three.js-demo/lib/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.setSize(window.innerWidth, window.innerHeight)renderer.shadowMap.enabled = truerenderer.shadowMap.type = THREE.PCFSoftShadowMapdocument.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, 1000)camera.position.set(0, 40, 100)camera.lookAt(new THREE.Vector3(0, 0, 0))}var lightvar initLight = () => {scene.add(new THREE.AmbientLight(0x444444))light = new THREE.DirectionalLight(0xffffff)light.position.set(15, 50, 10)light.castShadow = truescene.add(light)}var cubeMaterial = new THREE.MeshLambertMaterial({color: 0x00ff00, transparent: true, opacity: 0.8})var addCube = () => {var cubeGeometry = new THREE.BoxGeometry(1, 1, 1)var cube = new THREE.Mesh(cubeGeometry, cubeMaterial)cube.castShadow = truecube.position.set(-100 + Math.round(Math.random() * 200), -100 + Math.round(Math.random() * 200), -100 + Math.round(Math.random() * 200))return cube}var guivar initGui = () => {//声明一个保存需求修改的相关数据的对象gui = {numberOfObjects: 500, //当前场景中模型的个数combined: false, //是否合并模型redraw: function () {//删除场景内现有的立方体var arr = []scene.traverse(function (e) {if (e instanceof THREE.Mesh) arr.push(e)});arr.forEach(function (value) {scene.remove(value)})//重新生成立方体if (gui.combined) {//合并模型,则使用merge方法合并var geometry = new THREE.Geometry()//merge方法将两个几何体对象或者Object3D里面的几何体对象合并,(使用对象的变换)将几何体的顶点,面,UV分别合并.//THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.for (var i = 0; i < gui.numberOfObjects; i++) {var cube = addCube()cube.updateMatrix()geometry.merge(cube.geometry, cube.matrix)}scene.add(new THREE.Mesh(geometry, cubeMaterial))}else {//不合并模型,则直接将模型放入for (var i = 0; i < gui.numberOfObjects; i++) {scene.add(addCube())}}}};var datGui = new dat.GUI()//将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值)//添加旋转功能datGui.add(gui, "numberOfObjects", 0, 50000)datGui.add(gui, "combined")datGui.add(gui, "redraw")gui.redraw()}var initModel = () => {var helper = new THREE.AxesHelper(50)scene.add(helper)}var statsvar initStats = () => {stats = new Stats()document.body.appendChild(stats.dom)}var controlsvar initControls = () => {controls = new THREE.OrbitControls(camera, renderer.domElement)controls.enableDamping = truecontrols.autoRotate = truecontrols.autoRotateSpeed = 0.5}var render = () => {renderer.render(scene, camera)}var onWindowResize = () => {camera.aspect = window.innerWidth / window.innerHeightcamera.updateProjectionMatrix()render()renderer.setSize(window.innerWidth, window.innerHeight)}var animate = () => {render()stats.update()controls.update()requestAnimationFrame(animate)}var draw = () => {initRender()initScene()initCamera()initLight()initModel()initGui()initStats()initControls()animate()window.onresize = onWindowResize}
</script>
</html>

效果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/465377.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 线程控制

一. 线程互斥 1.1 线程互斥相关概念 临界资源&#xff1a;多线程执行流共享的资源就叫做临界资源。临界区&#xff1a;每个线程内部&#xff0c;访问临界资源的代码&#xff0c;就叫做临界区。互斥&#xff1a;任何时刻&#xff0c;互斥保证有且只有一个执行流进入临界区&…

Centos安装ZooKeeper教程(单机版)

本章教程介绍,如何在Centos7中,安装ZooKeeper 3.9.3版本。 一、什么是ZooKeeper ? Apache ZooKeeper 是一个分布式协调服务,用于大型分布式系统中的管理和协调。它为分布式应用提供了一个高性能的通信框架,简化了开发人员在构建复杂分布式系统的任务。ZooKeeper 能够解决一…

企业CRM管理系统PHP源码/PHP客户关系CRM客户管理系统源码

系统功能实现 1、 公海管理:公海类型、客户公海。 2、 线索管理:我的线索、线索列表、线索状态、线索来源。 3、 客户管理:我的客户、客户列表、成交客户、行业类别、预查、地区列表、客户状态、客户级别。 4、 业绩订单:订单列表、我的订单。 5、 系统设置:系统设置…

设置JAVA以适配华为2288HV2服务器的KVM控制台

华为2288HV2服务器比较老旧了&#xff0c;其管理控制台登录java配置比较麻烦&#xff0c;华为的ibmc_kvm_client_windows客户端测试了几个版本&#xff0c;连接控制台也有问题&#xff0c;最终安装JDK解决。 一、测试环境 主机为WindowsServer2012R2,64位系统 二、Java软件包…

10大软件使用感受分享,数据恢复的得力助手!!

在找数据恢复软件&#xff1f;&#xff01;是不是存在误删重要文件或遭遇硬盘故障&#xff0c;想要找回丢失的数据&#xff1f;别担心&#xff0c;今天我就来给大家分享10款我亲自使用过的数据恢复软件&#xff0c;分别给你说说它们各自的优缺点&#xff0c;希望能帮你们在数据…

一周模电速成(3) 超详细!入门小白速成!!!

目录 稳压二极管 整流二极管 晶体三极管 三极管结构图 三极管的特点 1、如何让它工作在放大状态呢 2、如何工作在截止状态呢&#xff1f; 3、如何让三极管工作在饱和状态呢&#xff1f; 在电路中要如何实现呢&#xff1f;工作在各个状态有什么特点呢&#xff1f; 截止…

Python的条件语句if与match...case

一、定义 条件语句&#xff0c;也叫作选择语句、判断语句。根绝特定条件判断是否成立&#xff0c;执行不同的语句段。简单来说&#xff0c;满足条件执行&#xff0c;不满足不执行。 条件语句是使用关键字 if 做判断&#xff0c;根据不同情况结合不同的关键字else 或者 elif来…

SpringBoot基础系列学习(二):日志

文章目录 一丶日志控制台介绍二丶日志的用法三丶日志级别四丶配置文件参数及介绍五丶slf4j 一丶日志控制台介绍 只要引用了spring-boot-starter依赖,就无需引入日志依赖,里面自带了logging依赖,默认情况下,springBoot使用Logback来记录日志,并用INFO级别输出到控制台 二丶日…

Bert模型介绍

简介 BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;是一个基于Transformer的双向编码器表示模型&#xff0c;它通过预训练学习到了丰富的语言表示&#xff0c;并可以用于各种自然语言处理任务。 模型结构&#xff1a;BERT基于Transf…

AI驱动无人驾驶:安全与效率能否兼得?

内容概要 如今&#xff0c;人工智能正以其神奇的魔力驱动着无人驾驶的浪潮&#xff0c;带来了无数令人兴奋的可能性。这一领域的最新动态显示&#xff0c;AI技术在车辆的决策过程和实时数据分析中发挥着重要作用&#xff0c;帮助车辆更聪明地应对复杂的交通环境。通过实时监测…

Windows、Linux系统上进行CPU和内存压力测试

CPU和内存压力测试 1. Linux环境 Linux环境下&#xff0c;我们可以用 stress 工具进行内存、CPU等的压力测试。 【1】. stress工具说明 [kalamikysrv1 ~]$ stress --help stress imposes certain types of compute stress on your systemUsage: stress [OPTION [ARG]] ...-…

从零开始的c++之旅——多态

1. 多态的概念 通俗来说就是多种形态。 多态分为编译时多态&#xff08;静态多态&#xff09;和运行时多态&#xff08;动态多态&#xff09;。 编译时多态主要就是我们之前提过的函数重载和函数模板&#xff0c;同名提高传不同的参数就可以调 用不同的函数&#xff0c…

linux node vue3 部署手册

第一步&#xff1a;在linux 系统中安装node 1、在网址&#xff1a;https://nodejs.org/dist/ 下载对应版本的安装包。 2、解压缩下载的压缩包到任意位置&#xff0c;推荐home下。 样例路径为&#xff1a;/home/syl/node-v20.17.0-linux-x64.tar.xz 样例&#xff1a; tar -xv…

探索C/C++的奥秘之string类

string叫串&#xff0c;是一个管理字符数组的类&#xff0c;其实就是一个字符数组的顺序表&#xff0c;通过成员函数对字符串进行增、删、查、改。 C标准库里面的东西都在std这个命名空间中。 int main() { string s1; std:: string s2; std::string name("x…

【刷题】优选算法

优选算法 双指针 202. 快乐数 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 【思路】 第一个实例是快乐数&#xff0c;因为会变为1且不断是1的循环 第二个实例不可能为1&#xff0c;因为会陷入一个没有1的循环 根据两个实例和鸽巢原理可以发现不断的平方和最…

openEuler的aarch64操作系统上安装k3s

1、需要安装docker容器引擎&#xff08;省略&#xff09; 2、安装ks3命令 curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRRORcn INSTALL_K3S_SKIP_SELINUX_RPMtrue INSTALL_K3S_SELINUX_WARNtrue sh -s -- --docker 其中&#xff1a…

Synchronized锁、锁的四种状态、锁的升级(偏向锁,轻量级锁,重量级锁)

目录 1. Synchronized锁 1.1 介绍 1.2 三种应用方式★ 1.2.1 synchronized同步方法 1.2.2 synchronized 同步静态方法 1.2.3 synchronized 同步代码块 1.3 Synchronized锁底层原理 1.3.1 简答 1.3.2 详述 1. Monitor对象 2. Monitor与对象锁关联时 具体的流程&#…

【网络】数据链路层

目录 以太网 以太网的帧格式 MSS 交换机 MTU对UDP的影响 ARP协议 数据链路层是软件层的最底层协议&#xff0c;它的下面就是物理层&#xff0c;那么下面我们就来介绍一下它负责在网络通信中完成什么工作 我们前面说的IP协议是解决如何进行跨网络转发的&#xff0c;也就是…

零基础‘自外网到内网’渗透过程详细记录(cc123靶场)——下

细节较多&#xff0c;篇幅较大&#xff0c;分为上/下两部分发布在两篇文章内 另一部分详见下面文章 零基础‘自外网到内网’渗透过程详细记录(cc123靶场)——上https://blog.csdn.net/weixin_62808713/article/details/143572185 八、第二层数据库服务器权限获取 猜到新闻资…

13-鸿蒙开发中的综合实战:华为登录界面

大家好&#xff0c;欢迎来到鸿蒙开发系列教程&#xff01;今天&#xff0c;我们将通过一个综合实战项目来实现一个华为登录界面。这个项目将涵盖输入框组件、按钮组件、文本组件和布局容器的使用&#xff0c;帮助你更好地理解和应用这些组件。无论你是初学者还是有一定经验的开…