Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Weld vertices using only position attribute. #77

Merged
merged 1 commit into from
Apr 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/Builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ class Builder {
/**
* Constructs groups from the given navigation mesh.
* @param {BufferGeometry} geometry
* @param {number} tolerance
* @return {Zone}
*/
static buildZone (geometry) {
static buildZone (geometry, tolerance) {

const navMesh = this._buildNavigationMesh(geometry);
const navMesh = this._buildNavigationMesh(geometry, tolerance);

const zone = {};

Expand Down Expand Up @@ -72,8 +73,8 @@ class Builder {
* @param {BufferGeometry} geometry
* @return {Object}
*/
static _buildNavigationMesh (geometry) {
geometry = Utils.mergeVertices(geometry);
static _buildNavigationMesh (geometry, tolerance) {
geometry = Utils.mergeVertices(geometry, tolerance);
return this._buildPolygonsFromGeometry(geometry);
}

Expand Down
5 changes: 3 additions & 2 deletions src/Pathfinding.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ class Pathfinding {
/**
* (Static) Builds a zone/node set from navigation mesh geometry.
* @param {BufferGeometry} geometry
* @param {number} tolerance Vertex welding tolerance.
* @return {Zone}
*/
static createZone (geometry) {
return Builder.buildZone(geometry);
static createZone (geometry, tolerance = 1e-4) {
return Builder.buildZone(geometry, tolerance);
}

/**
Expand Down
123 changes: 24 additions & 99 deletions src/Utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BufferAttribute } from 'three';
import { BufferAttribute, BufferGeometry } from 'three';

class Utils {

Expand Down Expand Up @@ -65,8 +65,8 @@ class Utils {
}

/**
* Copied from BufferGeometryUtils.mergeVertices, because importing ES modules
* from a sub-directory makes Node.js (as of v14) angry.
* Modified version of BufferGeometryUtils.mergeVertices, ignoring vertex
* attributes other than position.
*
* @param {THREE.BufferGeometry} geometry
* @param {number} tolerance
Expand All @@ -83,92 +83,39 @@ class Utils {
var positions = geometry.getAttribute( 'position' );
var vertexCount = indices ? indices.count : positions.count;

// next value for triangle indices
// Next value for triangle indices.
var nextIndex = 0;

// attributes and new attribute arrays
var attributeNames = Object.keys( geometry.attributes );
var attrArrays = {};
var morphAttrsArrays = {};
var newIndices = [];
var getters = [ 'getX', 'getY', 'getZ', 'getW' ];
var newPositions = [];

// initialize the arrays
for ( var i = 0, l = attributeNames.length; i < l; i ++ ) {

var name = attributeNames[ i ];

attrArrays[ name ] = [];

var morphAttr = geometry.morphAttributes[ name ];
if ( morphAttr ) {

morphAttrsArrays[ name ] = new Array( morphAttr.length ).fill().map( () => [] );

}

}

// convert the error tolerance to an amount of decimal places to truncate to
// Convert the error tolerance to an amount of decimal places to truncate to.
var decimalShift = Math.log10( 1 / tolerance );
var shiftMultiplier = Math.pow( 10, decimalShift );

for ( var i = 0; i < vertexCount; i ++ ) {

var index = indices ? indices.getX( i ) : i;

// Generate a hash for the vertex attributes at the current index 'i'
// Generate a hash for the vertex attributes at the current index 'i'.
var hash = '';
for ( var j = 0, l = attributeNames.length; j < l; j ++ ) {

var name = attributeNames[ j ];
var attribute = geometry.getAttribute( name );
var itemSize = attribute.itemSize;

for ( var k = 0; k < itemSize; k ++ ) {

// double tilde truncates the decimal value
hash += `${ ~ ~ ( attribute[ getters[ k ] ]( index ) * shiftMultiplier ) },`;

}

}
// Double tilde truncates the decimal value.
hash += `${ ~ ~ ( positions.getX( index ) * shiftMultiplier ) },`;
hash += `${ ~ ~ ( positions.getY( index ) * shiftMultiplier ) },`;
hash += `${ ~ ~ ( positions.getZ( index ) * shiftMultiplier ) },`;

// Add another reference to the vertex if it's already
// used by another index
// used by another index.
if ( hash in hashToIndex ) {

newIndices.push( hashToIndex[ hash ] );

} else {

// copy data to the new index in the attribute arrays
for ( var j = 0, l = attributeNames.length; j < l; j ++ ) {

var name = attributeNames[ j ];
var attribute = geometry.getAttribute( name );
var morphAttr = geometry.morphAttributes[ name ];
var itemSize = attribute.itemSize;
var newarray = attrArrays[ name ];
var newMorphArrays = morphAttrsArrays[ name ];

for ( var k = 0; k < itemSize; k ++ ) {

var getterFunc = getters[ k ];
newarray.push( attribute[ getterFunc ]( index ) );

if ( morphAttr ) {

for ( var m = 0, ml = morphAttr.length; m < ml; m ++ ) {

newMorphArrays[ m ].push( morphAttr[ m ][ getterFunc ]( index ) );

}

}

}

}
newPositions.push( positions.getX( index ) );
newPositions.push( positions.getY( index ) );
newPositions.push( positions.getZ( index ) );

hashToIndex[ hash ] = nextIndex;
newIndices.push( nextIndex );
Expand All @@ -178,38 +125,16 @@ class Utils {

}

// Generate typed arrays from new attribute arrays and update
// the attributeBuffers
const result = geometry.clone();
for ( var i = 0, l = attributeNames.length; i < l; i ++ ) {

var name = attributeNames[ i ];
var oldAttribute = geometry.getAttribute( name );

var buffer = new oldAttribute.array.constructor( attrArrays[ name ] );
var attribute = new BufferAttribute( buffer, oldAttribute.itemSize, oldAttribute.normalized );

result.setAttribute( name, attribute );

// Update the attribute arrays
if ( name in morphAttrsArrays ) {

for ( var j = 0; j < morphAttrsArrays[ name ].length; j ++ ) {

var oldMorphAttribute = geometry.morphAttributes[ name ][ j ];

var buffer = new oldMorphAttribute.array.constructor( morphAttrsArrays[ name ][ j ] );
var morphAttribute = new BufferAttribute( buffer, oldMorphAttribute.itemSize, oldMorphAttribute.normalized );
result.morphAttributes[ name ][ j ] = morphAttribute;

}

}

}
// Construct merged BufferGeometry.

// indices
const positionAttribute = new BufferAttribute(
new Float32Array( newPositions ),
positions.itemSize,
positions.normalized
);

const result = new BufferGeometry();
result.setAttribute( 'position', positionAttribute );
result.setIndex( newIndices );

return result;
Expand Down