pmndrs / use-cannon

👋💣 physics based hooks for @react-three/fiber
https://cannon.pmnd.rs
2.74k stars 154 forks source link

Sphere and plane combo, disrespecting gravity #284

Closed oskery closed 2 years ago

oskery commented 2 years ago

I have a sphere and a plane wrapped within a Physics component and the physics work, if I remove the plane the sphere will fall. But when I run the sphere outside the plane, the sphere does not fall of the edge. In debug mode it looks like cannon have interpreted some kind of area, smaller than the planeBufferGeometry, but it doesn't apply to the physics? I'm new here so I might be missing something trivial, am I supposed to specify a bounding box e.g?

Even if sphere is outside plane it does not fall

main.js:

import { Canvas } from '@react-three/fiber'
import { Sky, PointerLockControls } from '@react-three/drei'
import { Physics } from '@react-three/cannon'
import { Plane, Sphere } from '../components/'

export default function Game(props) {
  return (
    <>
      <Canvas shadows colorManagement camera={{ fov: 45 }}>
        <Sky sunPosition={[100, 10, 100]} />
        <ambientLight intensity={0.3} />
        <pointLight castShadow intensity={2.8} position={[100, 100, 100]} />
        <Physics gravity={[0, -106, 0]}>
          <Plane />
          <Sphere />
        </Physics>
        <PointerLockControls />
      </Canvas>
    </>
  )
}

Plane.js:

import { usePlane } from '@react-three/cannon'
import { useNormalTexture } from '@react-three/drei'

export default function Plane(props) {
  const [ref] = usePlane(() => ({ rotation: [-Math.PI / 2, 0, 0], ...props }))

  const [normalMap] = useNormalTexture(32, {
    offset: [0, 0],
    repeat: [100, 100],
    anisotropy: 8
  })

  return (
    <mesh ref={ref} receiveShadow>
      <planeBufferGeometry attach="geometry" args={[15, 15]} />
      <meshStandardMaterial
        attach="material"
        normalMap={normalMap}
        color="#dadb84"
      />
    </mesh>
  )
}
bjornstar commented 2 years ago

In your code planeBufferGeometry receives args to indicate the size of the plane, but usePlane has not received the same args which indicates a potential mismatch between the size of the plane in the physics engine and the one in the render engine.

oskery commented 2 years ago

@bjornstar The issues persist even if I remove args from planeBufferGeometry, the plane becomes smaller and the sphere still doesn't respect gravity at the edge.

bjornstar commented 2 years ago

I believe the Plane in Cannon is infinite in the X & Y axis which is different from the Plane in three.js, to have something with an edge you might try a Box instead.

arya-s commented 2 years ago

I ran into this issue too and eventually had to setup a box for the plane with the bounding box extents of my model.

e.g.

const [ref] = useBox(() => ({
    // calculated by getting the bounding box of the model
    // via nodes.Curve.geometry.boundingBox
    // Note: useBox args are full width/height not just min/max
    args: [93.04108802877366 * 2, 0.1, 29.52432893730702 * 2],
    ...(props as any),
  }));

  const { nodes } = useGLTF("/akigase-transformed.glb") as GLTFResult;
oskery commented 2 years ago

Thank you! I hadn't considered I could just use a box instead.