# 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

``````
// 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

}

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

}

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

}

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

}

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