modify method
BufferGeometry
modify(
- BufferGeometry geometry,
- dynamic cutOffAngle, [
- bool tryKeepNormals = true
Implementation
BufferGeometry modify(BufferGeometry geometry, cutOffAngle, [bool tryKeepNormals = true ]) {
bool hadNormals = false;
Float32Array? oldNormals;
if ( geometry.attributes['normal'] != null) {
hadNormals = true;
geometry = geometry.clone();
if ( tryKeepNormals == true && geometry.index != null ) {
oldNormals = geometry.attributes['normal'].array;
}
geometry.deleteAttributeFromString( 'normal' );
}
if ( geometry.index == null ) {
geometry = BufferGeometryUtils.mergeVertices( geometry );
}
final NativeArray<int> indexes = geometry.index!.array as NativeArray<int>;
final positions = geometry.getAttributeFromString( 'position' ).array;
late Float32Array normals;
late List pointToIndexMap;
final splitIndexes = [];
void computeNormals() {
normals = Float32Array( indexes.length * 3 );
for (int i = 0; i < indexes.length; i += 3 ) {
num index = indexes[ i ];
_A.setValues(
positions[ 3 * index ],
positions[ 3 * index + 1 ],
positions[ 3 * index + 2 ] );
index = indexes[ i + 1 ];
_B.setValues(
positions[ 3 * index ],
positions[ 3 * index + 1 ],
positions[ 3 * index + 2 ] );
index = indexes[ i + 2 ];
_C.setValues(
positions[ 3 * index ],
positions[ 3 * index + 1 ],
positions[ 3 * index + 2 ] );
_C.sub( _B );
_A.sub( _B );
final normal = _C.cross( _A ).normalize();
for (int j = 0; j < 3; j ++ ) {
normals[ 3 * ( i + j ) ] = normal.x;
normals[ 3 * ( i + j ) + 1 ] = normal.y;
normals[ 3 * ( i + j ) + 2 ] = normal.z;
}
}
}
void mapPositionsToIndexes() {
pointToIndexMap = List.filled( positions.length ~/ 3, null);
for (int i = 0; i < indexes.length; i ++ ) {
final index = indexes[ i ];
if ( pointToIndexMap[ index ] == null ) {
pointToIndexMap[ index ] = [];
}
pointToIndexMap[index].add( i );
}
}
Map<String, List<dynamic>> edgeSplitToGroups(List indexes, double cutOff, int firstIndex ) {
_A.setValues( normals[ 3 * firstIndex ], normals[ 3 * firstIndex + 1 ], normals[ 3 * firstIndex + 2 ] ).normalize();
final result = {
'splitGroup': [],
'currentGroup': [ firstIndex ]
};
for ( final ji in indexes ) {
int j = ji;
if ( j != firstIndex ) {
_B.setValues( normals[ 3 * j ], normals[ 3 * j + 1 ], normals[ 3 * j + 2 ] ).normalize();
if ( _B.dot( _A ) < cutOff ) {
result['splitGroup']!.add( j );
} else {
result['currentGroup']!.add( j );
}
}
}
return result;
}
void edgeSplit(List? indexes, cutOff, [original]) {
if ( (indexes?.length ?? 0) == 0 ) return;
final List<Map<String,List>> groupResults = [];
for ( final index in indexes! ) {
groupResults.add( edgeSplitToGroups( indexes, cutOff, index ) );
}
Map<String,List> result = groupResults[ 0 ];
for ( final groupResult in groupResults ) {
if ( groupResult['currentGroup']!.length > result['currentGroup']!.length ) {
result = groupResult;
}
}
if ( original != null ) {
splitIndexes.add( {
'original': original,
'indexes': result['currentGroup']
} );
}
if ( result['splitGroup']!.isNotEmpty ) {
edgeSplit( result['splitGroup'], cutOff, original ?? result['currentGroup']![ 0 ] );
}
}
computeNormals();
mapPositionsToIndexes();
for ( final vertexIndexes in pointToIndexMap ) {
edgeSplit( vertexIndexes, math.cos( cutOffAngle ) - 0.001 );
}
final newAttributes = {};
for ( final name in geometry.attributes.keys) {
final oldAttribute = geometry.attributes[ name ] as Float32BufferAttribute;
final newArray = Float32Array(( indexes.length + splitIndexes.length ) * oldAttribute.itemSize);//oldAttribute.array.constructor( ( indexes.length + splitIndexes.length ) * oldAttribute.itemSize );
newArray.set( oldAttribute.array.toList() );
newAttributes[name] = Float32BufferAttribute( newArray, oldAttribute.itemSize, oldAttribute.normalized );
}
final newIndexes = Uint32Array( indexes.length );
newIndexes.set( indexes.toDartList() );
for (int i = 0; i < splitIndexes.length; i ++ ) {
final Map<String, dynamic> split = splitIndexes[ i ];
final index = indexes[ split['original'] ];
for ( final attribute in newAttributes.values) {
for (int j = 0; j < attribute.itemSize; j ++ ) {
attribute.array[ ( indexes.length + i ) * attribute.itemSize + j ] =
attribute.array[ index * attribute.itemSize + j ];
}
}
for ( final j in split['indexes'] ) {
newIndexes[ j ] = indexes.length + i;
}
}
geometry = BufferGeometry();
geometry.setIndex( Uint32BufferAttribute( newIndexes, 1 ) );
for ( final name in newAttributes.keys) {
geometry.setAttributeFromString( name, newAttributes[ name ] );
}
if ( hadNormals ) {
geometry.computeVertexNormals();
if ( oldNormals != null ) {
final changedNormals = Map.from(List.filled(oldNormals.length ~/ 3, false).asMap());
for ( final splitData in splitIndexes ){
changedNormals[ splitData['original'] ] = true;
}
for (int i = 0; i < changedNormals.length; i ++ ) {
if ( changedNormals[ i ] == false ) {
for (int j = 0; j < 3; j ++ ){
geometry.attributes['normal'].array[ 3 * i + j ] = oldNormals[ 3 * i + j ];
}
}
}
}
}
return geometry;
}