threejs全景图和锚点编辑的实现方案
全景图和锚点编辑
今天来简单聊聊threejs全景图和锚点编辑的方案。 全景图也就是所谓的天空盒子,所应用到的场景例如:场景模型的天空背景、夜晚的星空背景、VR看房等~
锚点编辑这篇重点讲一讲锚点编辑,也就是所谓场景编辑的方案。其中思想无限接近于Low Code,说到Low Code!我拖更了四篇文章,由于过年那段时间太忙了,实在是没时间更新!看到许多人都在等我完事,感到十分抱歉,后续一定会整理好更新!
全景图
其实全景图没什么内容。可以想象成一个非常大正方体的盒子,通过六个面的图片衔接而成。而我们相机则是存在于正方体内部,这样就能形成一个视觉误差,认为我们处于场景中。
全景图拆解
以下就是全景图正方体拆解图,六个面互相衔接,可以脑补下当将这个正方体组装后,我们所看到就是一个无缝衔接的一个场景,当然认真看还是可以看出正方体的边界处。
可以把骰子脑补成相机所在的位置,这样就很容易理解
既然有天空盒子,那多个场景的天空盒子肯定存在不同之处。在我们切换场景如何切换对应的天空盒子呢?很简单,我们只需封装一个切换函数如下
// 添加地面和天空盒 Viewer.prototype.changeSkyBox = function (skydir) { const that = this // 创建几何模型 BoxGeometry('x轴', '轴', 'z轴') const geometry = new THREE.BoxGeometry(999, 999, 999) // 创建纹理贴图 前后 上下 左右 const texture0 = new THREE.TextureLoader().load((gAppPath + `/images/ysThree/sky/${skydir}/px.jpg`)) const texture1 = new THREE.TextureLoader().load((gAppPath + `/images/ysThree/sky/${skydir}/nx.jpg`)) const texture2 = new THREE.TextureLoader().load((gAppPath + `/images/ysThree/sky/${skydir}/py.jpg`)) const texture3 = new THREE.TextureLoader().load((gAppPath + `/images/ysThree/sky/${skydir}/ny.jpg`)) const texture4 = new THREE.TextureLoader().load((gAppPath + `/images/ysThree/sky/${skydir}/pz.jpg`)) const texture5 = new THREE.TextureLoader().load((gAppPath + `/images/ysThree/sky/${skydir}/nz.jpg`)) // 添加材质 const material = [ new THREE.MeshBasicMaterial({color: 0xffddff, map: texture0, side: THREE.DoubleSide}), new THREE.MeshBasicMaterial({color: 0xffddff, map: texture1, side: THREE.DoubleSide}), new THREE.MeshBasicMaterial({color: 0xffddff, map: texture2, side: THREE.DoubleSide}), new THREE.MeshBasicMaterial({color: 0xffddff, map: texture3, side: THREE.DoubleSide}), new THREE.MeshBasicMaterial({color: 0xffddff, map: texture4, side: THREE.DoubleSide}), new THREE.MeshBasicMaterial({color: 0xffddff, map: texture5, side: THREE.DoubleSide}) ] // 创建网格对象 const cube = new _3d.Mesh(geometry, material) cube.layers.enableAll() cube.name = 'skybox' that.skybox && this.scene.remove(that.skybox) that.skybox = cube that.AmbientGroup.add(cube) }
场景编辑方案
不同场景的灯光位置以及图标点位可能不同,作为一个基础编辑平台,我们肯定要考虑如何将我们的场景变成可配置化,根据不同的需求做出不同的改变。之前的文章介绍过我们将模型通过JSON的形式去配置,那我们如何将场景中的点位以及灯光位置做出配置呢?
transformControls
变换控制器,这里它的作用主要是对锚点的平移、缩放、旋转操作
初始化控制器
//移动控制器 this.transformControls = new TransformControls(this.camera, this.renderer.domElement) this.transformControls.setSize(0.5) this.scene.add(this.transformControls) //添加入场景
添加可移动对象
我们可以在比如说灯光类中,添加一个transform_attach方法,在启用编辑后调用该方法。只有attach后才能够被拾取,进行平移、旋转、缩放的操作
transformControls.attach(...) //对象类中 transform_attach(value){ if (value) { this.transformControls.attach(this.dlight) } else { this.transformControls.detach(this.dlight) } }
平移、缩放、旋转
gapp.history.execute 这里主要是业务逻辑,将编辑后的对象保存起来,主要用于回显
SetPositionCommand 这里主要的作用是记录下旧的位置信息与新的位置信息
抛开上面两个方法,其实只要添加进变换控制器就可以对物体就行操作了,下面我单独介绍为什么需要保存信息
Viewer.prototype.bindTransformEvent = function () { this.transformControls.addEventListener('mouseDown', () => { //鼠标拾取到 var object = gapp.transformControls.object //获取拾取对象 this.objectPositionOnDown = object.position.clone()//保存位置 this.objectRotationOnDown = object.rotation.clone()//保存角度 this.objectScaleOnDown = object.scale.clone()//保存缩放大小 gapp.controls.enabled = false }) this.transformControls.addEventListener('mouseUp', () => {//鼠标提起 var object = gapp.transformControls.object//获取拾取对象 if (object !== undefined) { switch (gapp.transformControls.getMode()) { //这里判断是要进行平移、缩放、旋转操作 case 'translate': if (!this.objectPositionOnDown.equals(object.position)) { gapp.history.execute(new SetPositionCommand(this, object, object.position, this.objectPositionOnDown)) } break case 'rotate': if (!this.objectRotationOnDown.equals(object.rotation)) { gapp.history.execute(new SetRotationCommand(this, object, object.rotation, this.objectRotationOnDown)) } break case 'scale': if (!this.objectScaleOnDown.equals(object.scale)) { gapp.history.execute(new SetScaleCommand(this, object, object.scale, this.objectScaleOnDown)) } break } } gapp.controls.enabled = true }) }
保存对象
其实这里和我Low Code的思想很像,就是我们最终要将所有配置好的物体信息保存成一个JSON的形式。以便于在任意其它项目中做回显。怎么回显呢? 假如说我们现在编辑好一个灯光的位置信息以及通过gui调整好的颜色、亮度等,我们可以将该灯光object对象通过toJSON转成JSON后存储于我们最终对象中,后续通过接口取回JSON通过转化重新add到场景中即可
//转化为threejs特有的json格式 scene.toJSON() (了解过json的同学可以发现,threejs为了缩小大小,将瓦片对象最大限度的拆分材质等,通过id关联并保存为json) //解析json转为对象 Viewer.prototype.fromJSON = function (json, layeridx, isRayobj) { return new Promise((resolve, reject) => { // 解析 json 对象 let loader = new THREE.ObjectLoader(); let loadedMesh = loader.parse(json); let scene = this.mergeToMaterialsMap(loadedMesh, true) resolve(scene) }) }
结语
这篇文章主要介绍思想,相对来说这篇文章比较基础,当然后续可以根据自己的要求进行扩展
上一篇:过虑特殊字符输入的js代码
栏 目:JavaScript代码
本文标题:threejs全景图和锚点编辑的实现方案
本文地址:http://www.codeinn.net/misctech/218325.html