yarn add @react-three/cannon
import { Canvas } from '@react-three/fiber';
import { Physics, useSphere, usePlane, useBox } from '@react-three/cannon';
import { OrbitControls } from "@react-three/drei";
import { useRef, Suspense } from 'react';
const Ball = ({ position }) => {
const [ballRef] = useSphere(() => ({ mass: 1, position: position }));
return (
<mesh ref={ballRef}>
<sphereGeometry args={[1, 36, 36]} />
<meshStandardMaterial roughness={0} color="pink" />
</mesh>
)
}
const Ground = (props) => {
const [ref] = usePlane(() => ({ ...props }));
return (
<mesh ref={ref}>
<planeGeometry args={[100, 100]} />
<meshStandardMaterial color={"#f8f8f8"} />
</mesh>
)
}
const Example = () => {
return (
<Canvas
style={{ height: 600, width: 600 }}
camera={{ position: [0, 10, 5] }}>
<color attach="background" args={['pink']} />
<fog attach="fog" args={['red', 60, 100]} />
<directionalLight
position={[0, 5, 5]}/>
<ambientLight intensity={0.1} />
<Suspense fallback={null}>
<Physics>
<Ball position={[0.5, 7, 0]} />
<Ball position={[0, 5, 0]} />
<Ball position={[-0.5, 9, 0]} />
<Ground rotation={[-Math.PI / 2, 0, 0]} />
</Physics>
</Suspense>
<OrbitControls />
</Canvas>
)
}
export default Example;
<Physics>
로 감싸주어야 한다.
import { Canvas, useFrame, useThree } from '@react-three/fiber';
import { OrbitControls } from "@react-three/drei";
import { Suspense } from 'react';
import { Physics, usePlane, useSphere } from "@react-three/cannon";
const InstancedSpheres = ({ count = 200 }) => {
const { viewport } = useThree();
const [ref] = useSphere((index) => ({ mass: 100, position: [4 - Math.random() * 8, viewport.height, 0, 0], args: [1.2] }))
return (
<instancedMesh ref={ref} castShadow receiveShadow args={[null, null, count]}>
<sphereBufferGeometry args={[1.2, 62, 62]} />
<meshStandardMaterial color="#ccf0a4" roughness={0}/>
</instancedMesh>
)
}
const Borders = () => {
const { viewport } = useThree();
return(
<>
<Plane position={[0, -viewport.height / 2, 0]} rotation={[-Math.PI / 2, 0, 0]} />
<Plane position={[-viewport.width / 2 - 1, 0, 0]} rotation={[0, Math.PI / 2, 0]} />
<Plane position={[viewport.width / 2 + 1, 0, 0]} rotation={[0, -Math.PI / 2, 0]} />
<Plane position={[0, 0, 1]} rotation={[0, 0, 0]} />
<Plane position={[0, 0, 12]} rotation={[0, -Math.PI, 0]} />
</>
)
}
const Plane = ({ color, ...props }) => {
usePlane(() => ({ ...props }))
return null
}
function Mouse() {
const { viewport } = useThree()
const [, api] = useSphere(() => ({ type: "Kinematic", args: [6] }))
return useFrame((state) => api.position.set((state.mouse.x * viewport.width) / 2, (state.mouse.y * viewport.height) / 2, 7))
}
const Rounded = () => {
return (
<Canvas shadows gl={{ stencil: false, antialias: false }} camera={{ position: [0, 0, 20], fov: 50, near: 17, far: 40 }}>
<fog attach="fog" args={["#a2f14a", 25, 35]} />
<color attach="background" args={["t"]} />
<ambientLight intensity={1.5} />
<directionalLight position={[-10, -10, -5]} intensity={0.5} />
<directionalLight
castShadow
intensity={6}
position={[50, 50, 25]}
shadow-mapSize={[256, 256]}
shadow-camera-left={-10}
shadow-camera-right={10}
shadow-camera-top={10}
shadow-camera-bottom={-10}
/>
<Suspense fallback={null}>
<Physics gravity={[0, -50, 0]} defaultContactMaterial={{ restitution: 0.5 }}>
<group position={[0, 0, -10]}>
<InstancedSpheres />
<Borders />
<Mouse />
</group>
</Physics>
</Suspense>
<OrbitControls />
</Canvas>
)
}
export default Rounded;