Skip to content

Commit

Permalink
Improvements to mesh2shape()
Browse files Browse the repository at this point in the history
  • Loading branch information
donmccurdy committed May 13, 2016
1 parent d596291 commit 9df3943
Showing 1 changed file with 68 additions and 23 deletions.
91 changes: 68 additions & 23 deletions lib/CANNON-mesh2shape.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ var CANNON = require('cannon');
* @param {THREE.Object3D} object
* @return {CANNON.Shape}
*/
module.exports = function (object, options) {
module.exports = CANNON.mesh2shape = function (object, options) {
options = options || {};

if (options.type === 'BoxGeometry') {
Expand All @@ -14,26 +14,9 @@ module.exports = function (object, options) {
throw new Error('[CANNON.mesh2shape] Invalid type "%s".', options.type);
}

var geometry, meshes = [];
object.traverse(function (object) {
if (object.type === 'Mesh') {
meshes.push(object);
}
});
var geometry = getGeometry(object);

if (meshes.length > 1) {
// Merge additional geometries into the first. Could try to create a
// compound shape from primitives, but this is probably a custom model, and
// doing that well automatically is complex.
geometry = meshes.pop().geometry.clone();
for (var i = 0; i < meshes.length; i++) {
geometry.merge(meshes[i].geometry);
}
} else if (meshes.length === 1) {
geometry = meshes[0].geometry;
} else if (meshes.length === 0) {
return null;
}
if (!geometry) return null;

switch (geometry.type) {
case 'BoxGeometry':
Expand Down Expand Up @@ -183,15 +166,44 @@ function createTrimeshShape (geometry) {
* Utils
*/

/**
* Returns a single geometry for the given object. If the object is compound,
* its geometries are automatically merged.
*
* NOTE: Only clone geometry when required, because doing so loses type
* information - PlaneBufferGeometry will be converted to BufferGeometry, for
* example.
*
* @param {THREE.Object3D} object
* @return {THREE.Geometry}
*/
function getGeometry (object) {
var geometry, tmpGeometry, scale, mesh, meshes = [];
object.traverse(function (object) {
if (object.type === 'Mesh') {
meshes.push(object);
}
});

if (meshes.length === 0) return null;

geometry = safeCloneGeometry(meshes.pop());
while (meshes.length > 0) {
geometry.merge( safeCloneGeometry(meshes.pop()) );
}

return geometry;
}

/**
* @param {THREE.Geometry} geometry
* @return {Array<number>}
*/
function getVertices (geometry) {
if (geometry.attributes) {
return geometry.attributes.position.array;
if (!geometry.attributes) {
geometry = new THREE.BufferGeometry().fromGeometry(geometry);
}
return geometry.vertices || [];
return geometry.attributes.position.array;
}

/**
Expand All @@ -218,3 +230,36 @@ function centerGeometry (geometry) {

return geometry;
}

/**
* Clones a mesh's geometry, with several non-default workarounds.
*
* 1. Scale geometry to match the mesh.
* 2. Offset geometry position to match mesh.
* 3. Avoid cloning when possible, to keep type information. For example,
* cloning PlaneBufferGeometry normally returns a BufferGeometry instead.
*
* @param {THREE.Mesh} mesh
* @return {THREE.Geometry}
*/
function safeCloneGeometry (mesh) {
var cloned = false;
var geometry = mesh.geometry;
var scale = mesh.getWorldScale();
var offset = mesh.getWorldPosition();

if (scale.x !== 1 || scale.y !== 1 || scale.z !== 1) {
console.log('SCALE %f %f %f', scale.x, scale.y, scale.z);
geometry = geometry.clone().scale(scale.x, scale.y, scale.z);
cloned = true;
}

if (offset.x || offset.y || offset.z) {
console.log('OFFSET %f %f %f', offset.x, offset.y, offset.z);
geometry = cloned ? geometry : geometry.clone();
geometry.applyMatrix(new THREE.Matrix4().makeTranslation(offset.x, offset.y, offset.z));
cloned = true;
}

return geometry;
}

0 comments on commit 9df3943

Please sign in to comment.