Редактирование сетки: вершины
Сегодня сделал, пожалуй, самый значимый для себя функционал. Мне было очень интересно сделать возможность редактирования сетки объекта. Пока реализовано только перемещение вершин по одной. На реализацию у меня ушло 2 дня, и еще больше на обдумывание и теоретическую подготовку.
Редактирование реализовано для BufferGeometry.
Сначала в места вершин расставляю маленькие сферы
addPoints(){
let points = getPoints( this.mesh );
let vertexes = getVertexes( points );
addSpheresToVertexes( this.mesh, vertexes );
}
Так как координаты вершин хранятся в буфере, представляющем собой массив значений с шагом 3: [ x1, y1, z1, x2, y2, z2 … xn, yn, zn ], нужно получить координаты точек в виде векторов
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;
}
Но точки повторяются. Например, для куба (8 вершин) — 24 точки, по 3 точки на вершину (одна точка для одной грани)
Получим массив координат вершин:
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;
}
В каждую вершину помещаем сферу
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 );
}
Редактирование геометрии я сделал статическим методом. Передаю в него объект, номер вершины, которая изменятся и её положение
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 ) );
}
Теперь нужно сделать обратную процедуру.
Находим в каких позициях массива points содержатся координаты вершин
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;
}
Меняем значение положения вершины
vertexes[ +vertexNumber ] = position;
и меняем массив points
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;
}
Который в свою очередь меняет значения в буфере объекта
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]
})
}
Изменение происходит на событие
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 );
}

Очень интересный проект. Внимательно слежу. Радует что он достаточно динамично развивается и обновляется.