Skip to content

Commit

Permalink
Use connected faces from generated convex hull
Browse files Browse the repository at this point in the history
Motivation:
- Generated convex hulls did not have connected faces, which is required for convex-convex collision in cannon-es
- Using the generated faces in ConvexHull addresses this
- Fixes donmccurdy#76
  • Loading branch information
isaac-mason committed Aug 15, 2022
1 parent 144fd6b commit c0cea4f
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 80 deletions.
5 changes: 3 additions & 2 deletions lib/ConvexHull.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Mesh, Vector3 } from 'three';
import { Vector3 } from 'three';

declare class HalfEdge {
next: HalfEdge;
Expand All @@ -12,5 +12,6 @@ declare class Face {

declare class ConvexHull {
public faces: Face[];
setFromObject(mesh: Mesh): this;
setFromPoints(points: Vector3[]): this;
collectFaces(): number[][];
}
81 changes: 29 additions & 52 deletions lib/ConvexHull.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {
BufferGeometry,
Line3,
Plane,
Triangle,
Vector3
} from 'three';

/**
* Ported from: https://github.com/maurizzzio/quickhull3d/ by Mauricio Poppe (https://github.com/maurizzzio)
*/
Expand Down Expand Up @@ -42,6 +42,18 @@ var ConvexHull = ( function () {

Object.assign( ConvexHull.prototype, {

collectFaces: function () {
const faceIndices = []
for (let i = 0; i < this.faces.length; i += 1) {
if (this.faces[i].mark !== Visible) {
throw Error('attempt to include a destroyed face in the hull');
}
const indices = this.faces[i].collectIndices();
faceIndices.push(indices);
}
return faceIndices;
},

setFromPoints: function ( points ) {

if ( Array.isArray( points ) !== true ) {
Expand All @@ -60,7 +72,7 @@ var ConvexHull = ( function () {

for ( var i = 0, l = points.length; i < l; i ++ ) {

this.vertices.push( new VertexNode( points[ i ] ) );
this.vertices.push( new VertexNode( points[ i ], i ) );

}

Expand All @@ -70,54 +82,6 @@ var ConvexHull = ( function () {

},

setFromObject: function ( object ) {

var points = [];

object.updateMatrixWorld( true );

object.traverse( function ( node ) {

var i, l, point;

var geometry = node.geometry;

if ( geometry === undefined ) return;

if ( geometry.isGeometry ) {

geometry = geometry.toBufferGeometry
? geometry.toBufferGeometry()
: new BufferGeometry().fromGeometry( geometry );

}

if ( geometry.isBufferGeometry ) {

var attribute = geometry.attributes.position;

if ( attribute !== undefined ) {

for ( i = 0, l = attribute.count; i < l; i ++ ) {

point = new Vector3();

point.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld );

points.push( point );

}

}

}

} );

return this.setFromPoints( points );

},

containsPoint: function ( point ) {

var faces = this.faces;
Expand Down Expand Up @@ -980,6 +944,16 @@ var ConvexHull = ( function () {

Object.assign( Face.prototype, {

collectIndices: function () {
const indices = [];
let edge = this.edge;
do {
indices.push(edge.head().index);
edge = edge.next || null;
} while (edge !== this.edge);
return indices;
},

getEdge: function ( i ) {

var edge = this.edge;
Expand Down Expand Up @@ -1105,12 +1079,15 @@ var ConvexHull = ( function () {

// A vertex as a double linked list node.

function VertexNode( point ) {
function VertexNode( point, index ) {

this.point = point;
// index in the input array
this.index = index;
this.prev = null;
this.next = null;
this.face = null; // the face that is able to see this vertex
// the face that is able to see this vertex
this.face = null;

}

Expand Down
44 changes: 18 additions & 26 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Box, Quaternion as CQuaternion, ConvexPolyhedron, Cylinder, Shape, Sphere, Trimesh, Vec3 } from 'cannon-es';
import { Box3, BufferGeometry, CylinderGeometry, MathUtils, Mesh, Object3D, SphereGeometry, Vector3 } from 'three';
import { ConvexHull } from '../lib/ConvexHull.js';
import { Box, ConvexPolyhedron, Cylinder, Quaternion as CQuaternion, Shape, Sphere, Trimesh, Vec3 } from 'cannon-es';
import { Box3, BufferGeometry, CylinderGeometry, MathUtils, Object3D, SphereGeometry, Vector3 } from 'three';
import { ConvexHull } from '../lib/ConvexHull';
import { getComponent, getGeometry, getVertices } from './utils';

const PI_2 = Math.PI / 2;
Expand Down Expand Up @@ -254,34 +254,26 @@ function getConvexPolyhedronParameters (object: Object3D): ShapeParameters<Shape
);
}

// Compute the 3D convex hull.
const hull = new ConvexHull().setFromObject(new Mesh(geometry));
const hullFaces = hull.faces;
const vertices: number[] = [];
const faces: number[][] = [];

let currentFaceVertex = 0;
for (let i = 0; i < hullFaces.length; i++) {
const hullFace = hullFaces[ i ];
const face: number[] = [];
faces.push(face);

let edge = hullFace.edge;
do {
const point = edge.head().point;
vertices.push(point.x, point.y, point.z);
face.push(currentFaceVertex);
currentFaceVertex++;
edge = edge.next;
} while ( edge !== hullFace.edge );
// Get geometry points
const points: Vector3[] = [];
for (let i = 0; i < geometry.attributes.position.array.length; i += 3) {
points.push(
new Vector3(
geometry.attributes.position.array[i],
geometry.attributes.position.array[i + 1],
geometry.attributes.position.array[i + 2]
)
);
}

const verticesTypedArray = new Float32Array(vertices.length);
verticesTypedArray.set(vertices);
// Get convex hull faces
const faces = new ConvexHull().setFromPoints(points).collectFaces();

const vertices = geometry.attributes.position.array as Float32Array

return {
type: ShapeType.HULL,
params: { vertices: verticesTypedArray, faces },
params: { vertices, faces },
};
}

Expand Down

0 comments on commit c0cea4f

Please sign in to comment.