'Sphere not rolling straight

First time poster, long time (copy/)paster.

I am making a pool/billiards game using React-Three/Cannon for physics, which is pretty much Cannon ES but with a layer that works well with React.

When I apply friction to the ball-table contact material the ball does not go in a straight line. The higher the velocity is the more it swerves away from it's path.

The problem doesn't occur when the ball goes straight in the x-or Z direction or at a 45 degree angle.

If I remove the friction the problem goes away, but that isn't a viable option in this case.

The higher the velocity is the more the sphere turns.

I have tried the different available solvers (GS and Split), Broadphases (Naive and SAP) and setting extremely high and low values for the different contact material options. The only thing that worked was removing friction. I also tried applying velocity to the ball by using sphere.applyForce, sphere.apply.impulse and setting the velocity manually. Scaling the size/velocities doesn't work either.

Other people have had the same issue using another physics engine: pybullet bullet. Their fixas involved setting some option called "SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS" (which I havn't found an option for in cannon) or updating the engine to use cone friction for rolling friction. They describe cone friction this way: "Instead of clamping individual friction directions, cone friction clamps the combined friction vector.

I reproduced the problem in a much smaller project here:

import React, {useEffect} from 'react';
import ReactDOM from 'react-dom';
import { Physics } from '@react-three/cannon'
import { Canvas } from '@react-three/fiber'
import { usePlane, useSphere } from "@react-three/cannon"


const Floor = (props)=>{
  const [ref] = usePlane(() => ({ rotation:[-Math.PI/2,0,0.2] }))
  return (
    <mesh ref={ref}>
      <planeBufferGeometry args={[160, 800]} />
      <meshStandardMaterial color="green" />
    </mesh>
  )
}

const Ball = (props)=> {
  const [ref,api] = useSphere(()=>({
    position:[-1000,8,360],
    args:[8], 
    mass:1
  }))
  
  useEffect(()=>{
    
    setTimeout(()=>{
      api.position.set(0,8,360)
      api.velocity.set(-0.2*props.force,0,-1*props.force);
    },props.delay)
    
  },[])
  
  return (
    <mesh
      ref={ref}
    >
      
      <sphereBufferGeometry 
        args={[8, 24, 24]} />
        <meshStandardMaterial color={"white"} />
      
    </mesh>
  );
}


class App extends React.Component { 
  render() {
    return (
      <div style={{width:"100vw",height:"100vh"}}>
        <Canvas 
          camera={ {
            position: [70, 200, 550], 
            fov:75,
          }}
        >
          <ambientLight args={[0xaaaaaa]}/>
          <Physics 
            allowSleep={false}
            gravity={[0, -40, 0]}
            defaultContactMaterial = {{
              friction:0.2
            }}
          >
            <Floor />
            <Ball 
              force={100} 
              delay={2500}
            />
            <Ball 
              force={200} 
              delay={2000}
            />
            <Ball 
              force={400} 
              delay={1500}
            />
            <Ball 
              force={800} 
              delay={1000}
            />
            <Ball 
              force={1600} 
              delay={500}
            />
          </Physics>
          
        </Canvas>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'));

The following versions were used:

"@react-three/cannon": "^6.3.0",
"@react-three/fiber": "^7.0.0",
"three": "^0.139.1"

Other than removing friction and implementing my own rolling friction physics (which I tried and realized was alot harder than I thought), does anyone know how to get the ball to roll straight using Cannon ES? Either by finding a way to implement the fixes mentioned above or another solution.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source