"use client"
import { Canvas } from '@react-three/fiber'
import { OrbitControls, Sphere } from '@react-three/drei'
import { button, Leva, useControls } from 'leva'
import { StrictMode, useRef, useState } from 'react'
import * as THREE from 'three'

export default function App() {
  return (
    <StrictMode>
      <Leva flat />
      <Experience />
    </StrictMode>
  )
}

export function Experience() {
  const [points, setPoints] = useState([])
  const { showPoints } = useControls('Shape', { reset: button(() => setPoints([])), showPoints: true })

  const shape = new THREE.Shape();
  if (points.length > 0) {
    shape.moveTo(points[0].x, points[0].y)
    points.forEach(p => shape.lineTo(p.x, p.y))
    shape.lineTo(points[0].x, points[0].y)
  }

  return <Canvas>
    <OrbitControls makeDefault />
    <directionalLight position={[1, 2, 3]} intensity={1.5} />
    <ambientLight intensity={0.5} />
    <Pointer setPoints={setPoints} />
    {showPoints && points.map((p, i) => <Point key={i} position={[...p, 0]} />)}
    <mesh>
      <shapeGeometry args={[shape]} />
      <meshBasicMaterial color={'crimson'} transparent={false} opacity={1} depthTest={false} side={THREE.DoubleSide} />
    </mesh>
  </Canvas>
}

//draw a plane and track the pointer position on it. 
export function Pointer({ setPoints }) {
  const pointerRef = useRef();
  const planeRef = useRef();

  return (
    <mesh
      ref={planeRef}
      onPointerOver={() => pointerRef.current.visible = true}
      onPointerOut={() => pointerRef.current.visible = false}
      onPointerMove={(e) => pointerRef.current.position.copy(planeRef.current.worldToLocal(e.point))}
      onClick={(e) => setPoints((state) => [...state, planeRef.current.worldToLocal(e.point)])}>
      <planeGeometry args={[10, 10]} />
      <meshBasicMaterial transparent={true} opacity={0.25} />
      <Sphere args={[0.1]} ref={pointerRef} raycast={() => null} visible={false} material-color="orange" />
    </mesh>
  )
}

export function Point({ position, color = "black", args = [0.1], ...props }) {
  return (
    <mesh position={position} {...props}>
      <sphereGeometry args={args} />
      <meshBasicMaterial color={color} />
    </mesh>
  )
}

Comments (0)

Loading comments...