Blender imported meshes crash on collision

Hi there !

First off, I’m a total newbie, so don’t hesitate to tell me if I’m asking in the wrong place or just explaining things wrong.

So I’m working with react-three-fiber and use-cannon, and I’m trying to throw basic meshes on a plane. I’m importing simple models from Blender. They display fine, but they seem to make the page crash as soon as they collide with each other.

I’ve put up a straight forward sandbox to reproduce my issue.


Do you guys have any insights about that ?

The error’s stack trace is pretty far into the cannon-es code:

Screen Shot 2020-11-30 at 2.12.29 PM

I’m not too sure what’s going on there; it might be worth filing a bug on the cannon-es repository since you already have a nice example to reproduce the problem.

Hey, thanks for the answer !
Yeah, I noticed that the stack went lost in cannon-es. I tried to track it down and it seems to be about normals not being found. But it just gets to chaotic for me to understand. Also it is located inside the web worker, not within a local code I can easily log .

I’ll post an issue in some places to see if people have a clue. But if anyone comes around with an idea, I’ll hear it it. :smile:

So…
THE CAUSE :
In the process of cuting quads into triangles, Blender GLTF export multiplies the vertices. This doesn’t bother the rendering of the meshes in Three.js, but causes crashing deep into cannon-es script when two of them collide with each other.

THE FIX :
The geometry can be cleaned up with geometry.mergeVertices(). This caused the duplicated vertices to disappear, and the geometry.faces to be remapped onto the new geometry.vertices.

The CodeSandBox here shows the issue and the fix.

Hm, this seems like a bug in cannonjs to me. There are many cases where you don’t want your source geometry to have welded geometries, or where Blender has to split them. But you might be able to avoid the splits by not exporting normals, UVs, or other attributes on your collision meshes.

Also note that BufferGeometryUtils.mergeVertices is probably what you want to use, since conversion from BufferGeometry -> Geometry -> BufferGeometry is not a great workflow.

Is there no option in Blender GLTF exporter to output welded geometries ? It would be better than calling BufferGeometryUtils.mergeVertices because it’s quite an overhead for big geometries.

No, there is no specific option because welding vertices will throw away information that may be important. If you know you don’t want normals, tangents, or UVs, you can disable those in the export options and Blender should automatically keep your vertex count lower. CannonJS does not use that data, so it’s just wasted space for physics simulation.

You can also use the gltf-transform weld in.glb out.glb CLI to do this, but (similar to above, and to three.js itself) it can’t weld vertices that have different normals and UVs.

1 Like

Thanks for the reactions, guys !
There is indeed no such feature in Blender export as merged vertices), which I missed. But I can imagine that there are good reasons for that.
I haven’t heard of this CLI, @donmccurdy, I guess I didn’t want to spend to much time on Blender since I’m a fresh beginner with this software (coming from 3DsMax).

As to the BufferGeometryUtils, I chose not to use it, because I was already converting the BufferGeometryto Geometry, in order to access the material indices as well as the faceVertexUvs, which are not available in a BufferGeometry

1 Like

if you havent done already could you make an issue on cannon-es? this should be fixable. but awesome that you found the cause of this just going by these cryptic error messages!

btw instead of this:

  const Ground = () => {
    let geom = new THREE.PlaneGeometry(150, 150);
    const [ref] = usePlane(() => ({
      args: geom,
      position: [0, 0, -2]
    }));
    return (
      <mesh
        ref={ref}
        material={new THREE.MeshPhongMaterial({ color: "#222" })}
        geometry={geom}
      />
    );
  };

you can make it:

function Ground() {
  const [ref] = usePlane(() => ({ position: [0, 0, -2] }))
  return (
    <mesh ref={ref}>
      <meshPhongMaterial color="#222" />
      <planeBufferGeometry args={[150, 150]} />
    </mesh>
  )
}

Thanks, @drcmda ! Actually, the cryptic messages juste gave me an idea that collision and geometries must have been in cause. I figured it out by comparing the logs of my custom geometry with the native boxgeometry. Mine just had thrice the expected amount of vertices.

I have seen this other way that uses components for the mesh properties. I wasn’t sure what was the better way to go, so thank you for the tip. :slight_smile:

I’ll open an issue on cannon-es about that.