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 connected faces generated by ConvexHull addresses this
- Fixes #76
  • Loading branch information
isaac-mason committed Sep 3, 2022
1 parent 144fd6b commit 3a13f24
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 30 deletions.
1 change: 1 addition & 0 deletions lib/ConvexHull.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ declare class Face {
declare class ConvexHull {
public faces: Face[];
setFromObject(mesh: Mesh): this;
collectFacesAndVertices(): { faces: number[][]; vertices: Vector3[]; }
}
55 changes: 51 additions & 4 deletions lib/ConvexHull.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
BufferGeometry,
Line3,
Plane,
Triangle,
Expand Down Expand Up @@ -42,6 +41,41 @@ var ConvexHull = ( function () {

Object.assign( ConvexHull.prototype, {

collectFacesAndVertices: function () {
// Get face vertex indices.
// These indices reference the array positions of all input vertices, which include vertices inside the convex hull.
// These will be re-mapped to the convex hull's vertices, which exclude interior vertices.
const faceIndices = this.faces.map((f) => f.collectIndices());

// Get distinct vertex indices referenced by convex hull faces, in ascending order.
const referencedFaceIndices = Array.from(new Set(faceIndices.flat())).sort();

// Create a mapping between the original vertex indices to new vertex indices,
// excluding vertex indices that are not part of the generated convex hull.
const originalToNewIndex = new Map();
for (let i = 0; i < referencedFaceIndices.length; i++) {
originalToNewIndex.set(referencedFaceIndices[i], i);
}

// Get faces with remapped vertex indices.
const faces = [];
for (let i = 0; i < faceIndices.length; i++) {
const indices = faceIndices[i];
const a = originalToNewIndex.get(indices[0]);
const b = originalToNewIndex.get(indices[1]);
const c = originalToNewIndex.get(indices[2]);
faces.push([a, b, c]);
}

// Get vertices referenced by faces.
const vertices = [];
for (let i = 0; i < referencedFaceIndices.length; i++) {
vertices.push(this.vertices[referencedFaceIndices[i]].point);
}

return { faces, vertices };
},

setFromPoints: function ( points ) {

if ( Array.isArray( points ) !== true ) {
Expand All @@ -60,7 +94,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 Down Expand Up @@ -980,6 +1014,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;
} while (edge !== this.edge);
return indices;
},

getEdge: function ( i ) {

var edge = this.edge;
Expand Down Expand Up @@ -1105,12 +1149,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
41 changes: 15 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 { Box, ConvexPolyhedron, Cylinder, Quaternion as CQuaternion, 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 { ConvexHull } from '../lib/ConvexHull';
import { getComponent, getGeometry, getVertices } from './utils';

const PI_2 = Math.PI / 2;
Expand Down Expand Up @@ -254,34 +254,23 @@ 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 );
// Compute the 3D convex hull and collect convex hull vertices and faces.
const { vertices: verticesArray, faces } = new ConvexHull()
.setFromObject(new Mesh(geometry))
.collectFacesAndVertices();

const vertices = new Float32Array(verticesArray.length * 3);
for (let i = 0; i < verticesArray.length; i++) {
const { x, y, z } = verticesArray[i];
const v = i * 3;
vertices[v] = x;
vertices[v + 1] = y;
vertices[v + 2] = z;
}

const verticesTypedArray = new Float32Array(vertices.length);
verticesTypedArray.set(vertices);

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

Expand Down

0 comments on commit 3a13f24

Please sign in to comment.