Mesh editing: Vertices
Today has made, perhaps, the most significant functional for me. I was very interested in making the ability to edit the mesh of the object. So far, only moving vertices one at a time has been implemented. It took me 2 days to implement, and even more to ponder and theoretical preparation.
Editing is implemented for BufferGeometry.
First, I place small spheres to the vertices positions:
addPoints(){
let points = getPoints( this.mesh );
let vertexes = getVertexes( points );
addSpheresToVertexes( this.mesh, vertexes );
}
Since the coordinates of the vertices are stored in a buffer, which is an array of values in increments of 3: [x1, y1, z1, x2, y2, z2 … xn, yn, zn], we need to get the coordinates of the points in the form of vectors
function getPoints( mesh ) {
let pointsArray = mesh.geometry.attributes.position.array;
let itemSize = mesh.geometry.attributes.position.itemSize;
let points = [];
for (let i = 0; i < pointsArray.length; i += itemSize ) {
points.push( new Vector3( pointsArray[i], pointsArray[i+1], pointsArray[i+2]));
}
return points;
}
But the points are repeated. For example, for a cube (8 vertices) – 24 points, 3 points per vertex (one point for one face)
We get an array of vertex coordinates:
function getVertexes( points ) {
let vertexes = [];
points.forEach( ( indexPoints ) => {
let equal = false;
vertexes.forEach( ( indexVertex ) => {
if (indexPoints.equals( indexVertex) ){
equal = true;
return;
}
})
if ( !equal ) {
vertexes.push( indexPoints );
}
})
return vertexes;
}
At each vertex we put a sphere
function addSpheresToVertexes( mesh, vertexes ){
let ta_Scene = new TA_Scene();
let sphereGeometry = new SphereBufferGeometry( 0.3, 4, 4 );
ta_Scene.tempSelectableObjects = ta_Scene.tempSelectableObjects.concat( ta_Scene.selectableObjects );
ta_Scene.selectableObjects = [];
let group = new Group();
group.name = 'shperesForMeshEdit';
vertexes.map( (item, index) => {
let sphere = new Mesh( sphereGeometry, new MeshBasicMaterial( { color: new Color( 'red' ) } ) );
sphere.name = 'editMeshHelper'
sphere.userData.vertexNumer = `${index}` ;
group.add( sphere );
sphere.position.set( item.x, item.y, item.z);
ta_Scene.selectableObjects.push( sphere );
})
mesh.add( group );
}
I did the editing of the geometry using the static method. I pass in it an object, the number of the vertex, which will change and its position
static changeGeometry( object, vertexNumber, position ){
let ta_Entities = new TA_Entities();
let points = getPoints( object );
let vertexes = getVertexes( points );
let VertexesPointsIndexes = getVertexesPointsIndexes( points, vertexes);
ta_Entities.removeWireframeAndBoundingBox(object );
vertexes[ +vertexNumber ] = position;
let newPoints = vertexesChangePoints ( vertexes, points, VertexesPointsIndexes);
pointsChangeAttributesPosition( object, newPoints );
object.geometry.attributes.position.needsUpdate = true;
object.updateMatrix();
// object.add( ta_Entities.createBoundingBox( object ) );
object.add( ta_Entities.createWireframe( object ) );
}
Now we need to do the reverse procedure.
We find in what positions of the points array the coordinates of the vertices are contained
function getVertexesPointsIndexes( points, vertexes){
let indexesArray = [];
vertexes.map ( (itemVertex ) => {
let indexes = [];
points.forEach( (itemPoints, index) => {
if( itemPoints.equals( itemVertex ) )
indexes.push( index );
})
indexesArray.push( indexes );
})
return indexesArray;
}
Change the value of the vertex position
vertexes[ +vertexNumber ] = position;
and change the points array
function vertexesChangePoints ( vertexes, points, VertexesPointsIndexes) {
// let newPoints = points;
vertexes.map( ( itemVertex, index ) => {
let arrayIndexes = VertexesPointsIndexes[ index ];
arrayIndexes.map( ( item ) => points[ item ] = itemVertex);
})
points[0] = vertexes[0];
return points;
}
Which in turn changes the values in the object buffer
function pointsChangeAttributesPosition( mesh, points ) {
let positions = [];
points.map( (item) => {
positions.push( item.x);
positions.push( item.y);
positions.push( item.z);
} )
let arrayAttr = mesh.geometry.attributes.position.array;
arrayAttr.map( (item, index) => {
mesh.geometry.attributes.position.array[index] = positions[index]
})
}
Change occurs on an event
this.transformControls.addEventListener( 'objectChange', function( event ) {
if( event.target.mode === 'translate' ){
if ( scope.mode.action === 'meshEdit' ){
let vertexNumber = event.target.object.userData.vertexNumer;
let position = event.target.object.position;
let object = event.target.object.parent.parent;
MeshEdit.changeGeometry( object, +vertexNumber, position );
}
