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 ); }