Vertex Face Numbering Helper

If you want to change built-in three.js geometries or if you create geometries yourself, it is helpful to see the 3D position of the vertices and faces in their order.

When I created my addons THREEf and THREEp ( hofk (Klaus Hoffmeister) · GitHub ) I programmed and included such a help individually at that time.

Now I wanted to use built-in geometries for specific purposes, so I created a more general variant.
It works for BufferGeometry created directly with the index and position attribute.

const positionCount = mesh.geometry.attributes.position.count;
const faceCount = mesh.geometry.index.array.length / 3;

const posArray = mesh.geometry.attributes.position.array;
const indArray = mesh.geometry.index.array;

Note that in the 3D geometries edges or corners coincide and thus several vertex numbers lie on top of each other. But by the systematic arrangement you can find out the single values.

NumberingHelperExamples

see threejsResources/THREEn at master · hofk/threejsResources · GitHub



// THREEn.js  numbers helper ( vertex, face )

// uses  mesh.geometry.index.array and mesh.geometry.attributes.position.array;

/**
 * @author hofk     https://github.com/hofk
*/

import {
        BufferGeometry, BufferAttribute, Mesh, LineBasicMaterial, Line
} from '../jsm/three.module.136.js';     // original '../build/three.module.js'
    
const vertexFaceNumbersHelper = function ( camera, mesh, mode, size, color ) {
    
    // mode: 0 nothing, 1 vertex, 2 face, 3 vertex & face
    
    this.mode = mode;
    
    const positionCount = mesh.geometry.attributes.position.count;
    const faceCount = mesh.geometry.index.array.length / 3;
     
    const vertexNumbers = [];
    const faceNumbers = [];
    const materialDigits = new LineBasicMaterial( { color: color } );
    const geometryDigit = [];
    const digit = [];
    const digitPositions = [];
    let d100, d10, d1;      // digits
    
    const coordDigit = [];  // design of the digits
    coordDigit[ 0 ] = [ 0,0, 0,9, 6,9, 6,0, 0,0 ];
    coordDigit[ 1 ] = [ 0,6, 3,9, 3,0 ];
    coordDigit[ 2 ] = [ 0,9, 6,9, 6,6, 0,0, 6,0 ];
    coordDigit[ 3 ] = [ 0,9, 6,9, 6,5, 3,5, 6,5, 6,0, 0,0 ];
    coordDigit[ 4 ] = [ 0,9, 0,5, 6,5, 3,5, 3,6, 3,0 ];
    coordDigit[ 5 ] = [ 6,9, 0,9, 0,5, 6,5, 6,0, 0,0 ];
    coordDigit[ 6 ] = [ 6,9, 0,9, 0,0, 6,0, 6,5, 0,5 ];
    coordDigit[ 7 ] = [ 0,9, 6,9, 6,6, 0,0 ];
    coordDigit[ 8 ] = [ 0,0, 0,9, 6,9, 6,5, 0,5, 6,5, 6,0, 0,0 ];
    coordDigit[ 9 ] = [ 6,5, 0,5, 0,9, 6,9, 6,0, 0,0 ];
    
    for ( let i = 0; i < 10; i ++ ) {
        
        geometryDigit[ i ] = new BufferGeometry();
        
        digitPositions[ i ] =  new Float32Array( coordDigit[ i ].length / 2 * 3 );
        geometryDigit[ i ].setAttribute( 'position', new BufferAttribute( digitPositions[ i ], 3 ) );
        
        for ( let j = 0; j < coordDigit[ i ].length/ 2; j ++ ) {
            
            digitPositions[ i ][ j * 3 ] =  0.1 * size * coordDigit[ i ][ 2 * j ];
            digitPositions[ i ][ j * 3 + 1 ] = 0.1 * size * coordDigit[ i ][ 2 * j + 1 ];
            digitPositions[ i ][ j * 3 + 2 ] = 0;
            
        }
        
        digit[ i ] = new Line( geometryDigit[ i ], materialDigits );
        
    }
    
    // ......................................................
    
    const posArray = mesh.geometry.attributes.position.array;
    const indArray = mesh.geometry.index.array;
    
    let x, y, z;
    
    let i100 =  0;
    let i10  =  0;
    let i1   = -1;
    
    if ( mode === 1 || mode === 3 ) {
        
        for ( let i = 0; i < positionCount ; i ++ ) {
            
            // number on board, up to three digits are pinned there
            
            const board = new Mesh( new BufferGeometry( ) );
            
            numbering( board ); // numbering the vertices, hundreds ...
            
            vertexNumbers.push( board );    // place the table in the vertex numbering data field
            mesh.add( vertexNumbers[ i ] );
            
        }
        
        for( let n = 0; n < vertexNumbers.length; n ++ ) {
            
            const n3 = 3 * n; 
            vertexNumbers[ n ].position.set( posArray[ n3 ], posArray[ n3  + 1 ], posArray[ n3  + 2 ] );
            
        }
        
    }
    
    i100 =  0; // reset
    i10  =  0;
    i1   = -1;
    
    if ( mode === 2 || mode === 3 ) {
    
        for ( let i = 0; i < faceCount ; i ++ ) {
             
            // number on board, up to three digits are pinned there
            
            const board = new Mesh( new BufferGeometry( ) );
            
            numbering( board  ); // numbering the faces, hundreds ...
            
            faceNumbers.push( board );  // place the table in the face numbering data field
            mesh.add( faceNumbers[ i ] );    
            
        }
        
       for( let n = 0; n < faceNumbers.length; n ++ ) {
            
            const n3 = 3 * n;
            
            x = 0;
            x += posArray[ indArray[ n3 ] * 3 ];
            x += posArray[ indArray[ n3 + 1 ] * 3 ];
            x += posArray[ indArray[ n3 + 2 ] * 3 ];
            x /= 3;
            
            y = 0;
            y += posArray[ indArray[ n3 ] * 3  + 1 ];
            y += posArray[ indArray[ n3 + 1 ] * 3 + 1 ];
            y += posArray[ indArray[ n3 + 2 ] * 3 + 1 ];
            y /= 3;
            
            z = 0;
            z += posArray[ indArray[ n3 ] * 3  + 2 ];
            z += posArray[ indArray[ n3 + 1 ] * 3 + 2 ];
            z += posArray[ indArray[ n3 + 2 ] * 3 + 2 ];
            z /= 3;
            
            faceNumbers[ n ].position.set( x, y, z );
            
        }
        
    }
    
    function numbering( board ) {
        
        i1 ++;                                                      // starts with  -1 + 1 = 0
        
        if ( i1   === 10 ) { i1   = 0; i10 ++ }
        if ( i10  === 10 ) { i10  = 0; i100 ++ }
        if ( i100 === 10 ) { i100 = 0 }                             // hundreds (reset when overflow)
        
        if ( i100 > 0 ) {
            
            d100 = digit[ i100 ].clone();                           // digit for hundreds
            board.add( d100 );                                      //  on the board ...
            d100.position.x = -8 * 0.1 * size;                      // ... move slightly to the left
            
        }
        
        if ( ( i100 > 0 ) || ( ( i100 === 0 ) && ( i10 > 0 ) ) ) {  // no preceding zeros tens
            
            d10 = digit[ i10 ].clone();                             // digit for tenth
            board.add( d10 );                                       //  on the board
            
        }
        
        d1 =   digit[ i1 ].clone();                                 // digit 
        board.add( d1 );                                            //  on the board ...
        d1.position.x = 8 * 0.1 * size;                             // ... move slightly to the right
        
    }
    
    this.update = function ( ) {
        
        if ( this.mode === 1 || this.mode === 3 ) {
            
            for( let n = 0; n < vertexNumbers.length; n ++ ) {
                
                vertexNumbers[ n ].lookAt( camera.position );
                
            }
            
        }
        
        if ( this.mode === 2 || this.mode === 3 ) {
            
            for( let n = 0; n < faceNumbers.length; n ++ ) {
                
                faceNumbers[ n ].lookAt( camera.position );
                
            }
            
        }
        
    }
     
    this.update( ); // update helper
    
};

export{ vertexFaceNumbersHelper };



UPDATE:

After a hint, I took a closer look at the board numbering algorithm.

I simply copied it from my template. At that time I was new to three.js and had also hardly used javascript.

You can use .toString( ) and get the single digits that way. However, the code doesn’t get much shorter overall, since you have a few more lines in the case distinction than before.

But the comparison is already interesting.

The example is now based on the new version with function numbering( board, i ) :


// THREEn.js  numbers helper ( vertex, face )

// uses  mesh.geometry.index.array and mesh.geometry.attributes.position.array;

/**
 * @author hofk     https://github.com/hofk
*/

import {
        BufferGeometry, BufferAttribute, Mesh, LineBasicMaterial, Line
} from '../jsm/three.module.136.js';     // original '../build/three.module.js'
    
const vertexFaceNumbersHelper = function ( camera, mesh, mode, size, color ) {
    
    // mode: 0 nothing, 1 vertex, 2 face, 3 vertex & face
    
    this.mode = mode;
    
    const positionCount = mesh.geometry.attributes.position.count;
    const faceCount = mesh.geometry.index.array.length / 3;
     
    const vertexNumbers = [];
    const faceNumbers = [];
    const materialDigits = new LineBasicMaterial( { color: color } );
    const geometryDigit = [];
    const digit = [];
    const digitPositions = [];
    let d100, d10, d1;      // digits
    
    const coordDigit = [];  // design of the digits
    coordDigit[ 0 ] = [ 0,0, 0,9, 6,9, 6,0, 0,0 ];
    coordDigit[ 1 ] = [ 0,6, 3,9, 3,0 ];
    coordDigit[ 2 ] = [ 0,9, 6,9, 6,6, 0,0, 6,0 ];
    coordDigit[ 3 ] = [ 0,9, 6,9, 6,5, 3,5, 6,5, 6,0, 0,0 ];
    coordDigit[ 4 ] = [ 0,9, 0,5, 6,5, 3,5, 3,6, 3,0 ];
    coordDigit[ 5 ] = [ 6,9, 0,9, 0,5, 6,5, 6,0, 0,0 ];
    coordDigit[ 6 ] = [ 6,9, 0,9, 0,0, 6,0, 6,5, 0,5 ];
    coordDigit[ 7 ] = [ 0,9, 6,9, 6,6, 0,0 ];
    coordDigit[ 8 ] = [ 0,0, 0,9, 6,9, 6,5, 0,5, 6,5, 6,0, 0,0 ];
    coordDigit[ 9 ] = [ 6,5, 0,5, 0,9, 6,9, 6,0, 0,0 ];
    
    for ( let i = 0; i < 10; i ++ ) {
        
        geometryDigit[ i ] = new BufferGeometry();
        
        digitPositions[ i ] =  new Float32Array( coordDigit[ i ].length / 2 * 3 );
        geometryDigit[ i ].setAttribute( 'position', new BufferAttribute( digitPositions[ i ], 3 ) );
        
        for ( let j = 0; j < coordDigit[ i ].length/ 2; j ++ ) {
            
            digitPositions[ i ][ j * 3 ] =  0.1 * size * coordDigit[ i ][ 2 * j ];
            digitPositions[ i ][ j * 3 + 1 ] = 0.1 * size * coordDigit[ i ][ 2 * j + 1 ];
            digitPositions[ i ][ j * 3 + 2 ] = 0;
            
        }
        
        digit[ i ] = new Line( geometryDigit[ i ], materialDigits );
        
    }
    
    // ......................................................   
    
    const posArray = mesh.geometry.attributes.position.array;
    const indArray = mesh.geometry.index.array;
    
    let x, y, z;

    if ( mode === 1 || mode === 3 ) {
        
        for ( let i = 0; i < positionCount ; i ++ ) {
            
            // number on board, up to three digits are pinned there
            
            const board = new Mesh( new BufferGeometry( ) );
            
            numbering( board, i ); // numbering the vertices, hundreds ...
            
            vertexNumbers.push( board );    // place the table in the vertex numbering data field
            mesh.add( vertexNumbers[ i ] );
            
        }
        
        for( let n = 0; n < vertexNumbers.length; n ++ ) {
            
            const n3 = 3 * n; 
            vertexNumbers[ n ].position.set( posArray[ n3 ], posArray[ n3  + 1 ], posArray[ n3  + 2 ] );
            
        }
        
    }
    
    if ( mode === 2 || mode === 3 ) {
    
        for ( let i = 0; i < faceCount ; i ++ ) {
             
            // number on board, up to three digits are pinned there
            
            const board = new Mesh( new BufferGeometry( ) );
            
            numbering( board, i  ); // numbering the faces, hundreds ...
            
            faceNumbers.push( board );  // place the table in the face numbering data field
            mesh.add( faceNumbers[ i ] );    
            
        }
        
       for ( let n = 0; n < faceNumbers.length; n ++ ) {
            
            const n3 = 3 * n;
            
            x = 0;
            x += posArray[ indArray[ n3 ] * 3 ];
            x += posArray[ indArray[ n3 + 1 ] * 3 ];
            x += posArray[ indArray[ n3 + 2 ] * 3 ];
            x /= 3;
            
            y = 0;
            y += posArray[ indArray[ n3 ] * 3  + 1 ];
            y += posArray[ indArray[ n3 + 1 ] * 3 + 1 ];
            y += posArray[ indArray[ n3 + 2 ] * 3 + 1 ];
            y /= 3;
            
            z = 0;
            z += posArray[ indArray[ n3 ] * 3  + 2 ];
            z += posArray[ indArray[ n3 + 1 ] * 3 + 2 ];
            z += posArray[ indArray[ n3 + 2 ] * 3 + 2 ];
            z /= 3;
            
            faceNumbers[ n ].position.set( x, y, z );
            
        }
        
    }
    
    function numbering( board, i ) { 
        
        const d = i.toString( ); 
        const n = d.length;
   
        if ( n === 3 ) {
        
            d100 = digit[ d[ 0 ] ].clone( );                      // digit for hundreds
            board.add( d100 );                                      //  on the board ...
            d100.position.x = -8 * 0.1 * size;                      // ... move slightly to the left
            
            d10 = digit[ d[ 1 ] ].clone( );                       // digit for tenth
            board.add( d10 );                                       //  on the board
            
            d1 = digit[ d[ 2 ] ].clone( );                       // digit 
            board.add( d1 );                                        //  on the board ...
            
        } else if (  n === 2 ) {
            
            d10 = digit[ d[ 0 ] ].clone( );                       // digit for tenth
            board.add( d10 );                                       //  on the board
            
            d1 = digit[ d[ 1 ] ].clone( );                        // digit 
            board.add( d1 );                                        //  on the board ...
            
        } else if (  n === 1 ) {
        
            d1 = digit[ d[ 0 ] ].clone( );                        // digit 
            board.add( d1 );                                        //  on the board ...
            
        }
        
        d1.position.x = 8 * 0.1 * size;                         // ... move slightly to the right
        
    }
    
    this.update = function ( ) {
        
        if ( this.mode === 1 || this.mode === 3 ) {
            
            for( let n = 0; n < vertexNumbers.length; n ++ ) {
                
                vertexNumbers[ n ].lookAt( camera.position );
                
            }
            
        }
        
        if ( this.mode === 2 || this.mode === 3 ) {
            
            for( let n = 0; n < faceNumbers.length; n ++ ) {
                
                faceNumbers[ n ].lookAt( camera.position );
                
            }
            
        }
        
    }
     
    this.update( ); // update helper
    
};

export{ vertexFaceNumbersHelper };
6 Likes