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

👨‍⚕️ 主页: gis分享者

👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍⚕️ 收录于专栏:threejs gis工程师


文章目录

  • 一、🍀前言
    • [1.1 ☘️THREE.Geometry 几何体](#1.1 ☘️THREE.Geometry 几何体)
    • [1.2 为什么将多个网格合并成一个网格](#1.2 为什么将多个网格合并成一个网格)
  • 二、🍀将多个网格合并成一个网格
    • [1. ☘️实现思路](#1. ☘️实现思路)
    • [2. ☘️代码样例](#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. ☘️代码样例

html 复制代码
<!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 renderer
  var initRender = () => {
    renderer = new THREE.WebGLRenderer({antialias: true})
    renderer.setSize(window.innerWidth, window.innerHeight)
    renderer.shadowMap.enabled = true
    renderer.shadowMap.type = THREE.PCFSoftShadowMap
    document.body.appendChild(renderer.domElement)
  }
  var scene
  var initScene = () => {
    scene = new THREE.Scene()
  }
  var camera
  var 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 light
  var initLight = () => {
    scene.add(new THREE.AmbientLight(0x444444))

    light = new THREE.DirectionalLight(0xffffff)
    light.position.set(15, 50, 10)
    light.castShadow = true
    scene.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 = true
    cube.position.set(-100 + Math.round(Math.random() * 200), -100 + Math.round(Math.random() * 200), -100 + Math.round(Math.random() * 200))
    return cube
  }
  var gui
  var 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 stats
  var initStats = () => {
    stats = new Stats()
    document.body.appendChild(stats.dom)
  }
  var controls
  var initControls = () => {
    controls = new THREE.OrbitControls(camera, renderer.domElement)
    controls.enableDamping = true
    controls.autoRotate = true
    controls.autoRotateSpeed = 0.5
  }
  var render = () => {
    renderer.render(scene, camera)
  }
  var onWindowResize = () => {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.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>

效果如下:

相关推荐
gis分享者2 天前
学习threejs,使用PointLight点光源
threejs·点光源·pointlight
gis分享者6 天前
学习threejs,使用HemisphereLight半球光
threejs·hemispherelight·半球光
gis分享者10 天前
学习threejs,使用Lensflare模拟镜头眩光
threejs·lensflare·眩光
gis分享者13 天前
学习threejs,tga格式图片文件贴图
threejs·贴图·tga·tgaloader
gis分享者14 天前
学习threejs,pvr格式图片文件贴图
threejs·贴图·pvr
gis分享者1 个月前
学习threejs,使用OrbitControls相机控制器
threejs·相机·相机控制器·orbitcontrols
不系舟1781 个月前
threejs 实现镜面反射,只反射指定物体,背景透明
threejs
gis分享者1 个月前
学习threejs,使用RollControls相机控制器
threejs·相机控制器·rollcontrols
gis分享者1 个月前
学习threejs,使用FlyControls相机控制器
threejs·相机控制器·flycontrols
gis分享者1 个月前
学习threejs,使用TrackballControls相机控制器
threejs·trackball·相机控制器