模型拖拽
由于导入的obj文件模型导入后生成的是一个group对象,而dragControls插件无法绑定在group对象,所以进行以下尝试:
解决导入模型无法拖拽尝试1
原理:将group对象下的所有网格模型mesh合并进一个新建的几何对象geometry,然后创建一个新的mesh,然后绑定拖拽事件;
缺点:模型可能只有单一的颜色,会失去模型文件中所有的材质信息;而且合并后的网格模型将因为有不可计的顶点,所以无法在合并后自己进行贴图;
let objLoader = new THREE.OBJLoader();
objLoader.load('assets/objs/室内/书桌.obj', function (obj) {
// 控制台查看返回结构:包含一个网格模型Mesh的组Group
console.log('---', obj);
// 查看加载器生成的材质对象:MeshPhongMaterial
console.log('===', obj.children[0].material);
obj.position.y = 0;
obj.rotation.y = 0.5;
obj.scale.set(1, 1, 1);
// scene.add(obj);
let geometry = new THREE.Geometry()
for (let i = 0; i < obj.children.length; i++) {
let item = new THREE.Geometry().fromBufferGeometry(obj.children[i].geometry)
geometry.merge(item, obj.children[i].matrix);
}
let material = new THREE.MeshLambertMaterial({
}); //材质对象Material
let mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
console.log('合并====', mesh.geometry.faceVertexUvs)
scene.add(mesh); //网格模型添加到场景中
objects.push(mesh)
})
解决导入模型无法拖拽尝试2
原理:经过尝试发现,dragControls对象只能接收mesh,但是在与平移控件绑定时可以绑定group,并且group与mesh可以通过parent、children属性进行相互查看;所以在new dragControls时先使用group中的某一个mesh进行创建,在后续将移动控件与当前选中对象绑定的操作中mesh通过parent属性找到其group进行绑定;
缺点:只有在鼠标略过以在new dragControls时绑定的mesh才会进行绑定操作,需要人为找到模型中体积较大的mesh,否则唤起拖拽会比较困难;
function initControls() {
controls = new THREE.OrbitControls(camera, renderer.domElement);//创建控件对象
controls.addEventListener('change', render);//监听鼠标、键盘事件
console.log('------', controls)
// 初始化拖拽控件
console.log('objects', objects)
dragControls = new THREE.DragControls(objects, camera, renderer.domElement);
transformControls = new THREE.TransformControls(camera, renderer.domElement);
scene.add(transformControls);
// 鼠标略过事件
dragControls.addEventListener('hoveron', function (event) {
// 让变换控件对象和选中的mesh与其group绑定
console.log('===', event)
transformControls.attach( event.object.parent);
});
// 开始拖拽
dragControls.addEventListener('dragstart', function (event) {
controls.enabled = false;
});
// 拖拽结束
dragControls.addEventListener('dragend', function (event) {
controls.enabled = true;
});
}
产生的问题:由于绑定的mesh与TransformControls控件并不重合,而dragControls控件可以不通过TransformControls控件的坐标系,直接通过拖拽mesh进行移动,导致当前用于绑定的mesh与group分离,通过取消dragControls源码中的拖拽方法onDocumentMouseDown解决;
解决导入模型无法拖拽尝试3(正在使用)
原理:创建模型,跟导入的模型设置相同的位置和大小,在创建dragControls对象时绑定创建的模型;
缺点:场景内的模型数量会大大增加,可能导致性能问题;
function addServer(list) {
return new Promise((resolve, reject) => {
let mtlLoader = new THREE.MTLLoader();
let objLoader = new THREE.OBJLoader();
mtlLoader.setPath('./ThreeJs/objs/test/');
mtlLoader.load('server2.mtl', function (materials) {
materials.preload();
let objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath('./ThreeJs/objs/test/');
objLoader.load('server2.obj', function (object) {
object.scale.set(0.3, 0.5, 0.3);
let {x, y, z} = getObjectSize(object)
list.forEach((item) => {
let { rotation, name } = item
let pX = item.x
let pY = item.y
let pZ = item.z
let obj = object.clone()
let material = new THREE.MeshBasicMaterial({
color: 0xfff,
transparent: true,
opacity: 0
});
let big = returnObject(x, y, z, rotation, material, pX, pY, pZ);
big.name = 'test$1'
scene.add(big)
obj.position.x = pX;
obj.position.y = pY;
obj.position.z = pZ;
obj.rotation.y = rotation;
obj.name = name
obj.siblingComponent = big
big.siblingComponent = obj
scene.add(obj);
})
resolve('addServer')
});
});
})
}
function returnObject(width, height, depth, angle, material, x, y, z) {
var cubeGeometry = new THREE.BoxGeometry(width, height, depth);
var cube = new THREE.Mesh(cubeGeometry, material);
cube.position.x = x;
cube.position.y = y;
cube.position.z = z;
cube.rotation.y = angle;
return cube;
}
修改dragControls的监听事件,在拖动模型的同时改变导入的模型的位置
dragControls.addEventListener('drag', function (event) {
let obj = event.object
const { x, y, z } = obj.position
if (obj.siblingComponent !== undefined && obj.siblingComponent !== null && obj.siblingComponent !== '') {
// console.log('test')
obj.siblingComponent.position.set(x, y, z);
}
});