Select multiple objects, clone


Implemented the selection of several objects. In this case, the center of selection is set in the geometric center of mass, the so-called barycenter, which is defined as follows

The barycenter is determined by the addition of the position vectors of the points included in the group and is divided by the number of points.

function findBaryCenter( points) {

            if ( !Array.isArray( points) ) return null;

            let pointsCount = points.length;

            let resultVector = points.reduce( (sum, current) => sum.add(current) );
            let baryCenter = resultVector.divideScalar( pointsCount );

            return baryCenter;


To implement multiple selection, a group was created in the currentselection object and the moment of scene initialization was added to the scene

this.currentSelection = {
	object: null,
	objectOwnColor: null,
	multiselection: new Group()
scene.add( this.currentSelection.multiselection );

To initialize multiple selection, hold down the Ctrl key.

First, check if any object is selected. If selected, then add it to the multiselection group.

if ( event.ctrlKey ){

        if ( scope.currentSelection.object ) {

	taEntities.removeWireframeAndBoundingBox( scope.currentSelection.object );
	scope.currentSelection.multiselection.attach( scope.currentSelection.object );
	scope.currentSelection.object = null;


We create an array of objects included in the multiselection group and check if there is a selected object in this group. If not, then add it to the group, if so, then remove it from the selection:

let arrayObjectsInSelection = [];

arrayObjectsInSelection = arrayObjectsInSelection.concat( scope.currentSelection.multiselection.children );

if ( arrayObjectsInSelection.includes( objectToSelect )) {

	taEntities.removeWireframeAndBoundingBox( objectToSelect );

	arrayObjectsInSelection.splice( arrayObjectsInSelection.indexOf( objectToSelect), 1 );

else {

	arrayObjectsInSelection.push( objectToSelect );


We return all the objects from the group to the scene in order to establish the new position of the group by moving it to the geometric center of mass. To do this, determine the position of all objects selection


let centerPoints = [];

arrayObjectsInSelection.forEach( element => {

      centerPoints.push( element.position.clone() )


let baryCenter = findBaryCenter( centerPoints ).clone();

scope.currentSelection.multiselection.position.set( baryCenter.x, baryCenter.y, baryCenter.z);

We return all objects from the scene to the group

for (let i = arrayObjectsInSelection.length - 1; i >= 0; i--) {

	scope.currentSelection.multiselection.attach( arrayObjectsInSelection[i] );

	arrayObjectsInSelection[i].add( taEntities.createBoundingBox( arrayObjectsInSelection[i] ) );

We use the .attach method, which, unlike .add, adds objects to the group as a child of this, while maintaining the object’s world transform. That is, if the object has coordinates (0, 0, 0), and the group has (10, 10, 10), then .add will add to the placement point of the group, that is, at (10, 10, 10), and .attach will leave the object is at the point (0, 0, 0), but for the group in the local coordinates of the group it will be in with coordinates (-10, -10, -10).

The function of returning objects to the scene and resetting the multyselection is as follows

this.returnObjectsToScene = function(){
	if (scope.currentSelection.multiselection.children.length > 0 ){

		let lengthArray = scope.currentSelection.multiselection.children.length;

		for (let i = lengthArray - 1; i >= 0; i--) {

			taEntities.removeWireframeAndBoundingBox( scope.currentSelection.multiselection.children[i] );

			scene.attach( scope.currentSelection.multiselection.children[i] )


     scope.transformControls.detach( scope.currentSelection.multiselection )

this.resetMultyselection = function() {

	scope.currentSelection.multiselection.children = [];
	scope.currentSelection.multiselection.position.set( 0, 0, 0);
	scope.currentSelection.multiselection.scale.set( 1, 1, 1);
	scope.currentSelection.multiselection.rotation.set( 0, 0, 0);


Cloning multiple selected objects. You can clone with the “c” key or the Edit menu item

if ( ta_scene.currentSelection.multiselection.children.length > 0 ){

	let lengthArray = ta_scene.currentSelection.multiselection.children.length;

	let multuSelectionArray = ta_scene.currentSelection.multiselection.children;

	for (let i = lengthArray - 1; i >= 0; i--) {

		this.removeWireframeAndBoundingBox( multuSelectionArray[i] );

		let id = multuSelectionArray[i].id;

		let copiedObject = ta_scene.scene.getObjectById( id );

		ta_scene.scene.attach( multuSelectionArray[i]);

		let newObject = copiedObject.clone();

		ta_scene.scene.add( newObject );

		ta_scene.selectableObjects.push( newObject );

		ta_scene.currentSelection.multiselection.attach( copiedObject );

		copiedObject.add( this.createBoundingBox( copiedObject ) );



There was a problem that I described on the three.js forum.

I changed the transformation buttons to radio so that it was clear which mode is currently on. The Drag button was made by a checkbox, now the drag mode can work in parallel with other transformation modes. At the same time, the problem that I described in the issue in the GitHub repository three.js was revealed.

Switching the transformation modes is possible with the keys “m” – move, “r” – rotate, “s” – scale, “d” – drag.

Spent three days studying Webpack, set up the project, now it is going to WebPack.