Редактирование сетки: вершины

3+

Сегодня сделал, пожалуй, самый значимый для себя функционал. Мне было очень интересно сделать возможность редактирования сетки объекта. Пока реализовано только перемещение вершин по одной. На реализацию у меня ушло 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 );

                }

3+