Mesh collision problem playcanvas react

I am trying to use the lamborghini.glb model in the playcanvas react docs as a test model to test the mesh collision physics, but i can manage to pull it of.

Is there something wrong with this code?

Thanks!!

export function Model({ asset }) {
  // If the asset is not loaded, return null
  if (!asset) return null;

  // If the asset is loaded, render it
  return <Render type="asset" asset={asset} />;
}

const PhysicsScene = () => {
  const { isPhysicsLoaded } = usePhysics();
  const { asset } = useModel("lamborghini_vision_gt.glb");
  if (!isPhysicsLoaded || !asset) {
    return null;
  }

  return (
    <Entity name="PhysicsRoot">
      {/* Ground Plane */}
      <Entity
        name="ground"
        position={[0, -1, 0]}
        scale={[20, 1, 20]}
        rotation={[0, 0, 0]}
      >
        <Render type="box" />
        <Collision type="box" halfExtents={[10, 0.5, 10]} />
        <RigidBody type="static" />
      </Entity>

      {/* Mesh */}
      <Entity
        name="mesh"
        position={[-3, 0, 0]}
        scale={[1, 1, 1]}
        rotation={[0, 0, 0]}
      >
        <Model asset={asset} />
        <Collision type="mesh" asset={asset} renderAsset={asset} convexHull={true} />
        <RigidBody type="static" />
      </Entity>

    </Entity>
  );
};

Hi @Jorgix!

I have no experience with React, but from what I can see, you set the rigidbody type to static. If this is a moving object, I would expect a dynamic rigidbody instead (or kinematic if you don’t want to use physics).

Also, be aware that mesh-to-mesh collision is not supported.

Hi! Thanks for your answer!

The thing is that i want my player (camera with a capsule collision attached) to collide with a mesh (for example a statue on my environment).

The camera is a capsule, so it’s not directly a mesh type collider, and should interact with the mesh itself?

I am not familiar with react, but maybe @Mark_Lundin can give advice.

As for collision mesh - for a static object you want to use mesh as a collision shape type. It will collide with dynamic convex shapes, like capsules, spheres, etc.

For a dynamic object, you can use convex hull as a collision shape type. This will allow it to become dynamic object as well. It is more expensive than a static mesh, though, so don’t use it, unless you really have to.

Hi @LeXXik @Mark_Lundin !!
I have been trying to solve the mesh collision problem but it has been impossible.

This is a simplified version of the code i want to achieve where a static mesh is used as a collider for a falling object (collision type box in this case).

The falling box keeps going through the static mesh, but collides correctly with the ground (also collision type box) under it.

Please, help me figure out how the mesh collision works, I will heavily appreciate it :slight_smile:

Also, i think the wireframe renderstyle has problems with the type asset in the render component. Because it works perfectly fine with a type box render.

import React from 'react';
import { Application, Entity } from '@playcanvas/react';
import { useModel } from '@playcanvas/react/hooks';
import { Camera, Render, Light, Collision, RigidBody } from '@playcanvas/react/components';
import { OrbitControls } from '@playcanvas/react/scripts';
import { FILLMODE_FILL_WINDOW, RESOLUTION_AUTO } from 'playcanvas';

export function ModelViewer() {
  const { asset } = useModel("lamborghini_vision_gt.glb");
 
  // If the asset is not loaded, return null    
  if (!asset) return null;
 
  // If the asset is loaded, render it
  return (
    <Entity name="mesh" position={[0, 5, 0.5]}>
      <Render type='asset' asset={asset} renderStyle={1}/>;
      <Collision  type='asset' asset={asset} />
      <RigidBody type="static" />
    </Entity>
  );
}

export default function App() {
  return (
    <Application
      fillMode={FILLMODE_FILL_WINDOW}
      resolutionMode={RESOLUTION_AUTO}
      usePhysics
    >
      <Entity name='camera' position={[0, 10, 25]}>
        <Camera />
        <OrbitControls />
      </Entity>

      <Entity name='light' rotation={[45, -45, 45]}>
        <Light type='directional' />
      </Entity>

      <Entity name='ground' scale={[20, 1, 20]}>
        <Render type="box" />
        <Collision type="box" halfExtents={[10, 0.5, 10]} />
        <RigidBody type="static" />
      </Entity>

      <Entity name='fallingBox' position={[0, 10, 0]}>
        <Render type="box" />
        <Collision type="box" />
        <RigidBody type="dynamic" mass={50} />
      </Entity>

      <ModelViewer />

    </Application>
  );
}

Thanks so much in advance!!

hey @Jorgix, I’m currently looking into this for you. I’ll let you know if I manage to get this working

Hi @Mark_Lundin, I have been trying to solver this, but i can not figure it out.
Have you had time to look at it?

Thanks in advance!!

Same problem, can not make the mesh collider work using react, brower console keeps telling me: [PlayCanvas React]: Unknown props in “.”
The following props are invalid and will be ignored: “asset”

Hey @Jorgix and @JazzenChen. So the issue here is that loaded GLB’s are a sub hierarchy of entities. So we need a better API to map these to Collision or RigidBody components. This is something I’m actively working on.

As a workaround for the time being, you would need to manually add these in a useEffect hook once the asset is loaded.

Thanks for the answer and for your work.
I would really appreciate if you have an example of code of the workaround to see excatly how to manage the issue.

Hi @Mark_Lundin!!

I have been trying to figure out the workaround, but its been impossible for me to make it work.
Could you please share if you have an example of code that uses what you say.

Thanks in advance!!

Hey @Jorgix I have an API improvement that should help with this, but for the mean time I would look at something like the following

export function ModelViewer() {
  const { asset } = useModel("lamborghini_vision_gt.glb");
  const entityRef = useRef();

  useEffect(() => {
    if (!entityRef.current) return
    // select all render components
    const components = entityRef.findComponents('render');
    
    // add some imperative logic to add components to each entity with a render component
    components.forEach((component) => {
      component.entity.addComponent('collision', ... )
      // ...
     }) 
  }, [])
 
  // If the asset is not loaded, return null    
  if (!asset) return null;
 
  // If the asset is loaded, render it
  return (
    <Entity name="mesh" position={[0, 5, 0.5]} ref={ref}>
      <Render type='asset' asset={asset} renderStyle={1}/>
    </Entity>
  );
}

Hi @Mark_Lundin, sorry to bother you, but its been impossible for me to make it work.
With that implementation the model fallas until it reaches trhe ground and it gets dissolved in each piece. Also if the type is set to static the collision doesnt work at all.
This is my actual code:

export function ModelViewer() {
  const { asset } = useModel("lamborghini_vision_gt.glb");
  const entityRef = useRef();
  const app = useApp();

  useEffect(() => {
    if (!entityRef.current || !asset) return;
    // select all render components
    const components = entityRef.current.findComponents('render');
    
    // add some imperative logic to add components to each entity with a render component
    components.forEach((component) => {
      if (component.meshInstances.length > 0) {
        const meshInstance = component.meshInstances[0];
        
        const model = new Model();
        model.graph = meshInstance.node;
        model.meshInstances.push(meshInstance);

        component.entity.addComponent('collision', {
            type: 'mesh',
            model: model,
            convexHull: true
        });
        component.entity.addComponent('rigidbody', {
            type: 'dynamic',
            mass: 50,
            restitution: 0.5
        });
      }
    });
  }, [asset, app]);
 
  // If the asset is not loaded, return null    
  if (!asset) return null;
 
  // If the asset is loaded, render it
  return (
    <Entity name="mesh" position={[0, 5, 0.5]} ref={entityRef}>
      <Render type='asset' asset={asset} renderStyle={1}/>
    </Entity>
  );
}